From 8e599b0daac87f8ec4a86f5e62ebf01d5f4e21f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Dec 2024 18:29:41 +0100 Subject: [PATCH 001/302] de-stabilize bench attribute --- library/core/src/macros/mod.rs | 1 - tests/ui/feature-gates/bench.rs | 2 -- tests/ui/feature-gates/bench.stderr | 40 ++++++++--------------------- tests/ui/lint/expansion-time.rs | 7 ----- tests/ui/lint/expansion-time.stderr | 33 ++---------------------- 5 files changed, 12 insertions(+), 71 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index ab674b58902b..f10a58618cd8 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1683,7 +1683,6 @@ pub(crate) mod builtin { #[unstable( feature = "test", issue = "50297", - soft, reason = "`bench` is a part of custom test frameworks which are unstable" )] #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] diff --git a/tests/ui/feature-gates/bench.rs b/tests/ui/feature-gates/bench.rs index 12e646f7a323..94c8992a8fe6 100644 --- a/tests/ui/feature-gates/bench.rs +++ b/tests/ui/feature-gates/bench.rs @@ -1,9 +1,7 @@ //@ edition:2018 #[bench] //~ ERROR use of unstable library feature `test` - //~| WARN this was previously accepted fn bench() {} use bench as _; //~ ERROR use of unstable library feature `test` - //~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/feature-gates/bench.stderr b/tests/ui/feature-gates/bench.stderr index de78e863012d..f5fc579b23be 100644 --- a/tests/ui/feature-gates/bench.stderr +++ b/tests/ui/feature-gates/bench.stderr @@ -1,43 +1,23 @@ -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable +error[E0658]: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable --> $DIR/bench.rs:3:3 | LL | #[bench] | ^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default + = note: see issue #50297 for more information + = help: add `#![feature(test)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:7:5 +error[E0658]: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:6:5 | LL | use bench as _; | ^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 + = note: see issue #50297 for more information + = help: add `#![feature(test)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors -Future incompatibility report: Future breakage diagnostic: -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:3:3 - | -LL | #[bench] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default - -Future breakage diagnostic: -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:7:5 - | -LL | use bench as _; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default - +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs index d0f26a87385c..c13649c93a1b 100644 --- a/tests/ui/lint/expansion-time.rs +++ b/tests/ui/lint/expansion-time.rs @@ -9,13 +9,6 @@ macro_rules! foo { macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier //~| WARN this was previously accepted -#[warn(soft_unstable)] -mod benches { - #[bench] //~ WARN use of unstable library feature `test` - //~| WARN this was previously accepted - fn foo() {} -} - #[deprecated = "reason"] macro_rules! deprecated { () => {} diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr index f65627c2c087..f24d1b68a8da 100644 --- a/tests/ui/lint/expansion-time.stderr +++ b/tests/ui/lint/expansion-time.stderr @@ -26,20 +26,6 @@ note: the lint level is defined here LL | #[warn(missing_fragment_specifier)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/expansion-time.rs:14:7 - | -LL | #[bench] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 -note: the lint level is defined here - --> $DIR/expansion-time.rs:12:8 - | -LL | #[warn(soft_unstable)] - | ^^^^^^^^^^^^^ - warning: include macro expected single expression in source --> $DIR/expansion-time-include.rs:4:1 | @@ -47,12 +33,12 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:29:8 + --> $DIR/expansion-time.rs:22:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 4 warnings emitted +warning: 3 warnings emitted Future incompatibility report: Future breakage diagnostic: warning: missing fragment specifier @@ -69,18 +55,3 @@ note: the lint level is defined here LL | #[warn(missing_fragment_specifier)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/expansion-time.rs:14:7 - | -LL | #[bench] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 -note: the lint level is defined here - --> $DIR/expansion-time.rs:12:8 - | -LL | #[warn(soft_unstable)] - | ^^^^^^^^^^^^^ - From f5c63b9e63b841a3b60731769078571514a1cdad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Dec 2024 20:14:13 +0100 Subject: [PATCH 002/302] the soft_unstable lint cannot have an example that will keep working --- compiler/rustc_lint_defs/src/builtin.rs | 32 +++---------------------- src/tools/lint-docs/src/lib.rs | 1 + 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 54e927df3c42..a6d437b71a4e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2389,37 +2389,11 @@ declare_lint! { } declare_lint! { - /// The `soft_unstable` lint detects unstable features that were - /// unintentionally allowed on stable. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #[cfg(test)] - /// extern crate test; - /// - /// #[bench] - /// fn name(b: &mut test::Bencher) { - /// b.iter(|| 123) - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The [`bench` attribute] was accidentally allowed to be specified on - /// the [stable release channel]. Turning this to a hard error would have - /// broken some projects. This lint allows those projects to continue to - /// build correctly when [`--cap-lints`] is used, but otherwise signal an - /// error that `#[bench]` should not be used on the stable channel. This - /// is a [future-incompatible] lint to transition this to a hard error in - /// the future. See [issue #64266] for more details. + /// The `soft_unstable` lint detects unstable features that were unintentionally allowed on + /// stable. This is a [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #64266] for more details. /// /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 - /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html - /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints /// [future-incompatible]: ../index.md#future-incompatible-lints pub SOFT_UNSTABLE, Deny, diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 8c7ff08ccd72..b54a4dba41c7 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -306,6 +306,7 @@ impl<'a> LintExtractor<'a> { if matches!( lint.name.as_str(), "unused_features" // broken lint + | "soft_unstable" // cannot have a stable example ) { return Ok(()); } From 3d41095af9752891b315cda30a4a91ee7db0763b Mon Sep 17 00:00:00 2001 From: Vladislav Date: Sun, 23 Feb 2025 10:51:22 +0100 Subject: [PATCH 003/302] Put shebang at the top of pretty-print --- compiler/rustc_ast_pretty/src/pprust/state.rs | 19 +++++++++++++++++++ tests/pretty/shebang-at-top.pp | 12 ++++++++++++ tests/pretty/shebang-at-top.rs | 6 ++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/pretty/shebang-at-top.pp create mode 100644 tests/pretty/shebang-at-top.rs diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0bf5de3ef898..0d6c69510820 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -243,6 +243,11 @@ pub fn print_crate<'a>( let mut s = State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann }; + // We need to print shebang before anything else + // otherwise the resulting code will not compile + // and shebang will be useless. + s.maybe_print_shebang(); + if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. @@ -574,6 +579,20 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(st) } + fn maybe_print_shebang(&mut self) { + if let Some(cmnt) = self.peek_comment() { + // Comment is a shebang if it's: + // Isolated, starts with #! and doesn't continue with `[` + // See [rustc_lexer::strip_shebang] and [gather_comments] from pprust/state.rs for details + if cmnt.style == CommentStyle::Isolated + && cmnt.lines.first().map_or(false, |l| l.starts_with("#!")) + { + let cmnt = self.next_comment().unwrap(); + self.print_comment(cmnt); + } + } + } + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } diff --git a/tests/pretty/shebang-at-top.pp b/tests/pretty/shebang-at-top.pp new file mode 100644 index 000000000000..a27972526364 --- /dev/null +++ b/tests/pretty/shebang-at-top.pp @@ -0,0 +1,12 @@ +#!/usr/bin/env rust +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} diff --git a/tests/pretty/shebang-at-top.rs b/tests/pretty/shebang-at-top.rs new file mode 100644 index 000000000000..8bfa925fa1ab --- /dev/null +++ b/tests/pretty/shebang-at-top.rs @@ -0,0 +1,6 @@ +#!/usr/bin/env rust +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} From a3c5b6a2dcd7ad57dda3d483aa29f71208f56dd6 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Fri, 28 Feb 2025 00:28:41 +0100 Subject: [PATCH 004/302] Fix span info for mir::Operand Fixes #19172 --- .../rust-analyzer/crates/hir-ty/src/mir.rs | 23 ++++-- .../crates/hir-ty/src/mir/borrowck.rs | 22 +++--- .../crates/hir-ty/src/mir/eval.rs | 18 ++--- .../crates/hir-ty/src/mir/lower.rs | 72 ++++++++++++------- .../crates/hir-ty/src/mir/lower/as_place.rs | 8 +-- .../hir-ty/src/mir/lower/pattern_matching.rs | 47 ++++++++---- .../crates/hir-ty/src/mir/monomorphization.rs | 8 +-- .../crates/hir-ty/src/mir/pretty.rs | 12 ++-- .../src/handlers/moved_out_of_ref.rs | 19 ++++- 9 files changed, 147 insertions(+), 82 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 247f0ec429fc..43408eb75e27 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -77,7 +77,14 @@ pub struct Local { /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Operand { +pub struct Operand { + kind: OperandKind, + // FIXME : This should actually just be of type `MirSpan`. + span: Option, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum OperandKind { /// Creates a value by loading the given place. /// /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there @@ -101,7 +108,13 @@ pub enum Operand { impl Operand { fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap, ty: Ty) -> Self { - Operand::Constant(intern_const_scalar(ConstScalar::Bytes(data, memory_map), ty)) + Operand { + kind: OperandKind::Constant(intern_const_scalar( + ConstScalar::Bytes(data, memory_map), + ty, + )), + span: None, + } } fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self { @@ -1076,11 +1089,11 @@ impl MirBody { f: &mut impl FnMut(&mut Place, &mut ProjectionStore), store: &mut ProjectionStore, ) { - match op { - Operand::Copy(p) | Operand::Move(p) => { + match &mut op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { f(p, store); } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), } } for (_, block) in self.basic_blocks.iter_mut() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index d9938fc60cd7..769510c42537 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -15,13 +15,13 @@ use crate::{ ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags, db::{HirDatabase, InternedClosure}, display::DisplayTarget, - mir::Operand, + mir::OperandKind, utils::ClosureSubst, }; use super::{ - BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, MutBorrowKind, Place, - ProjectionElem, Rvalue, StatementKind, TerminatorKind, + BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, MutBorrowKind, Operand, + Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -120,8 +120,8 @@ fn make_fetch_closure_field( fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec { let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op { - Operand::Copy(p) | Operand::Move(p) => { + let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty = body.locals[p.local].ty.clone(); let mut is_dereference_of_ref = false; for proj in p.projection.lookup(&body.projection_store) { @@ -139,10 +139,10 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec && !ty.clone().is_copy(db, body.owner) && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR) { - result.push(MovedOutOfRef { span, ty }); + result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty }); } } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -215,8 +215,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec { let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op { - Operand::Copy(p) | Operand::Move(p) => { + let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty = body.locals[p.local].ty.clone(); for proj in p.projection.lookup(&body.projection_store) { ty = proj.projected_ty( @@ -232,7 +232,7 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec result.push(PartiallyMoved { span, ty, local: p.local }); } } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -500,7 +500,7 @@ fn record_usage(local: LocalId, result: &mut ArenaMap } fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap) { - if let Operand::Copy(p) | Operand::Move(p) = arg { + if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind { record_usage(p.local, result); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index ee412dd00b3a..00e51ae20571 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -46,7 +46,7 @@ use crate::{ use super::{ AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, - Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind, + Operand, OperandKind, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind, TerminatorKind, UnOp, return_slot, }; @@ -867,10 +867,10 @@ impl Evaluator<'_> { } fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result { - Ok(match o { - Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?, - Operand::Constant(c) => c.data(Interner).ty.clone(), - &Operand::Static(s) => { + Ok(match &o.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, + OperandKind::Constant(c) => c.data(Interner).ty.clone(), + &OperandKind::Static(s) => { let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr].clone(); TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner) } @@ -1884,16 +1884,16 @@ impl Evaluator<'_> { } fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result { - Ok(match it { - Operand::Copy(p) | Operand::Move(p) => { + Ok(match &it.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p, &locals.body.projection_store); self.eval_place(p, locals)? } - Operand::Static(st) => { + OperandKind::Static(st) => { let addr = self.eval_static(*st, locals)?; Interval::new(addr, self.ptr_size()) } - Operand::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, + OperandKind::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 95c93b5f3edd..9816902fc07b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -50,6 +50,8 @@ use crate::{ utils::ClosureSubst, }; +use super::OperandKind; + mod as_place; mod pattern_matching; @@ -329,7 +331,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else { return Ok(None); }; - Ok(Some((Operand::Copy(p), current))) + Ok(Some((Operand { kind: OperandKind::Copy(p), span: Some(expr_id.into()) }, current))) } fn lower_expr_to_place_with_adjust( @@ -352,7 +354,12 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); + self.push_assignment( + current, + place, + Operand { kind: OperandKind::Copy(p), span: None }.into(), + expr_id.into(), + ); Ok(Some(current)) } Adjust::Borrow(AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) => { @@ -376,7 +383,7 @@ impl<'ctx> MirLowerCtx<'ctx> { place, Rvalue::Cast( CastKind::PointerCoercion(*cast), - Operand::Copy(p), + Operand { kind: OperandKind::Copy(p), span: None }, last.target.clone(), ), expr_id.into(), @@ -482,7 +489,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Operand::Copy(temp).into(), + Operand { kind: OperandKind::Copy(temp), span: None }.into(), expr_id.into(), ); Ok(Some(current)) @@ -523,21 +530,24 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Operand::Constant( - ConstData { - ty, - value: chalk_ir::ConstValue::BoundVar(BoundVar::new( - DebruijnIndex::INNERMOST, - generics.type_or_const_param_idx(p.into()).ok_or( - MirLowerError::TypeError( - "fail to lower const generic param", - ), - )?, - )), - } - .intern(Interner), - ) - .into(), + Rvalue::from(Operand { + kind: OperandKind::Constant( + ConstData { + ty, + value: chalk_ir::ConstValue::BoundVar(BoundVar::new( + DebruijnIndex::INNERMOST, + generics.type_or_const_param_idx(p.into()).ok_or( + MirLowerError::TypeError( + "fail to lower const generic param", + ), + )?, + )), + } + .intern(Interner), + ) + .into(), + span: None, + }), expr_id.into(), ); Ok(Some(current)) @@ -882,7 +892,7 @@ impl<'ctx> MirLowerCtx<'ctx> { })), &mut self.result.projection_store, ); - Operand::Copy(p) + Operand { kind: OperandKind::Copy(p), span: None } } }) .collect(), @@ -984,7 +994,12 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); + self.push_assignment( + current, + place, + Operand { kind: OperandKind::Copy(p), span: None }.into(), + expr_id.into(), + ); Ok(Some(current)) } Expr::UnaryOp { @@ -1061,8 +1076,11 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - let r_value = - Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op); + let r_value = Rvalue::CheckedBinaryOp( + op.into(), + Operand { kind: OperandKind::Copy(lhs_place), span: None }, + rhs_op, + ); self.push_assignment(current, lhs_place, r_value, expr_id.into()); return Ok(Some(current)); } @@ -1237,9 +1255,11 @@ impl<'ctx> MirLowerCtx<'ctx> { Rvalue::Ref(*bk, p), capture_spans[0], ); - operands.push(Operand::Move(tmp)); + operands.push(Operand { kind: OperandKind::Move(tmp), span: None }); + } + CaptureKind::ByValue => { + operands.push(Operand { kind: OperandKind::Move(p), span: None }) } - CaptureKind::ByValue => operands.push(Operand::Move(p)), } } self.push_assignment( @@ -1481,7 +1501,7 @@ impl<'ctx> MirLowerCtx<'ctx> { .const_eval(const_id, subst, None) .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))? }; - Ok(Operand::Constant(c)) + Ok(Operand { kind: OperandKind::Constant(c), span: None }) } fn write_bytes_to_place( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 7b0ee22d51fc..c2077d669fb2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,6 +1,6 @@ //! MIR lowering for places -use crate::mir::MutBorrowKind; +use crate::mir::{MutBorrowKind, Operand, OperandKind}; use super::*; use hir_def::FunctionId; @@ -156,7 +156,7 @@ impl MirLowerCtx<'_> { self.push_assignment( current, temp, - Operand::Static(s).into(), + Operand { kind: OperandKind::Static(s), span: None }.into(), expr_id.into(), ); Ok(Some(( @@ -306,7 +306,7 @@ impl MirLowerCtx<'_> { ); let Some(current) = self.lower_call( index_fn_op, - Box::new([Operand::Copy(place), index_operand]), + Box::new([Operand { kind: OperandKind::Copy(place), span: None }, index_operand]), result, current, false, @@ -366,7 +366,7 @@ impl MirLowerCtx<'_> { let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); let Some(current) = self.lower_call( deref_fn_op, - Box::new([Operand::Copy(ref_place)]), + Box::new([Operand { kind: OperandKind::Copy(ref_place), span: None }]), result, current, false, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index d6b2100253f6..7607560bdd1a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -5,10 +5,10 @@ use hir_def::{AssocItemId, hir::ExprId}; use crate::{ BindingMode, mir::{ - LocalId, MutBorrowKind, + LocalId, MutBorrowKind, Operand, OperandKind, lower::{ BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner, - MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place, + MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Pat, PatId, Place, PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs, VariantData, VariantId, @@ -217,10 +217,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place)), + Rvalue::CheckedBinaryOp( + binop, + lv, + Operand { kind: OperandKind::Copy(cond_place), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -262,7 +266,10 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(place_len), + discr: Operand { + kind: OperandKind::Copy(place_len), + span: None, + }, targets: SwitchTargets::static_if( pattern_len as u128, next, @@ -282,10 +289,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)), + Rvalue::CheckedBinaryOp( + BinOp::Le, + c, + Operand { kind: OperandKind::Copy(place_len), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -412,8 +423,8 @@ impl MirLowerCtx<'_> { tmp2, Rvalue::CheckedBinaryOp( BinOp::Eq, - Operand::Copy(tmp), - Operand::Copy(cond_place), + Operand { kind: OperandKind::Copy(tmp), span: None }, + Operand { kind: OperandKind::Copy(cond_place), span: None }, ), span, ); @@ -422,7 +433,7 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(tmp2), + discr: Operand { kind: OperandKind::Copy(tmp2), span: None }, targets: SwitchTargets::static_if(1, next, else_target), }, span, @@ -491,7 +502,7 @@ impl MirLowerCtx<'_> { self.push_assignment( current, lhs_place, - Operand::Copy(cond_place).into(), + Operand { kind: OperandKind::Copy(cond_place), span: None }.into(), expr.into(), ); (current, current_else) @@ -528,7 +539,9 @@ impl MirLowerCtx<'_> { current, target_place.into(), match mode { - BindingMode::Move => Operand::Copy(cond_place).into(), + BindingMode::Move => { + Operand { kind: OperandKind::Copy(cond_place), span: None }.into() + } BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place), BindingMode::Ref(Mutability::Mut) => { Rvalue::Ref(BorrowKind::Mut { kind: MutBorrowKind::Default }, cond_place) @@ -552,10 +565,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(BinOp::Eq, c, Operand::Copy(cond_place)), + Rvalue::CheckedBinaryOp( + BinOp::Eq, + c, + Operand { kind: OperandKind::Copy(cond_place), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -588,7 +605,7 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(tmp), + discr: Operand { kind: OperandKind::Copy(tmp), span: None }, targets: SwitchTargets::static_if(e, next, *else_target), }, span, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index c733c7ed845a..99be0d57c9a8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -25,7 +25,7 @@ use crate::{ infer::normalize, }; -use super::{MirBody, MirLowerError, Operand, Rvalue, StatementKind, TerminatorKind}; +use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind}; macro_rules! not_supported { ($it: expr) => { @@ -170,8 +170,8 @@ impl Filler<'_> { } fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { - match op { - Operand::Constant(c) => { + match &mut op.kind { + OperandKind::Constant(c) => { match &c.data(Interner).value { chalk_ir::ConstValue::BoundVar(b) => { let resolved = self @@ -215,7 +215,7 @@ impl Filler<'_> { } self.fill_const(c)?; } - Operand::Copy(_) | Operand::Move(_) | Operand::Static(_) => (), + OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (), } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index d9c0000fffd0..b65cf9dab502 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -18,8 +18,8 @@ use crate::{ }; use super::{ - AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, Place, - Rvalue, UnOp, + AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, OperandKind, + Place, Rvalue, UnOp, }; macro_rules! w { @@ -383,14 +383,14 @@ impl<'a> MirPrettyCtx<'a> { } fn operand(&mut self, r: &Operand) { - match r { - Operand::Copy(p) | Operand::Move(p) => { + match &r.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { // MIR at the time of writing doesn't have difference between move and copy, so we show them // equally. Feel free to change it. self.place(p); } - Operand::Constant(c) => w!(self, "Const({})", self.hir_display(c)), - Operand::Static(s) => w!(self, "Static({:?})", s), + OperandKind::Constant(c) => w!(self, "Const({})", self.hir_display(c)), + OperandKind::Static(s) => w!(self, "Static({:?})", s), } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 7d0f10983d73..da8eed29b03d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -18,7 +18,22 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf mod tests { use crate::tests::check_diagnostics; - // FIXME: spans are broken + #[test] + fn abc() { + check_diagnostics( + r#" +struct NotCopy; +struct S { + field: NotCopy, +} + +fn f(s: &S) -> S { + S { field: s.field } + //^^^^^^^ error: cannot move `NotCopy` out of reference +} + "#, + ); + } #[test] fn move_by_explicit_deref() { @@ -85,7 +100,7 @@ fn consume(_: X) { fn main() { let a = &X(Y); consume(*a); - //^^^^^^^^^^^ error: cannot move `X` out of reference + //^^ error: cannot move `X` out of reference let a = &X(5); consume(*a); } From d2de4c9411aeebb2bc27c2c737aaf121f48d17cb Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Fri, 28 Feb 2025 10:52:39 +0100 Subject: [PATCH 005/302] change test name to sth meaningful --- src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs | 3 +-- .../crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 9816902fc07b..acd56f02188c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -544,8 +544,7 @@ impl<'ctx> MirLowerCtx<'ctx> { )), } .intern(Interner), - ) - .into(), + ), span: None, }), expr_id.into(), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index da8eed29b03d..780271361d72 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -19,7 +19,7 @@ mod tests { use crate::tests::check_diagnostics; #[test] - fn abc() { + fn operand_field_span_respected() { check_diagnostics( r#" struct NotCopy; From cf26d82dafc95d73484b5688ccfc4eec8a9d3e52 Mon Sep 17 00:00:00 2001 From: pudongair <744355276@qq.com> Date: Wed, 26 Mar 2025 15:28:51 +0800 Subject: [PATCH 006/302] chore: remove redundant words in comment Signed-off-by: pudongair <744355276@qq.com> --- compiler/rustc_error_codes/src/error_codes/E0207.md | 2 +- library/core/src/clone.rs | 2 +- library/core/src/macros/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md index 5b35748f4723..f80b0093ecc5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0207.md +++ b/compiler/rustc_error_codes/src/error_codes/E0207.md @@ -195,7 +195,7 @@ impl<'a> Contains for Foo { Please note that unconstrained lifetime parameters are not supported if they are being used by an associated type. -In cases where the associated type's lifetime is meant to be tied to the the +In cases where the associated type's lifetime is meant to be tied to the self type, and none of the methods on the trait need ownership or different mutability, then an option is to implement the trait on a borrowed type: diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index e0ac0bfc5289..647463098610 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -427,7 +427,7 @@ pub unsafe trait CloneToUninit { /// read or dropped, because even if it was previously valid, it may have been partially /// overwritten. /// - /// The caller may wish to to take care to deallocate the allocation pointed to by `dest`, + /// The caller may wish to take care to deallocate the allocation pointed to by `dest`, /// if applicable, to avoid a memory leak (but this is not a requirement). /// /// Implementors should avoid leaking values by, upon unwinding, dropping all component values diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 5f200b31d1ae..c06f1b56399d 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1743,8 +1743,8 @@ pub(crate) mod builtin { /* compiler built-in */ } - /// Provide a list of type aliases and other opaque-type-containing type definitions. - /// This list will be used in the body of the item it is applied to define opaque + /// Provide a list of type aliases and other opaque-type-containing type definitions + /// to an item with a body. This list will be used in that body to define opaque /// types' hidden types. /// Can only be applied to things that have bodies. #[unstable( From d81559a453d7c9ca0ff9dbd64cf1a9933a54aeab Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 31 Mar 2025 19:30:05 +0200 Subject: [PATCH 007/302] Refactor `diy_float` --- library/core/src/num/diy_float.rs | 54 ++++--------------- .../core/src/num/flt2dec/strategy/grisu.rs | 8 +-- 2 files changed, 15 insertions(+), 47 deletions(-) diff --git a/library/core/src/num/diy_float.rs b/library/core/src/num/diy_float.rs index ce7f6475d059..e054e7f3f10a 100644 --- a/library/core/src/num/diy_float.rs +++ b/library/core/src/num/diy_float.rs @@ -21,61 +21,29 @@ pub struct Fp { impl Fp { /// Returns a correctly rounded product of itself and `other`. - pub fn mul(&self, other: &Fp) -> Fp { - const MASK: u64 = 0xffffffff; - let a = self.f >> 32; - let b = self.f & MASK; - let c = other.f >> 32; - let d = other.f & MASK; - let ac = a * c; - let bc = b * c; - let ad = a * d; - let bd = b * d; - let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */; - let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + pub fn mul(self, other: Self) -> Self { + let (lo, hi) = self.f.widening_mul(other.f); + let f = hi + (lo >> 63) /* round */; let e = self.e + other.e + 64; - Fp { f, e } + Self { f, e } } /// Normalizes itself so that the resulting mantissa is at least `2^63`. - pub fn normalize(&self) -> Fp { - let mut f = self.f; - let mut e = self.e; - if f >> (64 - 32) == 0 { - f <<= 32; - e -= 32; - } - if f >> (64 - 16) == 0 { - f <<= 16; - e -= 16; - } - if f >> (64 - 8) == 0 { - f <<= 8; - e -= 8; - } - if f >> (64 - 4) == 0 { - f <<= 4; - e -= 4; - } - if f >> (64 - 2) == 0 { - f <<= 2; - e -= 2; - } - if f >> (64 - 1) == 0 { - f <<= 1; - e -= 1; - } + pub fn normalize(self) -> Self { + let lz = self.f.leading_zeros(); + let f = self.f << lz; + let e = self.e - lz as i16; debug_assert!(f >= (1 << 63)); - Fp { f, e } + Self { f, e } } /// Normalizes itself to have the shared exponent. /// It can only decrease the exponent (and thus increase the mantissa). - pub fn normalize_to(&self, e: i16) -> Fp { + pub fn normalize_to(self, e: i16) -> Self { let edelta = self.e - e; assert!(edelta >= 0); let edelta = edelta as usize; assert_eq!(self.f << edelta >> edelta, self.f); - Fp { f: self.f << edelta, e } + Self { f: self.f << edelta, e } } } diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index 2816de4c6333..d3bbb0934e0f 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -196,9 +196,9 @@ pub fn format_shortest_opt<'a>( let (minusk, cached) = cached_power(ALPHA - plus.e - 64, GAMMA - plus.e - 64); // scale fps. this gives the maximal error of 1 ulp (proved from Theorem 5.1). - let plus = plus.mul(&cached); - let minus = minus.mul(&cached); - let v = v.mul(&cached); + let plus = plus.mul(cached); + let minus = minus.mul(cached); + let v = v.mul(cached); debug_assert_eq!(plus.e, minus.e); debug_assert_eq!(plus.e, v.e); @@ -480,7 +480,7 @@ pub fn format_exact_opt<'a>( // normalize and scale `v`. let v = Fp { f: d.mant, e: d.exp }.normalize(); let (minusk, cached) = cached_power(ALPHA - v.e - 64, GAMMA - v.e - 64); - let v = v.mul(&cached); + let v = v.mul(cached); // divide `v` into integral and fractional parts. let e = -v.e as usize; From ff37c7d3954ce9d1c9265e7c82a0bb7b6eba6fee Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 1 Apr 2025 13:35:16 +0200 Subject: [PATCH 008/302] std: use the address of `errno` to identify threads in `unique_thread_exit` Getting the address of `errno` should be just as cheap as `pthread_self()` and avoids having to use the expensive `Mutex` logic because it always results in a pointer. --- library/std/src/sys/exit_guard.rs | 43 ++++++++++++++---------------- library/std/src/sys/pal/unix/os.rs | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index 5a090f506661..bd70d1782440 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -1,14 +1,5 @@ cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - /// pthread_t is a pointer on some platforms, - /// so we wrap it in this to impl Send + Sync. - #[derive(Clone, Copy)] - #[repr(transparent)] - struct PThread(libc::pthread_t); - // Safety: pthread_t is safe to send between threads - unsafe impl Send for PThread {} - // Safety: pthread_t is safe to share between threads - unsafe impl Sync for PThread {} /// Mitigation for /// /// On glibc, `libc::exit` has been observed to not always be thread-safe. @@ -30,28 +21,34 @@ cfg_if::cfg_if! { /// (waiting for the process to exit). #[cfg_attr(any(test, doctest), allow(dead_code))] pub(crate) fn unique_thread_exit() { - let this_thread_id = unsafe { libc::pthread_self() }; - use crate::sync::{Mutex, PoisonError}; - static EXITING_THREAD_ID: Mutex> = Mutex::new(None); - let mut exiting_thread_id = - EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); - match *exiting_thread_id { - None => { + use crate::ffi::c_int; + use crate::ptr; + use crate::sync::atomic::AtomicPtr; + use crate::sync::atomic::Ordering::{Acquire, Relaxed}; + + static EXITING_THREAD_ID: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + // We use the address of `errno` as a cheap and safe way to identify + // threads. As the C standard mandates that `errno` must have thread + // storage duration, we can rely on its address not changing over the + // lifetime of the thread. Additionally, accesses to `errno` are + // async-signal-safe, so this function is available in all imaginable + // circumstances. + let this_thread_id = crate::sys::os::errno_location(); + match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + Ok(_) => { // This is the first thread to call `unique_thread_exit`, - // and this is the first time it is called. - // Set EXITING_THREAD_ID to this thread's ID and return. - *exiting_thread_id = Some(PThread(this_thread_id)); - }, - Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => { + // and this is the first time it is called. Continue exiting. + } + Err(exiting_thread_id) if exiting_thread_id == this_thread_id => { // This is the first thread to call `unique_thread_exit`, // but this is the second time it is called. // Abort the process. core::panicking::panic_nounwind("std::process::exit called re-entrantly") } - Some(_) => { + Err(_) => { // This is not the first thread to call `unique_thread_exit`. // Pause until the process exits. - drop(exiting_thread_id); loop { // Safety: libc::pause is safe to call. unsafe { libc::pause(); } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f47421c67051..3b712f316cd0 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -61,7 +61,7 @@ unsafe extern "C" { #[cfg_attr(target_os = "aix", link_name = "_Errno")] // SAFETY: this will always return the same pointer on a given thread. #[unsafe(ffi_const)] - fn errno_location() -> *mut c_int; + pub safe fn errno_location() -> *mut c_int; } /// Returns the platform-specific value of errno From b840942d1dd66d85c631f336b5a57f57f7a79b7f Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 8 Apr 2025 15:11:58 +0800 Subject: [PATCH 009/302] Stabilize precise capture syntax in style guide Signed-off-by: xizheyin --- src/doc/style-guide/src/nightly.md | 12 ------------ src/doc/style-guide/src/types.md | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md index d870edf18882..66e7fa3c9f89 100644 --- a/src/doc/style-guide/src/nightly.md +++ b/src/doc/style-guide/src/nightly.md @@ -5,15 +5,3 @@ This chapter documents style and formatting for nightly-only syntax. The rest of Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization. There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter. - -### `feature(precise_capturing)` - -A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`. - -``` -fn foo() -> impl Sized + use<'a> {} - -// is formatted analogously to: - -fn foo() -> impl Sized + Use<'a> {} -``` diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md index b7921c8914e4..247f05b57695 100644 --- a/src/doc/style-guide/src/types.md +++ b/src/doc/style-guide/src/types.md @@ -59,3 +59,15 @@ Box< + Debug > ``` + +## Precise capturing bounds + +A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`. + +```rust +fn foo() -> impl Sized + use<'a> {} + +// is formatted analogously to: + +fn foo() -> impl Sized + Use<'a> {} +``` From cbfe1f5f587c314ad64c57a7c7d2b38cdb3d3b7e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 3 Apr 2025 00:02:44 +0200 Subject: [PATCH 010/302] Restrict the cases where `ptr_eq` triggers `ptr_eq` was recently enhanced to lint on more cases of raw pointers comparison: - lint on all raw pointer comparison, by proposing to use `[core|std]::ptr::eq(lhs, rhs)` instead of `lhs == rhs`; - removing one symetric `as usize` on each size if needed - peeling any level of `as *[const|mut] _` if the remaining expression can still be coerced into the original one (i.e., is a ref or raw pointer to the same type as before) The current change restricts the lint to the cases where at least one level of symetric `as usize`, or any conversion to a raw pointer, could be removed. For example, a direct comparaison of two raw pointers will not trigger the lint anymore. --- clippy_lints/src/ptr.rs | 22 ++++++++++++-------- tests/ui/ptr_eq.fixed | 26 +++++++++++++----------- tests/ui/ptr_eq.rs | 16 ++++++++------- tests/ui/ptr_eq.stderr | 38 ++++------------------------------- tests/ui/ptr_eq_no_std.fixed | 20 +++++++++--------- tests/ui/ptr_eq_no_std.rs | 12 ++++++----- tests/ui/ptr_eq_no_std.stderr | 26 +----------------------- 7 files changed, 60 insertions(+), 100 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 5fb4d3a837b1..b76e54c382db 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -715,9 +715,9 @@ fn check_ptr_eq<'tcx>( } // Remove one level of usize conversion if any - let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { - (Some(lhs), Some(rhs)) => (lhs, rhs), - _ => (left, right), + let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { + (Some(lhs), Some(rhs)) => (lhs, rhs, true), + _ => (left, right, false), }; // This lint concerns raw pointers @@ -726,7 +726,12 @@ fn check_ptr_eq<'tcx>( return; } - let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) = + (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + + if !(usize_peeled || left_casts_peeled || right_casts_peeled) { + return; + } let mut app = Applicability::MachineApplicable; let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app); @@ -759,8 +764,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_> } } -// Peel raw casts if the remaining expression can be coerced to it -fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> { +// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been +// peeled or not. +fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) { if !expr.span.from_expansion() && let ExprKind::Cast(inner, _) = expr.kind && let ty::RawPtr(target_ty, _) = expr_ty.kind() @@ -768,8 +774,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind() && target_ty == inner_target_ty { - peel_raw_casts(cx, inner, inner_ty) + (peel_raw_casts(cx, inner, inner_ty).0, true) } else { - expr + (expr, false) } } diff --git a/tests/ui/ptr_eq.fixed b/tests/ui/ptr_eq.fixed index 484ff3073239..f0150e6784b4 100644 --- a/tests/ui/ptr_eq.fixed +++ b/tests/ui/ptr_eq.fixed @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = std::ptr::eq(a, b); //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq + + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,9 +53,9 @@ fn main() { let _ = !std::ptr::eq(x, y); //~^ ptr_eq - #[allow(clippy::eq_op)] - let _issue14337 = std::ptr::eq(main as *const (), main as *const ()); - //~^ ptr_eq + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type + let _issue14337 = main as *const () == main as *const (); // Do not peel the content of macros let _ = std::ptr::eq(mac!(cast a), mac!(cast b)); diff --git a/tests/ui/ptr_eq.rs b/tests/ui/ptr_eq.rs index f28707cc3e92..3fb89257cf1b 100644 --- a/tests/ui/ptr_eq.rs +++ b/tests/ui/ptr_eq.rs @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,9 +53,9 @@ fn main() { let _ = x as *const u32 != y as *mut u32 as *const u32; //~^ ptr_eq - #[allow(clippy::eq_op)] + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type let _issue14337 = main as *const () == main as *const (); - //~^ ptr_eq // Do not peel the content of macros let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; diff --git a/tests/ui/ptr_eq.stderr b/tests/ui/ptr_eq.stderr index 906831b9e031..f613e164b879 100644 --- a/tests/ui/ptr_eq.stderr +++ b/tests/ui/ptr_eq.stderr @@ -14,52 +14,22 @@ LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:26:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:28:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:39:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:41:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:48:13 + --> tests/ui/ptr_eq.rs:50:13 | LL | let _ = x as *const u32 == y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:51:13 + --> tests/ui/ptr_eq.rs:53:13 | LL | let _ = x as *const u32 != y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:55:23 - | -LL | let _issue14337 = main as *const () == main as *const (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:59:13 + --> tests/ui/ptr_eq.rs:61:13 | LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/ptr_eq_no_std.fixed b/tests/ui/ptr_eq_no_std.fixed index d8ee4ea88f84..48cbad62e1a3 100644 --- a/tests/ui/ptr_eq_no_std.fixed +++ b/tests/ui/ptr_eq_no_std.fixed @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = core::ptr::eq(a, b); //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq + + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/tests/ui/ptr_eq_no_std.rs b/tests/ui/ptr_eq_no_std.rs index a236314c29b7..3827178640ee 100644 --- a/tests/ui/ptr_eq_no_std.rs +++ b/tests/ui/ptr_eq_no_std.rs @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/tests/ui/ptr_eq_no_std.stderr b/tests/ui/ptr_eq_no_std.stderr index 5b8135dc8e8b..8c7b1ff76661 100644 --- a/tests/ui/ptr_eq_no_std.stderr +++ b/tests/ui/ptr_eq_no_std.stderr @@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:35:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:37:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:48:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:50:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors From a576362620a5e0691054a48fcdc7ba5038c042c5 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Thu, 10 Apr 2025 10:58:49 +1000 Subject: [PATCH 011/302] Document async block control flow in async keyword --- library/std/src/keyword_docs.rs | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c07c391892d8..93306296847c 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2388,6 +2388,40 @@ mod while_keyword {} /// /// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. /// +/// ## Control Flow +/// [`return`] statements and [`?`][try operator] operators within `async` blocks do not cause +/// a return from the parent function; rather, they cause the `Future` returned by the block to +/// return with that value. +/// +/// For example, the following Rust function will return `5`, assigning the `!` value to `x`, which +/// goes unused: +/// ```rust +/// #[expect(unused_variables)] +/// fn example() -> i32 { +/// let x = { +/// return 5; +/// }; +/// } +/// ``` +/// In contrast, the following asynchronous function assigns a `Future` to `x`, and +/// only returns `5` when `x` is `.await`ed: +/// ```rust +/// async fn example() -> i32 { +/// let x = async { +/// return 5; +/// }; +/// +/// x.await +/// } +/// ``` +/// Code using `?` behaves similarly - it causes the `async` block to return a [`Result`] without +/// affecting the parent function. +/// +/// Note that you cannot use `break` or `continue` from within an `async` block to affect the +/// control flow of a loop in the parent function. +/// +/// Control flow in `async` blocks is documented further in the [async book][async book blocks]. +/// /// ## Editions /// /// `async` is a keyword from the 2018 edition onwards. @@ -2397,6 +2431,10 @@ mod while_keyword {} /// [`Future`]: future::Future /// [`.await`]: ../std/keyword.await.html /// [async book]: https://rust-lang.github.io/async-book/ +/// [`return`]: ../std/keyword.return.html +/// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [`Result`]: result::Result +/// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {} #[doc(keyword = "await")] From e2caab1822d858de4525ae615002094ab6e06734 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Thu, 10 Apr 2025 11:11:09 +1000 Subject: [PATCH 012/302] Doc more control flow behaviour for return keyword --- library/std/src/keyword_docs.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 93306296847c..b8eb0fd104c3 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1195,6 +1195,28 @@ mod ref_keyword {} /// Ok(()) /// } /// ``` +/// +/// Within [closures] and [`async`] blocks, `return` returns a value from within the closure or +/// `async` block, not from the parent function: +/// +/// ```rust +/// fn foo() -> i32 { +/// let closure = || { +/// return 5; +/// }; +/// +/// let future = async { +/// return 10; +/// }; +/// +/// return 15; +/// } +/// +/// assert_eq!(foo(), 15); +/// ``` +/// +/// [closures]: ../book/ch13-01-closures.html +/// [`async`]: ../std/keyword.async.html mod return_keyword {} #[doc(keyword = "self")] From e5fb426a833e45565f13f81c2c664e77e0e351f1 Mon Sep 17 00:00:00 2001 From: Diego Ongaro Date: Sun, 13 Apr 2025 19:52:34 -0700 Subject: [PATCH 013/302] docs: Add example to `Iterator::take` with `by_ref` If you want to logically split an iterator after `n` items, you might first discover `take`. Before this change, you'd find that `take` consumes the iterator, and you'd probably be stuck. The answer involves `by_ref`, but that's hard to discover, especially since `by_ref` is a bit abstract and `Iterator` has many methods. After this change, you'd see the example showing `take` along with `by_ref`, which allows you to continue using the rest of the iterator. `by_ref` had a good example involving `take` already, so this change just duplicates that existing example under `take`. --- library/core/src/iter/traits/iterator.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d9534a445980..c68fd2115d68 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1340,6 +1340,24 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Use [`by_ref`] to take from the iterator without consuming it, and then + /// continue using the original iterator: + /// + /// ``` + /// let mut words = ["hello", "world", "of", "Rust"].into_iter(); + /// + /// // Take the first two words. + /// let hello_world: Vec<_> = words.by_ref().take(2).collect(); + /// assert_eq!(hello_world, vec!["hello", "world"]); + /// + /// // Collect the rest of the words. + /// // We can only do this because we used `by_ref` earlier. + /// let of_rust: Vec<_> = words.collect(); + /// assert_eq!(of_rust, vec!["of", "Rust"]); + /// ``` + /// + /// [`by_ref`]: Iterator::by_ref #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take(self, n: usize) -> Take From 0369ccb5320da3871bc03e6b0df8afbbfac0c9b9 Mon Sep 17 00:00:00 2001 From: Janggun Lee Date: Mon, 14 Apr 2025 22:26:43 +0900 Subject: [PATCH 014/302] Fix some grammar errors and hyperlinks in doc for `trait Allocator` * "while until either" could also be changed to "for a while until either", but I just deleted "while". * fixed sentence with incorrect "at" and "has/have". * linked [*currently allocated*] similar to other methods. --- library/core/src/alloc/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 9805cee1c331..9d608d5e83c4 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -90,7 +90,7 @@ impl fmt::Display for AllocError { /// # Safety /// /// Memory blocks that are [*currently allocated*] by an allocator, -/// must point to valid memory, and retain their validity while until either: +/// must point to valid memory, and retain their validity until either: /// - the memory block is deallocated, or /// - the allocator is dropped. /// @@ -112,7 +112,9 @@ pub unsafe trait Allocator { /// /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of: /// - the borrow-checker lifetime of the allocator type itself. - /// - as long as at the allocator and all its clones has not been dropped. + /// - as long as the allocator and all its clones have not been dropped. + /// + /// [*currently allocated*]: #currently-allocated-memory /// /// # Errors /// From 31cb737dee5193ba44ce26c429057f4681510fe7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Apr 2025 11:22:10 +0200 Subject: [PATCH 015/302] simd_select_bitmask: the 'padding' bits in the mask are just ignored --- library/core/src/intrinsics/simd.rs | 4 +--- src/tools/miri/src/intrinsics/simd.rs | 13 +------------ .../intrinsics/simd-select-bitmask-invalid.rs | 15 --------------- .../intrinsics/simd-select-bitmask-invalid.stderr | 15 --------------- .../miri/tests/pass/intrinsics/portable-simd.rs | 13 +++++++++++++ 5 files changed, 15 insertions(+), 45 deletions(-) delete mode 100644 src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs delete mode 100644 src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 9ac6ee855355..facc2e7f0853 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -577,11 +577,9 @@ pub unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// For each element, if the bit in `mask` is `1`, select the element from /// `if_true`. If the corresponding bit in `mask` is `0`, select the element from /// `if_false`. +/// The remaining bits of the mask are ignored. /// /// The bitmask bit order matches `simd_bitmask`. -/// -/// # Safety -/// Padding bits must be all zero. #[rustc_intrinsic] #[rustc_nounwind] pub unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index de5da6ec898a..c9250ba1b818 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -506,7 +506,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let dest_len = u32::try_from(dest_len).unwrap(); - let bitmask_len = u32::try_from(bitmask_len).unwrap(); for i in 0..dest_len { let bit_i = simd_bitmask_index(i, dest_len, this.data_layout().endian); let mask = mask & 1u64.strict_shl(bit_i); @@ -517,17 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if mask != 0 { yes } else { no }; this.write_immediate(*val, &dest)?; } - for i in dest_len..bitmask_len { - // If the mask is "padded", ensure that padding is all-zero. - // This deliberately does not use `simd_bitmask_index`; these bits are outside - // the bitmask. It does not matter in which order we check them. - let mask = mask & 1u64.strict_shl(i); - if mask != 0 { - throw_ub_format!( - "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" - ); - } - } + // The remaining bits of the mask are ignored. } // Converts a "vector of bool" into a bitmask. "bitmask" => { diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs deleted file mode 100644 index 409098ac3b5d..000000000000 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(core_intrinsics, repr_simd)] - -use std::intrinsics::simd::simd_select_bitmask; - -#[repr(simd)] -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -struct i32x2([i32; 2]); - -fn main() { - unsafe { - let x = i32x2([0, 1]); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits - } -} diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr deleted file mode 100644 index 9acb51d8c5f3..000000000000 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits - --> tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC - | -LL | simd_select_bitmask(0b11111111u8, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index cc753dac2156..e14ce51f35a3 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -331,6 +331,19 @@ fn simd_mask() { ); assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); assert_eq!(selected2, selected1); + // Non-zero "padding" (the extra bits) is also allowed. + let selected1 = simd_select_bitmask::( + if cfg!(target_endian = "little") { 0b11111000 } else { 0b11110001 }, + i32x4::splat(1), // yes + i32x4::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 1], _>( + if cfg!(target_endian = "little") { [0b11111000] } else { [0b11110001] }, + i32x4::splat(1), // yes + i32x4::splat(0), // no + ); + assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); + assert_eq!(selected2, selected1); } // Non-power-of-2 multi-byte mask. From 3a372e39ca54339925bf01ead93b3c1dc01078d2 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 20 Apr 2025 14:32:33 +0800 Subject: [PATCH 016/302] std: mention `remove_dir_all` can emit `DirectoryNotEmpty` when concurrently written into Signed-off-by: xizheyin --- library/std/src/fs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 801baf3d9907..0e306d23dd93 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2874,6 +2874,8 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// Consider ignoring the error if validating the removal is not required for your use case. /// +/// This function may return [`io::ErrorKind::DirectoryNotEmpty`] if the directory is concurrently +/// written into, which typically indicates some contents were removed but not all. /// [`io::ErrorKind::NotFound`] is only returned if no removal occurs. /// /// [`fs::remove_file`]: remove_file From 11cfc16a60dcca27a1872fa3e83df35d797e8521 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 20 Apr 2025 20:56:41 +0800 Subject: [PATCH 017/302] mir-opt: Use one MirPatch in MatchBranchSimplification --- .../rustc_mir_transform/src/match_branches.rs | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index b37241185c93..8c0c30968990 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -19,30 +19,32 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let typing_env = body.typing_env(tcx); - let mut should_cleanup = false; - for bb_idx in body.basic_blocks.indices() { - match &body.basic_blocks[bb_idx].terminator().kind { + let mut apply_patch = false; + let mut patch = MirPatch::new(body); + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + match &bb_data.terminator().kind { TerminatorKind::SwitchInt { discr: Operand::Copy(_) | Operand::Move(_), targets, .. // We require that the possible target blocks don't contain this block. - } if !targets.all_targets().contains(&bb_idx) => {} + } if !targets.all_targets().contains(&bb) => {} // Only optimize switch int statements _ => continue, }; - if SimplifyToIf.simplify(tcx, body, bb_idx, typing_env).is_some() { - should_cleanup = true; + if SimplifyToIf.simplify(tcx, body, &mut patch, bb, typing_env).is_some() { + apply_patch = true; continue; } - if SimplifyToExp::default().simplify(tcx, body, bb_idx, typing_env).is_some() { - should_cleanup = true; + if SimplifyToExp::default().simplify(tcx, body, &mut patch, bb, typing_env).is_some() { + apply_patch = true; continue; } } - if should_cleanup { + if apply_patch { + patch.apply(body); simplify_cfg(tcx, body); } } @@ -59,7 +61,8 @@ trait SimplifyMatch<'tcx> { fn simplify( &mut self, tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, + body: &Body<'tcx>, + patch: &mut MirPatch<'tcx>, switch_bb_idx: BasicBlock, typing_env: ty::TypingEnv<'tcx>, ) -> Option<()> { @@ -73,8 +76,6 @@ trait SimplifyMatch<'tcx> { let discr_ty = discr.ty(body.local_decls(), tcx); self.can_simplify(tcx, targets, typing_env, bbs, discr_ty)?; - let mut patch = MirPatch::new(body); - // Take ownership of items now that we know we can optimize. let discr = discr.clone(); @@ -87,19 +88,9 @@ trait SimplifyMatch<'tcx> { let parent_end = Location { block: switch_bb_idx, statement_index }; patch.add_statement(parent_end, StatementKind::StorageLive(discr_local)); patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr)); - self.new_stmts( - tcx, - targets, - typing_env, - &mut patch, - parent_end, - bbs, - discr_local, - discr_ty, - ); + self.new_stmts(tcx, targets, typing_env, patch, parent_end, bbs, discr_local, discr_ty); patch.add_statement(parent_end, StatementKind::StorageDead(discr_local)); patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone()); - patch.apply(body); Some(()) } From 5881b7c68b353c3723133c43f209802b3a0c9621 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 21 Apr 2025 21:46:35 +0800 Subject: [PATCH 018/302] mir-opt: execute MatchBranchSimplification after GVN This can provide more opportunities for MatchBranchSimplification. --- compiler/rustc_mir_transform/src/lib.rs | 3 +-- ...l_unsigned_smaller.Inline.panic-abort.diff | 14 +++++------ ..._unsigned_smaller.Inline.panic-unwind.diff | 14 +++++------ ..._shr_signed_bigger.Inline.panic-abort.diff | 14 +++++------ ...shr_signed_bigger.Inline.panic-unwind.diff | 14 +++++------ ...d.unwrap_unchecked.Inline.panic-abort.diff | 16 ++++++------- ....unwrap_unchecked.Inline.panic-unwind.diff | 16 ++++++------- ...hecked.InstSimplify-after-simplifycfg.diff | 18 +++++++------- ...e_75439.foo.MatchBranchSimplification.diff | 24 ++++++------------- .../matchbr.match1.PreCodegen.after.mir | 13 ++++++++++ tests/mir-opt/pre-codegen/matchbr.rs | 10 ++++++++ ....foo.SimplifyLocals-final.panic-abort.diff | 5 ++-- ...foo.SimplifyLocals-final.panic-unwind.diff | 5 ++-- 13 files changed, 90 insertions(+), 76 deletions(-) create mode 100644 tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/matchbr.rs diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4d74ecddfb05..8b81f0e61797 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -699,8 +699,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Now, we need to shrink the generated MIR. &ref_prop::ReferencePropagation, &sroa::ScalarReplacementOfAggregates, - &match_branches::MatchBranchSimplification, - // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, // After simplifycfg, it allows us to discover new opportunities for peephole // optimizations. @@ -709,6 +707,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &dead_store_elimination::DeadStoreElimination::Initial, &gvn::GVN, &simplify::SimplifyLocals::AfterGVN, + &match_branches::MatchBranchSimplification, &dataflow_const_prop::DataflowConstProp, &single_use_consts::SingleUseConsts, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index f36157a762c2..39ba480d2033 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -8,9 +8,9 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shl) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShlUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index be1b066c6c1b..5a758d357406 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -8,9 +8,9 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shl) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShlUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index 360687f3c4e7..a0caf141f2d0 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -8,9 +8,9 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shr) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShrUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index 986df55df037..633089e7b2a2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -8,9 +8,9 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shr) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShrUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 28878736ed7c..a5986a4315a2 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -10,9 +10,9 @@ + scope 2 { + } + scope 3 (inlined unreachable_unchecked) { -+ let mut _4: bool; -+ let _5: (); ++ let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { ++ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -24,7 +24,7 @@ _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable]; + StorageLive(_3); -+ StorageLive(_5); ++ StorageLive(_4); + _3 = discriminant(_2); + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -34,15 +34,15 @@ + } + + bb2: { -+ StorageLive(_4); -+ _4 = UbChecks(); -+ assume(copy _4); -+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = UbChecks(); ++ assume(copy _5); ++ _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + + bb3: { + _0 = move ((_2 as Some).0: T); -+ StorageDead(_5); ++ StorageDead(_4); + StorageDead(_3); StorageDead(_2); return; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index 27b6bb6a5bb2..12b03a6b6d92 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -10,9 +10,9 @@ + scope 2 { + } + scope 3 (inlined unreachable_unchecked) { -+ let mut _4: bool; -+ let _5: (); ++ let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { ++ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -24,7 +24,7 @@ _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2]; + StorageLive(_3); -+ StorageLive(_5); ++ StorageLive(_4); + _3 = discriminant(_2); + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -38,15 +38,15 @@ - bb2 (cleanup): { - resume; + bb2: { -+ StorageLive(_4); -+ _4 = UbChecks(); -+ assume(copy _4); -+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = UbChecks(); ++ assume(copy _5); ++ _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + + bb3: { + _0 = move ((_2 as Some).0: T); -+ StorageDead(_5); ++ StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + return; diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 5fee9a6733dd..82353a2d5404 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -10,9 +10,9 @@ scope 2 { } scope 3 (inlined unreachable_unchecked) { - let mut _4: bool; - let _5: (); + let _4: (); scope 4 (inlined core::ub_checks::check_language_ub) { + let mut _5: bool; scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -23,7 +23,7 @@ StorageLive(_2); _2 = copy _1; StorageLive(_3); - StorageLive(_5); + StorageLive(_4); _3 = discriminant(_2); switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -33,16 +33,16 @@ } bb2: { - StorageLive(_4); -- _4 = UbChecks(); -+ _4 = const false; - assume(copy _4); - _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + StorageLive(_5); +- _5 = UbChecks(); ++ _5 = const false; + assume(copy _5); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; } bb3: { _0 = move ((_2 as Some).0: i32); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); StorageDead(_2); return; diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index 1ab9be966522..d8eace98d556 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -5,23 +5,18 @@ debug bytes => _1; let mut _0: std::option::Option<[u8; 4]>; let _2: [u32; 4]; - let mut _3: [u8; 16]; - let mut _5: [u8; 4]; - let mut _6: u32; + let mut _4: [u8; 4]; scope 1 { debug dwords => _2; scope 2 { - debug ip => _4; - let _4: u32; + debug ip => _3; + let _3: u32; } } bb0: { StorageLive(_2); - StorageLive(_3); - _3 = copy _1; - _2 = move _3 as [u32; 4] (Transmute); - StorageDead(_3); + _2 = copy _1 as [u32; 4] (Transmute); switchInt(copy _2[0 of 4]) -> [0: bb1, otherwise: bb4]; } @@ -34,15 +29,10 @@ } bb3: { + _3 = copy _2[3 of 4]; StorageLive(_4); - _4 = copy _2[3 of 4]; - StorageLive(_5); - StorageLive(_6); - _6 = copy _4; - _5 = move _6 as [u8; 4] (Transmute); - StorageDead(_6); - _0 = Option::<[u8; 4]>::Some(move _5); - StorageDead(_5); + _4 = copy _3 as [u8; 4] (Transmute); + _0 = Option::<[u8; 4]>::Some(move _4); StorageDead(_4); goto -> bb5; } diff --git a/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir new file mode 100644 index 000000000000..3a202728ea91 --- /dev/null +++ b/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir @@ -0,0 +1,13 @@ +// MIR for `match1` after PreCodegen + +fn match1(_1: bool, _2: i32, _3: i32) -> i32 { + debug c => _1; + debug v1 => _2; + debug v2 => _3; + let mut _0: i32; + + bb0: { + _0 = Sub(copy _2, copy _3); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/matchbr.rs b/tests/mir-opt/pre-codegen/matchbr.rs new file mode 100644 index 000000000000..1822739da2c7 --- /dev/null +++ b/tests/mir-opt/pre-codegen/matchbr.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +// EMIT_MIR matchbr.match1.PreCodegen.after.mir +pub fn match1(c: bool, v1: i32, v2: i32) -> i32 { + // CHECK-LABEL: fn match1( + // CHECK: bb0: + // CHECK-NEXT: _0 = Sub + // CHECK-NEXT: return; + if c { v1 - v2 } else { v1 - v2 } +} diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff index c363dfcbf70b..ff1bc58524bc 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff @@ -8,6 +8,9 @@ let mut _3: std::option::Option; let mut _4: isize; let mut _5: isize; +- let mut _7: bool; +- let mut _8: u8; +- let mut _9: bool; scope 1 { debug a => _6; let _6: u8; @@ -32,9 +35,7 @@ } bb2: { - StorageLive(_6); _6 = copy (((_1.0: std::option::Option) as Some).0: u8); - StorageDead(_6); goto -> bb3; } diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff index 895b0067d2e6..2c289c664754 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff @@ -8,6 +8,9 @@ let mut _3: std::option::Option; let mut _4: isize; let mut _5: isize; +- let mut _7: bool; +- let mut _8: u8; +- let mut _9: bool; scope 1 { debug a => _6; let _6: u8; @@ -32,9 +35,7 @@ } bb2: { - StorageLive(_6); _6 = copy (((_1.0: std::option::Option) as Some).0: u8); - StorageDead(_6); goto -> bb3; } From d2d844c65dd120a9f3cab15d7519499fcc4130a0 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:19:49 +0200 Subject: [PATCH 019/302] Improve rustc_on_unimplemented ui test --- tests/ui/on-unimplemented/bad-annotation.rs | 69 ++++++++++-------- .../ui/on-unimplemented/bad-annotation.stderr | 70 +++++++++++++------ 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index f2b978657597..32b825ee3cc2 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -1,64 +1,73 @@ -// ignore-tidy-linelength - +#![crate_type = "lib"] #![feature(rustc_attrs)] - #![allow(unused)] #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"] -trait Foo -{} +trait Foo {} -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented = "a collection of type `{Self}` cannot \ + be built from an iterator over elements of type `{A}`"] trait MyFromIterator { /// Builds a container with elements from an external iterator. - fn my_from_iter>(iterator: T) -> Self; + fn my_from_iter>(iterator: T) -> Self; } #[rustc_on_unimplemented] //~^ ERROR malformed `rustc_on_unimplemented` attribute -trait BadAnnotation1 -{} +trait NoContent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] //~^ ERROR cannot find parameter C on this trait -trait BadAnnotation2 -{} +trait ParameterNotPresent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] //~^ ERROR positional format arguments are not allowed here -trait BadAnnotation3 -{} +trait NoPositionalArgs {} -#[rustc_on_unimplemented(lorem="")] +#[rustc_on_unimplemented(lorem = "")] //~^ ERROR this attribute must have a valid -trait BadAnnotation4 {} +trait EmptyMessage {} #[rustc_on_unimplemented(lorem(ipsum(dolor)))] //~^ ERROR this attribute must have a valid -trait BadAnnotation5 {} +trait Invalid {} -#[rustc_on_unimplemented(message="x", message="y")] +#[rustc_on_unimplemented(message = "x", message = "y")] //~^ ERROR this attribute must have a valid -trait BadAnnotation6 {} +trait DuplicateMessage {} -#[rustc_on_unimplemented(message="x", on(desugared, message="y"))] +#[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] //~^ ERROR this attribute must have a valid -trait BadAnnotation7 {} +trait OnInWrongPosition {} -#[rustc_on_unimplemented(on(), message="y")] +#[rustc_on_unimplemented(on(), message = "y")] //~^ ERROR empty `on`-clause -trait BadAnnotation8 {} +trait NoEmptyOn {} -#[rustc_on_unimplemented(on="x", message="y")] +#[rustc_on_unimplemented(on = "x", message = "y")] //~^ ERROR this attribute must have a valid -trait BadAnnotation9 {} +trait ExpectedPredicateInOn {} -#[rustc_on_unimplemented(on(x="y"), message="y")] -trait BadAnnotation10 {} +#[rustc_on_unimplemented(on(x = "y"), message = "y")] +trait OnWithoutDirectives {} -#[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] +#[rustc_on_unimplemented(on(desugared, on(desugared, message = "x")), message = "y")] //~^ ERROR this attribute must have a valid -trait BadAnnotation11 {} +trait NoNestedOn {} -pub fn main() { -} +// caught by `OnUnimplementedDirective::parse`, *not* `eval_condition` +#[rustc_on_unimplemented(on("y", message = "y"))] +//~^ ERROR invalid `on`-clause +trait UnsupportedLiteral {} + +#[rustc_on_unimplemented(on(not(a, b), message = "y"))] +//~^ ERROR expected 1 cfg-pattern +trait ExpectedOnePattern {} + +#[rustc_on_unimplemented(on(thing::What, message = "y"))] +//~^ ERROR `cfg` predicate key must be an identifier +trait KeyMustBeIdentifier {} + +#[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] +//~^ ERROR `cfg` predicate key must be an identifier +trait KeyMustBeIdentifier2 {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index afd737dc85e6..817d3c42cf69 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -1,5 +1,5 @@ error: malformed `rustc_on_unimplemented` attribute input - --> $DIR/bad-annotation.rs:17:1 + --> $DIR/bad-annotation.rs:15:1 | LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,27 +12,27 @@ LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /* | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0230]: cannot find parameter C on this trait - --> $DIR/bad-annotation.rs:22:90 + --> $DIR/bad-annotation.rs:19:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] | ^ error[E0231]: positional format arguments are not allowed here - --> $DIR/bad-annotation.rs:27:90 + --> $DIR/bad-annotation.rs:23:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] | ^ error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:32:26 + --> $DIR/bad-annotation.rs:27:26 | -LL | #[rustc_on_unimplemented(lorem="")] - | ^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(lorem = "")] + | ^^^^^^^^^^ expected value here | = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:36:26 + --> $DIR/bad-annotation.rs:31:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ expected value here @@ -40,44 +40,68 @@ LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:40:39 + --> $DIR/bad-annotation.rs:35:41 | -LL | #[rustc_on_unimplemented(message="x", message="y")] - | ^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", message = "y")] + | ^^^^^^^^^^^^^ expected value here | = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:44:39 + --> $DIR/bad-annotation.rs:39:41 | -LL | #[rustc_on_unimplemented(message="x", on(desugared, message="y"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:48:26 + --> $DIR/bad-annotation.rs:43:26 | -LL | #[rustc_on_unimplemented(on(), message="y")] +LL | #[rustc_on_unimplemented(on(), message = "y")] | ^^^^ empty on-clause here error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:52:26 + --> $DIR/bad-annotation.rs:47:26 | -LL | #[rustc_on_unimplemented(on="x", message="y")] - | ^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on = "x", message = "y")] + | ^^^^^^^^ expected value here | = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:59:40 + --> $DIR/bad-annotation.rs:54:40 | -LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message = "x")), message = "y")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | = note: eg `#[rustc_on_unimplemented(message="foo")]` -error: aborting due to 10 previous errors +error[E0232]: invalid `on`-clause in `#[rustc_on_unimplemented]` + --> $DIR/bad-annotation.rs:59:26 + | +LL | #[rustc_on_unimplemented(on("y", message = "y"))] + | ^^^^^^^^^^^^^^^^^^^^^^ invalid on-clause here -Some errors have detailed explanations: E0230, E0231, E0232. +error[E0536]: expected 1 cfg-pattern + --> $DIR/bad-annotation.rs:63:29 + | +LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] + | ^^^^^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/bad-annotation.rs:67:29 + | +LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] + | ^^^^^^^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/bad-annotation.rs:71:29 + | +LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] + | ^^^^^^^^^^^ + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0230, E0231, E0232, E0536. For more information about an error, try `rustc --explain E0230`. From ff428d91c2b690b8dbd8cc1e48274870c24fe1e2 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 22 Apr 2025 16:10:59 +0200 Subject: [PATCH 020/302] Merge commit '0621446356e20fd2ead13a6763bb936c95eb0cfa' into clippy-subtree-update --- .github/workflows/clippy_changelog.yml | 2 +- .github/workflows/clippy_mq.yml | 2 +- .github/workflows/clippy_pr.yml | 2 +- .github/workflows/deploy.yml | 4 + .github/workflows/lintcheck.yml | 4 +- CHANGELOG.md | 70 +++- Cargo.toml | 9 +- rinja.toml => askama.toml | 0 book/src/SUMMARY.md | 1 + book/src/development/adding_lints.md | 22 +- book/src/development/basics.md | 2 +- .../development/common_tools_writing_lints.md | 10 +- book/src/development/defining_lints.md | 3 +- .../infrastructure/benchmarking.md | 55 +++ .../src/development/infrastructure/release.md | 3 - book/src/development/infrastructure/sync.md | 2 +- book/src/development/writing_tests.md | 38 +- book/src/lint_configuration.md | 56 ++- clippy.toml | 7 +- clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 206 +++++++--- clippy_config/src/lib.rs | 1 + clippy_config/src/types.rs | 114 +++++- clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 3 +- clippy_dev/src/setup/toolchain.rs | 2 +- clippy_dev/src/sync.rs | 2 +- clippy_dev/src/update_lints.rs | 179 +++------ clippy_dev/src/utils.rs | 8 +- clippy_lints/Cargo.toml | 9 +- .../src/arbitrary_source_item_ordering.rs | 85 ++-- clippy_lints/src/as_conversions.rs | 22 +- clippy_lints/src/assigning_clones.rs | 6 +- .../attrs/blanket_clippy_restriction_lints.rs | 23 +- clippy_lints/src/attrs/deprecated_semver.rs | 8 +- .../src/attrs/duplicated_attributes.rs | 5 +- clippy_lints/src/attrs/mod.rs | 86 +++- clippy_lints/src/attrs/repr_attributes.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 130 +++--- clippy_lints/src/await_holding_invalid.rs | 16 +- clippy_lints/src/bool_to_int_with_if.rs | 29 +- clippy_lints/src/booleans.rs | 34 +- clippy_lints/src/borrow_deref_ref.rs | 13 +- clippy_lints/src/casts/borrow_as_ptr.rs | 33 +- .../src/casts/cast_abs_to_unsigned.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- .../src/casts/cast_possible_truncation.rs | 10 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 19 +- .../src/casts/cast_slice_different_sizes.rs | 65 ++- clippy_lints/src/casts/manual_dangling_ptr.rs | 82 ++++ clippy_lints/src/casts/mod.rs | 37 +- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/casts/ptr_cast_constness.rs | 7 +- clippy_lints/src/casts/unnecessary_cast.rs | 10 +- clippy_lints/src/checked_conversions.rs | 8 +- clippy_lints/src/cognitive_complexity.rs | 8 +- clippy_lints/src/collapsible_if.rs | 221 +++++++---- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 10 +- clippy_lints/src/declare_clippy_lint.rs | 13 - clippy_lints/src/declared_lints.rs | 39 +- .../src/default_constructed_unit_structs.rs | 24 +- clippy_lints/src/deprecated_lints.rs | 2 + clippy_lints/src/dereference.rs | 105 +++-- clippy_lints/src/derivable_impls.rs | 24 +- clippy_lints/src/derive.rs | 20 +- clippy_lints/src/disallowed_macros.rs | 10 +- clippy_lints/src/disallowed_methods.rs | 23 +- clippy_lints/src/disallowed_types.rs | 34 +- clippy_lints/src/doc/markdown.rs | 26 +- clippy_lints/src/doc/missing_headers.rs | 51 ++- clippy_lints/src/doc/mod.rs | 136 ++----- clippy_lints/src/doc/needless_doctest_main.rs | 5 +- clippy_lints/src/drop_forget_ref.rs | 8 +- clippy_lints/src/empty_line_after.rs | 23 +- clippy_lints/src/empty_with_brackets.rs | 235 ++++++++--- clippy_lints/src/entry.rs | 33 +- clippy_lints/src/enum_clike.rs | 8 +- clippy_lints/src/escape.rs | 46 +-- clippy_lints/src/fallible_impl_from.rs | 8 +- clippy_lints/src/floating_point_arithmetic.rs | 170 ++++---- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 4 +- clippy_lints/src/format_impl.rs | 16 +- clippy_lints/src/formatting.rs | 41 +- clippy_lints/src/from_str_radix_10.rs | 2 +- .../src/functions/misnamed_getters.rs | 17 +- .../src/functions/renamed_function_params.rs | 4 +- .../src/functions/too_many_arguments.rs | 18 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_return.rs | 30 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/implied_bounds_in_impls.rs | 4 +- .../src/inconsistent_struct_constructor.rs | 6 +- clippy_lints/src/indexing_slicing.rs | 45 +-- clippy_lints/src/infinite_iter.rs | 11 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/int_plus_one.rs | 24 +- .../src/invalid_upcast_comparisons.rs | 84 ++-- clippy_lints/src/item_name_repetitions.rs | 116 +++--- clippy_lints/src/len_zero.rs | 85 ++-- clippy_lints/src/lib.rs | 69 +--- clippy_lints/src/lifetimes.rs | 37 +- clippy_lints/src/literal_representation.rs | 11 +- .../literal_string_with_formatting_args.rs | 9 +- .../src/loops/char_indices_as_byte_indices.rs | 141 +++++++ clippy_lints/src/loops/explicit_iter_loop.rs | 16 +- clippy_lints/src/loops/for_kv_map.rs | 74 ++-- clippy_lints/src/loops/manual_find.rs | 2 + clippy_lints/src/loops/manual_memcpy.rs | 131 +++--- .../src/loops/manual_while_let_some.rs | 16 +- clippy_lints/src/loops/mod.rs | 46 +++ clippy_lints/src/loops/mut_range_bound.rs | 16 +- clippy_lints/src/loops/needless_range_loop.rs | 287 +++++++------- clippy_lints/src/loops/never_loop.rs | 8 +- clippy_lints/src/loops/utils.rs | 10 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 17 +- clippy_lints/src/manual_abs_diff.rs | 152 +++++++ clippy_lints/src/manual_assert.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_div_ceil.rs | 11 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/manual_is_power_of_two.rs | 198 ++++----- clippy_lints/src/manual_option_as_slice.rs | 2 +- clippy_lints/src/manual_retain.rs | 35 +- clippy_lints/src/manual_rotate.rs | 2 +- clippy_lints/src/manual_string_new.rs | 15 +- clippy_lints/src/manual_unwrap_or_default.rs | 212 ---------- clippy_lints/src/map_unit_fn.rs | 8 +- clippy_lints/src/matches/collapsible_match.rs | 4 +- clippy_lints/src/matches/manual_filter.rs | 20 +- clippy_lints/src/matches/manual_ok_err.rs | 4 +- clippy_lints/src/matches/manual_unwrap_or.rs | 306 +++++++++----- .../src/matches/match_like_matches.rs | 25 +- .../src/matches/match_on_vec_items.rs | 50 --- .../src/matches/match_single_binding.rs | 59 ++- .../src/matches/match_str_case_mismatch.rs | 8 +- clippy_lints/src/matches/match_wild_enum.rs | 18 +- .../src/matches/match_wild_err_arm.rs | 11 +- clippy_lints/src/matches/mod.rs | 51 ++- clippy_lints/src/matches/needless_match.rs | 8 +- clippy_lints/src/matches/overlapping_arms.rs | 22 +- .../src/matches/redundant_pattern_match.rs | 22 +- .../matches/significant_drop_in_scrutinee.rs | 9 +- clippy_lints/src/matches/single_match.rs | 17 +- clippy_lints/src/matches/wild_in_or_pats.rs | 22 +- clippy_lints/src/mem_replace.rs | 16 +- .../src/methods/bind_instead_of_map.rs | 8 +- ...se_sensitive_file_extension_comparisons.rs | 24 +- clippy_lints/src/methods/clone_on_copy.rs | 8 +- .../src/methods/double_ended_iterator_last.rs | 7 +- clippy_lints/src/methods/expect_fun_call.rs | 9 +- clippy_lints/src/methods/filter_map.rs | 31 +- .../src/methods/filter_map_bool_then.rs | 76 +++- .../methods/from_iter_instead_of_collect.rs | 97 +++-- clippy_lints/src/methods/is_empty.rs | 16 +- .../src/methods/iter_cloned_collect.rs | 10 +- clippy_lints/src/methods/iter_filter.rs | 8 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- .../src/methods/iterator_step_by_zero.rs | 18 +- .../methods/manual_saturating_arithmetic.rs | 24 +- clippy_lints/src/methods/manual_str_repeat.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 36 +- .../map_with_unused_argument_over_ranges.rs | 2 +- clippy_lints/src/methods/mod.rs | 94 ++++- clippy_lints/src/methods/needless_collect.rs | 36 +- .../src/methods/needless_option_take.rs | 49 +-- .../src/methods/obfuscated_if_else.rs | 18 +- clippy_lints/src/methods/or_fun_call.rs | 11 +- clippy_lints/src/methods/seek_from_current.rs | 44 +- .../seek_to_start_instead_of_rewind.rs | 6 +- clippy_lints/src/methods/str_splitn.rs | 15 +- clippy_lints/src/methods/suspicious_map.rs | 8 +- .../src/methods/swap_with_temporary.rs | 125 ++++++ .../src/methods/unnecessary_filter_map.rs | 26 +- .../src/methods/unnecessary_lazy_eval.rs | 99 ++--- .../src/methods/unnecessary_map_or.rs | 8 +- clippy_lints/src/methods/utils.rs | 3 + .../src/misc_early/builtin_type_shadow.rs | 18 +- .../src/misc_early/redundant_pattern.rs | 30 +- .../misc_early/unneeded_wildcard_pattern.rs | 46 +-- .../src/mismatching_type_param_order.rs | 8 +- .../src/missing_asserts_for_indexing.rs | 79 ++-- clippy_lints/src/missing_const_for_fn.rs | 15 +- clippy_lints/src/missing_fields_in_debug.rs | 9 +- clippy_lints/src/missing_inline.rs | 13 +- .../src/mixed_read_write_in_expression.rs | 46 +-- clippy_lints/src/module_style.rs | 32 +- .../src/multiple_unsafe_ops_per_block.rs | 5 +- clippy_lints/src/mut_key.rs | 8 +- clippy_lints/src/mut_mut.rs | 20 +- clippy_lints/src/mutable_debug_assertion.rs | 11 +- clippy_lints/src/mutex_atomic.rs | 24 +- clippy_lints/src/needless_bool.rs | 10 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 65 ++- clippy_lints/src/needless_pass_by_value.rs | 71 ++-- clippy_lints/src/needless_update.rs | 22 +- clippy_lints/src/neg_multiply.rs | 32 +- clippy_lints/src/new_without_default.rs | 8 +- clippy_lints/src/no_effect.rs | 31 +- clippy_lints/src/non_canonical_impls.rs | 118 +++--- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/non_std_lazy_statics.rs | 6 +- clippy_lints/src/non_zero_suggestions.rs | 7 +- clippy_lints/src/operators/cmp_owned.rs | 2 +- .../operators/float_equality_without_abs.rs | 2 +- clippy_lints/src/operators/identity_op.rs | 2 +- clippy_lints/src/operators/modulo_one.rs | 18 +- .../src/operators/numeric_arithmetic.rs | 16 +- clippy_lints/src/operators/op_ref.rs | 19 +- .../src/operators/verbose_bit_mask.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 15 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/partialeq_to_none.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 32 +- clippy_lints/src/pathbuf_init_then_push.rs | 19 +- clippy_lints/src/pattern_type_mismatch.rs | 21 +- clippy_lints/src/ptr.rs | 75 +++- clippy_lints/src/ptr_offset_with_cast.rs | 24 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/ranges.rs | 40 +- clippy_lints/src/rc_clone_in_vec_init.rs | 6 +- clippy_lints/src/redundant_async_block.rs | 26 +- clippy_lints/src/redundant_clone.rs | 69 +++- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 11 +- clippy_lints/src/redundant_slicing.rs | 33 +- clippy_lints/src/redundant_test_prefix.rs | 161 ++++++++ clippy_lints/src/regex.rs | 8 +- clippy_lints/src/same_name_method.rs | 3 +- clippy_lints/src/serde_api.rs | 40 +- clippy_lints/src/set_contains_or_insert.rs | 8 +- clippy_lints/src/shadow.rs | 25 +- .../src/significant_drop_tightening.rs | 32 +- .../src/single_char_lifetime_names.rs | 27 +- .../src/single_component_path_imports.rs | 22 +- clippy_lints/src/strings.rs | 16 +- clippy_lints/src/suspicious_trait_impl.rs | 44 +- clippy_lints/src/swap.rs | 13 +- clippy_lints/src/trait_bounds.rs | 23 +- .../src/transmute/transmute_float_to_int.rs | 2 +- .../src/transmute/transmute_ptr_to_ptr.rs | 4 +- .../src/transmute/transmute_ptr_to_ref.rs | 4 +- clippy_lints/src/types/mod.rs | 36 +- clippy_lints/src/unconditional_recursion.rs | 34 +- clippy_lints/src/unicode.rs | 8 +- clippy_lints/src/unnecessary_wraps.rs | 10 +- clippy_lints/src/unnested_or_patterns.rs | 21 +- clippy_lints/src/unused_io_amount.rs | 17 +- clippy_lints/src/unwrap.rs | 8 +- clippy_lints/src/useless_conversion.rs | 58 +-- clippy_lints/src/utils/internal_lints.rs | 11 - .../interning_defined_symbol.rs | 241 ----------- .../internal_lints/slow_symbol_comparisons.rs | 74 ---- .../unsorted_clippy_utils_paths.rs | 49 --- clippy_lints/src/utils/mod.rs | 3 - clippy_lints/src/wildcard_imports.rs | 6 +- clippy_lints/src/zero_sized_map_values.rs | 8 +- clippy_lints/src/zombie_processes.rs | 2 +- clippy_lints_internal/Cargo.toml | 14 + .../src}/almost_standard_lint_formulation.rs | 12 +- .../src}/collapsible_calls.rs | 10 +- .../src/interning_literals.rs | 102 +++++ .../src}/invalid_paths.rs | 40 +- clippy_lints_internal/src/lib.rs | 74 ++++ .../src}/lint_without_lint_pass.rs | 51 ++- .../src}/msrv_attr_impl.rs | 11 +- .../src}/outer_expn_data_pass.rs | 10 +- .../src}/produce_ice.rs | 12 +- .../src}/unnecessary_def_path.rs | 18 +- .../src/unsorted_clippy_utils_paths.rs | 54 +++ clippy_utils/Cargo.toml | 2 +- clippy_utils/README.md | 2 +- clippy_utils/src/ast_utils/mod.rs | 28 +- clippy_utils/src/consts.rs | 26 +- clippy_utils/src/diagnostics.rs | 20 +- clippy_utils/src/higher.rs | 17 +- clippy_utils/src/hir_utils.rs | 266 ++++++------- clippy_utils/src/lib.rs | 233 ++++++----- clippy_utils/src/mir/mod.rs | 2 +- clippy_utils/src/msrvs.rs | 13 +- clippy_utils/src/paths.rs | 2 + clippy_utils/src/source.rs | 43 +- clippy_utils/src/str_utils.rs | 4 +- clippy_utils/src/sugg.rs | 17 +- clippy_utils/src/sym.rs | 54 ++- clippy_utils/src/sym_helper.rs | 7 - clippy_utils/src/ty/mod.rs | 78 +++- clippy_utils/src/usage.rs | 8 +- clippy_utils/src/visitors.rs | 8 +- lintcheck/ci-config/clippy.toml | 7 + lintcheck/src/main.rs | 41 +- lintcheck/src/recursive.rs | 2 +- rust-toolchain => rust-toolchain.toml | 2 +- rustc_tools_util/src/lib.rs | 2 +- src/driver.rs | 32 +- tests/clippy.toml | 1 + tests/compile-test.rs | 26 +- tests/dogfood.rs | 7 +- tests/ui-internal/auxiliary/paths.rs | 2 + .../check_clippy_version_attribute.rs | 13 +- .../check_clippy_version_attribute.stderr | 13 +- tests/ui-internal/check_formulation.rs | 3 +- tests/ui-internal/check_formulation.stderr | 11 +- .../collapsible_span_lint_calls.fixed | 2 +- .../collapsible_span_lint_calls.rs | 2 +- .../collapsible_span_lint_calls.stderr | 5 +- tests/ui-internal/custom_ice_message.rs | 2 +- tests/ui-internal/custom_ice_message.stderr | 2 +- tests/ui-internal/default_lint.rs | 2 +- tests/ui-internal/default_lint.stderr | 5 +- tests/ui-internal/disallow_span_lint.rs | 1 + tests/ui-internal/disallow_span_lint.stderr | 11 +- .../interning_defined_symbol.fixed | 40 -- tests/ui-internal/interning_defined_symbol.rs | 40 -- .../interning_defined_symbol.stderr | 33 -- tests/ui-internal/interning_literals.fixed | 31 ++ tests/ui-internal/interning_literals.rs | 31 ++ tests/ui-internal/interning_literals.stderr | 64 +++ .../interning_literals_unfixable.rs | 16 + .../interning_literals_unfixable.stderr | 40 ++ .../ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- .../ui-internal/invalid_msrv_attr_impl.stderr | 5 +- tests/ui-internal/invalid_paths.rs | 2 +- tests/ui-internal/invalid_paths.stderr | 7 +- tests/ui-internal/lint_without_lint_pass.rs | 2 +- .../ui-internal/lint_without_lint_pass.stderr | 5 +- tests/ui-internal/outer_expn_data.fixed | 2 +- tests/ui-internal/outer_expn_data.rs | 2 +- tests/ui-internal/outer_expn_data.stderr | 5 +- .../ui-internal/slow_symbol_comparisons.fixed | 24 -- tests/ui-internal/slow_symbol_comparisons.rs | 24 -- .../slow_symbol_comparisons.stderr | 23 -- tests/ui-internal/unnecessary_def_path.fixed | 2 +- tests/ui-internal/unnecessary_def_path.rs | 2 +- tests/ui-internal/unnecessary_def_path.stderr | 5 +- .../unnecessary_def_path_hardcoded_path.rs | 2 +- ...unnecessary_def_path_hardcoded_path.stderr | 7 +- .../ui-internal/unnecessary_symbol_str.fixed | 26 -- tests/ui-internal/unnecessary_symbol_str.rs | 26 -- .../ui-internal/unnecessary_symbol_str.stderr | 39 -- .../ordering_good.rs | 1 + .../selective_ordering.default.stderr | 6 +- .../selective_ordering.ord_in_2.stderr | 12 +- .../selective_ordering.ord_in_3.stderr | 6 +- .../selective_ordering.ord_within.stderr | 30 +- .../selective_ordering.rs | 8 + .../await_holding_invalid_type.stderr | 9 +- tests/ui-toml/collapsible_if/clippy.toml | 1 + .../collapsible_if/collapsible_if.fixed | 34 ++ .../ui-toml/collapsible_if/collapsible_if.rs | 38 ++ .../collapsible_if/collapsible_if.stderr | 80 ++++ .../collapsible_if_let_chains.fixed | 25 ++ .../collapsible_if_let_chains.rs | 28 ++ .../collapsible_if_let_chains.stderr | 64 +++ .../macro_metavars_in_unsafe/default/test.rs | 16 + .../index_refutable_slice.fixed | 1 + .../index_refutable_slice.rs | 1 + .../index_refutable_slice.stderr | 4 +- .../strict_non_send_fields_in_send_ty/test.rs | 2 +- .../clippy.toml | 2 +- tests/ui-toml/toml_invalid_path/clippy.toml | 14 + .../toml_invalid_path/conf_invalid_path.rs | 5 + .../conf_invalid_path.stderr | 23 ++ .../toml_unknown_key/conf_unknown_key.stderr | 15 +- .../wildcard_imports/wildcard_imports.fixed | 2 +- .../wildcard_imports/wildcard_imports.rs | 2 +- .../wildcard_imports/wildcard_imports.stderr | 6 +- tests/ui/asm_syntax_not_x86.rs | 8 +- tests/ui/asm_syntax_x86.rs | 34 +- tests/ui/asm_syntax_x86.stderr | 36 +- tests/ui/author/if.rs | 2 +- tests/ui/author/macro_in_closure.rs | 2 + tests/ui/author/macro_in_loop.rs | 1 + tests/ui/auxiliary/proc_macros.rs | 12 +- tests/ui/blocks_in_conditions.fixed | 29 +- tests/ui/blocks_in_conditions.rs | 29 +- tests/ui/blocks_in_conditions.stderr | 27 +- tests/ui/blocks_in_conditions_2021.fixed | 25 ++ tests/ui/blocks_in_conditions_2021.rs | 25 ++ tests/ui/blocks_in_conditions_2021.stderr | 23 ++ tests/ui/bool_to_int_with_if.fixed | 24 ++ tests/ui/bool_to_int_with_if.rs | 24 ++ tests/ui/bool_to_int_with_if.stderr | 18 +- tests/ui/borrow_as_ptr.fixed | 18 + tests/ui/borrow_as_ptr.rs | 18 + tests/ui/borrow_as_ptr.stderr | 35 +- tests/ui/borrow_deref_ref.fixed | 43 ++ tests/ui/borrow_deref_ref.rs | 43 ++ tests/ui/borrow_deref_ref.stderr | 8 +- tests/ui/box_collection.rs | 1 - tests/ui/box_collection.stderr | 18 +- ...sensitive_file_extension_comparisons.fixed | 21 +- ...se_sensitive_file_extension_comparisons.rs | 7 +- ...ensitive_file_extension_comparisons.stderr | 134 ++++--- tests/ui/char_indices_as_byte_indices.fixed | 65 +++ tests/ui/char_indices_as_byte_indices.rs | 65 +++ tests/ui/char_indices_as_byte_indices.stderr | 130 ++++++ .../checked_unwrap/simple_conditionals.stderr | 3 +- tests/ui/cmp_owned/with_suggestion.fixed | 9 + tests/ui/cmp_owned/with_suggestion.rs | 9 + tests/ui/cmp_owned/with_suggestion.stderr | 14 +- tests/ui/cognitive_complexity.rs | 28 +- tests/ui/cognitive_complexity.stderr | 58 ++- tests/ui/collapsible_if.fixed | 116 +++--- tests/ui/collapsible_if.rs | 62 ++- tests/ui/collapsible_if.stderr | 109 +++-- tests/ui/collapsible_if_let_chains.fixed | 29 ++ tests/ui/collapsible_if_let_chains.rs | 32 ++ tests/ui/collapsible_if_let_chains.stderr | 58 +++ tests/ui/collapsible_match.rs | 12 + tests/ui/crashes/enum-glob-import-crate.rs | 3 - tests/ui/crashes/ice-11230.fixed | 4 +- tests/ui/crashes/ice-11230.rs | 2 +- tests/ui/crashes/ice-11230.stderr | 11 +- tests/ui/crashes/ice-13544-original.rs | 45 +++ tests/ui/crashes/ice-13544-reduced.rs | 16 + tests/ui/crashes/ice-1588.rs | 2 +- tests/ui/crashes/ice-1969.rs | 2 - tests/ui/crashes/ice-3462.rs | 4 +- tests/ui/crashes/ice-700.rs | 2 - tests/ui/crashes/ice-7012.rs | 2 +- tests/ui/crashes/ice-7423.rs | 2 +- tests/ui/crashes/ice_exact_size.rs | 3 - tests/ui/crashes/needless_borrow_fp.rs | 1 - tests/ui/crate_level_checks/no_std_swap.fixed | 1 - tests/ui/crate_level_checks/no_std_swap.rs | 1 - .../ui/crate_level_checks/no_std_swap.stderr | 5 +- tests/ui/dbg_macro/dbg_macro.fixed | 7 +- tests/ui/dbg_macro/dbg_macro.rs | 7 +- tests/ui/dbg_macro/dbg_macro.stderr | 38 +- tests/ui/def_id_nocore.rs | 2 +- .../ui/default_constructed_unit_structs.fixed | 14 + tests/ui/default_constructed_unit_structs.rs | 14 + .../default_constructed_unit_structs.stderr | 50 ++- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +- tests/ui/derive.rs | 17 + tests/ui/derive.stderr | 20 +- tests/ui/doc/doc-fixable.fixed | 3 +- tests/ui/doc/doc-fixable.rs | 3 +- tests/ui/doc/doc-fixable.stderr | 68 ++-- tests/ui/doc_unsafe.rs | 2 +- tests/ui/double_ended_iterator_last.fixed | 32 +- tests/ui/double_ended_iterator_last.rs | 28 +- tests/ui/double_ended_iterator_last.stderr | 52 +-- .../double_ended_iterator_last_unfixable.rs | 5 +- ...ouble_ended_iterator_last_unfixable.stderr | 24 +- tests/ui/eager_transmute.fixed | 6 +- tests/ui/eager_transmute.rs | 6 +- tests/ui/eager_transmute.stderr | 16 +- tests/ui/empty_docs.rs | 2 +- .../empty_enum_variants_with_brackets.fixed | 78 +++- tests/ui/empty_enum_variants_with_brackets.rs | 78 +++- .../empty_enum_variants_with_brackets.stderr | 68 +++- .../ui/empty_line_after/doc_comments.1.fixed | 5 + .../ui/empty_line_after/doc_comments.2.fixed | 6 + tests/ui/empty_line_after/doc_comments.rs | 6 + tests/ui/empty_line_after/doc_comments.stderr | 28 +- tests/ui/entry.fixed | 22 + tests/ui/entry.rs | 22 + tests/ui/explicit_auto_deref.fixed | 2 +- tests/ui/explicit_auto_deref.rs | 2 +- tests/ui/filter_map_bool_then_unfixable.rs | 63 +++ .../ui/filter_map_bool_then_unfixable.stderr | 65 +++ tests/ui/filter_map_next.rs | 2 +- tests/ui/filter_map_next_fixable.fixed | 3 +- tests/ui/filter_map_next_fixable.rs | 3 +- tests/ui/filter_map_next_fixable.stderr | 4 +- tests/ui/find_map.rs | 1 - tests/ui/fn_params_excessive_bools.rs | 10 +- tests/ui/formatting.rs | 3 - tests/ui/formatting.stderr | 15 +- tests/ui/from_iter_instead_of_collect.fixed | 43 ++ tests/ui/from_iter_instead_of_collect.rs | 43 ++ tests/ui/from_iter_instead_of_collect.stderr | 56 ++- tests/ui/functions.rs | 2 - tests/ui/functions.stderr | 35 +- tests/ui/if_not_else.fixed | 1 - tests/ui/if_not_else.rs | 1 - tests/ui/if_not_else.stderr | 12 +- tests/ui/ignore_without_reason.rs | 14 + tests/ui/ignore_without_reason.stderr | 12 + tests/ui/implicit_return.fixed | 43 ++ tests/ui/implicit_return.rs | 43 ++ tests/ui/implicit_return.stderr | 90 ++++- .../items_after_test_module/root_module.fixed | 1 - .../ui/items_after_test_module/root_module.rs | 1 - .../root_module.stderr | 2 +- tests/ui/iter_cloned_collect.fixed | 27 ++ tests/ui/iter_cloned_collect.rs | 27 ++ tests/ui/iter_cloned_collect.stderr | 8 +- tests/ui/iter_kv_map.fixed | 15 + tests/ui/iter_kv_map.rs | 15 + tests/ui/iter_kv_map.stderr | 8 +- tests/ui/iter_overeager_cloned.fixed | 2 +- tests/ui/iter_overeager_cloned.rs | 2 +- tests/ui/iter_overeager_cloned.stderr | 6 +- tests/ui/large_futures.fixed | 9 +- tests/ui/large_futures.rs | 9 +- tests/ui/large_futures.stderr | 16 +- tests/ui/len_without_is_empty_expect.rs | 28 ++ tests/ui/len_without_is_empty_expect.stderr | 11 + tests/ui/manual_abs_diff.fixed | 106 +++++ tests/ui/manual_abs_diff.rs | 116 ++++++ tests/ui/manual_abs_diff.stderr | 83 ++++ tests/ui/manual_async_fn.fixed | 6 +- tests/ui/manual_async_fn.rs | 6 +- tests/ui/manual_dangling_ptr.fixed | 44 ++ tests/ui/manual_dangling_ptr.rs | 44 ++ tests/ui/manual_dangling_ptr.stderr | 65 +++ tests/ui/manual_find.rs | 28 ++ tests/ui/manual_ignore_case_cmp.fixed | 10 +- tests/ui/manual_ignore_case_cmp.rs | 10 +- tests/ui/manual_ignore_case_cmp.stderr | 375 +++++++++--------- tests/ui/manual_inspect.fixed | 13 +- tests/ui/manual_inspect.rs | 11 +- tests/ui/manual_inspect.stderr | 17 +- tests/ui/manual_is_power_of_two.fixed | 34 ++ tests/ui/manual_is_power_of_two.rs | 34 ++ tests/ui/manual_is_power_of_two.stderr | 32 +- tests/ui/manual_map_option.rs | 2 +- tests/ui/manual_map_option.stderr | 2 +- tests/ui/manual_map_option_2.fixed | 6 +- tests/ui/manual_map_option_2.rs | 6 +- tests/ui/manual_ok_err.fixed | 5 + tests/ui/manual_ok_err.rs | 5 + tests/ui/manual_ok_err.stderr | 2 +- tests/ui/manual_retain.fixed | 10 +- tests/ui/manual_retain.rs | 10 +- tests/ui/manual_retain.stderr | 16 +- tests/ui/manual_strip_fixable.fixed | 1 + tests/ui/manual_strip_fixable.rs | 1 + tests/ui/manual_strip_fixable.stderr | 8 +- tests/ui/manual_unwrap_or.fixed | 30 +- tests/ui/manual_unwrap_or.rs | 15 +- tests/ui/manual_unwrap_or.stderr | 39 +- tests/ui/manual_unwrap_or_default.fixed | 17 +- tests/ui/manual_unwrap_or_default.rs | 28 +- tests/ui/manual_unwrap_or_default.stderr | 27 +- tests/ui/map_flatten_fixable.fixed | 13 +- tests/ui/map_flatten_fixable.rs | 13 +- tests/ui/map_flatten_fixable.stderr | 18 +- tests/ui/match_on_vec_items.rs | 161 -------- tests/ui/match_on_vec_items.stderr | 53 --- tests/ui/match_single_binding.fixed | 17 + tests/ui/match_single_binding.rs | 20 + tests/ui/match_single_binding.stderr | 44 +- tests/ui/methods.rs | 4 +- tests/ui/methods.stderr | 4 +- tests/ui/min_max.rs | 1 - tests/ui/min_max.stderr | 29 +- tests/ui/misnamed_getters.fixed | 24 +- tests/ui/misnamed_getters.rs | 24 +- tests/ui/misnamed_getters.stderr | 32 +- tests/ui/misnamed_getters_2021.fixed | 24 ++ tests/ui/misnamed_getters_2021.rs | 24 ++ tests/ui/misnamed_getters_2021.stderr | 16 + tests/ui/missing_asserts_for_indexing.fixed | 27 ++ tests/ui/missing_asserts_for_indexing.rs | 27 ++ tests/ui/missing_asserts_for_indexing.stderr | 54 ++- .../missing_asserts_for_indexing_unfixable.rs | 13 + ...sing_asserts_for_indexing_unfixable.stderr | 45 ++- .../missing_const_for_fn/could_be_const.fixed | 4 +- .../ui/missing_const_for_fn/could_be_const.rs | 4 +- .../could_be_const.stderr | 6 +- tests/ui/missing_panics_doc.rs | 39 ++ tests/ui/missing_panics_doc.stderr | 62 ++- tests/ui/missing_transmute_annotations.fixed | 50 +-- tests/ui/missing_transmute_annotations.rs | 50 +-- tests/ui/missing_transmute_annotations.stderr | 56 +-- tests/ui/must_use_candidates.fixed | 8 +- tests/ui/must_use_candidates.rs | 8 +- tests/ui/mut_from_ref.rs | 34 +- tests/ui/mut_from_ref.stderr | 50 ++- tests/ui/mutex_atomic.rs | 1 - tests/ui/mutex_atomic.stderr | 22 +- tests/ui/needless_borrowed_ref.fixed | 2 +- tests/ui/needless_borrowed_ref.rs | 2 +- tests/ui/needless_collect.fixed | 84 ++++ tests/ui/needless_collect.rs | 84 ++++ tests/ui/needless_lifetimes.fixed | 7 + tests/ui/needless_lifetimes.rs | 7 + tests/ui/needless_pass_by_ref_mut.rs | 5 +- tests/ui/needless_pass_by_ref_mut.stderr | 68 ++-- tests/ui/needless_pass_by_ref_mut_2021.rs | 12 + tests/ui/neg_multiply.fixed | 29 ++ tests/ui/neg_multiply.rs | 29 ++ tests/ui/neg_multiply.stderr | 50 ++- tests/ui/no_mangle_with_rust_abi.rs | 2 +- tests/ui/non_canonical_partial_ord_impl.fixed | 33 ++ tests/ui/non_canonical_partial_ord_impl.rs | 35 ++ .../ui/non_canonical_partial_ord_impl.stderr | 15 +- tests/ui/non_expressive_names.rs | 3 +- tests/ui/non_expressive_names.stderr | 12 +- tests/ui/non_send_fields_in_send_ty.rs | 4 +- .../non_std_lazy_static_fixable.fixed | 14 +- .../non_std_lazy_static_fixable.rs | 14 +- .../non_std_lazy_static_fixable.stderr | 14 +- .../non_std_lazy_static_unfixable.rs | 12 +- .../non_std_lazy_static_unfixable.stderr | 12 +- tests/ui/nonminimal_bool.rs | 20 + tests/ui/nonminimal_bool.stderr | 10 +- tests/ui/obfuscated_if_else.fixed | 12 + tests/ui/obfuscated_if_else.rs | 12 + tests/ui/obfuscated_if_else.stderr | 42 +- tests/ui/op_ref.fixed | 12 + tests/ui/op_ref.rs | 12 + tests/ui/option_if_let_else.fixed | 14 + tests/ui/option_if_let_else.rs | 14 + tests/ui/or_fun_call.fixed | 18 +- tests/ui/or_fun_call.rs | 18 +- tests/ui/or_fun_call.stderr | 40 +- tests/ui/pattern_type_mismatch/mutability.rs | 2 +- .../pattern_alternatives.rs | 1 - .../pattern_alternatives.stderr | 6 +- .../pattern_type_mismatch/pattern_structs.rs | 1 - .../pattern_structs.stderr | 16 +- .../pattern_type_mismatch/pattern_tuples.rs | 1 - .../pattern_tuples.stderr | 20 +- tests/ui/pattern_type_mismatch/syntax.rs | 7 +- tests/ui/pattern_type_mismatch/syntax.stderr | 18 +- tests/ui/patterns.fixed | 2 - tests/ui/patterns.rs | 2 - tests/ui/patterns.stderr | 6 +- tests/ui/pointers_in_nomem_asm_block.rs | 38 +- tests/ui/pointers_in_nomem_asm_block.stderr | 22 +- tests/ui/ptr_cast_constness.fixed | 18 +- tests/ui/ptr_cast_constness.rs | 18 +- tests/ui/ptr_cast_constness.stderr | 42 +- tests/ui/ptr_eq.fixed | 7 + tests/ui/ptr_eq.rs | 7 + tests/ui/ptr_eq.stderr | 26 +- tests/ui/question_mark.fixed | 8 + tests/ui/question_mark.rs | 10 + tests/ui/question_mark.stderr | 68 ++-- tests/ui/redundant_allocation.rs | 1 - tests/ui/redundant_allocation.stderr | 40 +- tests/ui/redundant_allocation_fixable.fixed | 4 +- tests/ui/redundant_allocation_fixable.rs | 4 +- tests/ui/redundant_allocation_fixable.stderr | 24 +- tests/ui/redundant_clone.fixed | 32 ++ tests/ui/redundant_clone.rs | 32 ++ .../redundant_pattern_matching_ipaddr.fixed | 3 +- tests/ui/redundant_pattern_matching_ipaddr.rs | 3 +- .../redundant_pattern_matching_ipaddr.stderr | 40 +- .../redundant_pattern_matching_option.fixed | 4 +- tests/ui/redundant_pattern_matching_option.rs | 4 +- .../redundant_pattern_matching_option.stderr | 62 +-- .../ui/redundant_pattern_matching_poll.fixed | 2 - tests/ui/redundant_pattern_matching_poll.rs | 2 - .../ui/redundant_pattern_matching_poll.stderr | 40 +- .../redundant_pattern_matching_result.fixed | 3 +- tests/ui/redundant_pattern_matching_result.rs | 3 +- .../redundant_pattern_matching_result.stderr | 56 +-- tests/ui/redundant_pub_crate.fixed | 8 + tests/ui/redundant_pub_crate.rs | 8 + tests/ui/redundant_pub_crate.stderr | 18 +- tests/ui/redundant_test_prefix.fixed | 158 ++++++++ tests/ui/redundant_test_prefix.rs | 158 ++++++++ tests/ui/redundant_test_prefix.stderr | 119 ++++++ tests/ui/redundant_test_prefix_noautofix.rs | 288 ++++++++++++++ .../ui/redundant_test_prefix_noautofix.stderr | 241 +++++++++++ .../ref_option/ref_option_traits.all.stderr | 8 +- .../ref_option_traits.private.stderr | 4 +- tests/ui/ref_option/ref_option_traits.rs | 1 - tests/ui/rename.fixed | 15 +- tests/ui/rename.rs | 15 +- tests/ui/rename.stderr | 154 +++---- tests/ui/repr_packed_without_abi.stderr | 4 +- tests/ui/result_unit_error_no_std.rs | 2 +- tests/ui/search_is_some_fixable_none.fixed | 7 +- tests/ui/search_is_some_fixable_none.rs | 9 +- tests/ui/search_is_some_fixable_none.stderr | 56 +-- .../ui/search_is_some_fixable_none_2021.fixed | 14 + tests/ui/search_is_some_fixable_none_2021.rs | 16 + .../search_is_some_fixable_none_2021.stderr | 35 ++ tests/ui/search_is_some_fixable_some.fixed | 7 +- tests/ui/search_is_some_fixable_some.rs | 9 +- tests/ui/search_is_some_fixable_some.stderr | 35 +- .../ui/search_is_some_fixable_some_2021.fixed | 11 + tests/ui/search_is_some_fixable_some_2021.rs | 11 + .../search_is_some_fixable_some_2021.stderr | 17 + tests/ui/shadow.rs | 15 + tests/ui/should_impl_trait/corner_cases.rs | 1 - tests/ui/should_impl_trait/method_list_1.rs | 1 - .../ui/should_impl_trait/method_list_1.stderr | 30 +- tests/ui/should_impl_trait/method_list_2.rs | 1 - .../ui/should_impl_trait/method_list_2.stderr | 30 +- tests/ui/single_call_fn.rs | 2 +- tests/ui/single_match.fixed | 36 ++ tests/ui/single_match.rs | 42 ++ tests/ui/single_match.stderr | 20 +- tests/ui/suspicious_doc_comments.fixed | 4 + tests/ui/suspicious_doc_comments.rs | 4 + tests/ui/swap.fixed | 5 - tests/ui/swap.rs | 5 - tests/ui/swap.stderr | 37 +- tests/ui/swap_with_temporary.fixed | 74 ++++ tests/ui/swap_with_temporary.rs | 74 ++++ tests/ui/swap_with_temporary.stderr | 100 +++++ tests/ui/swap_with_temporary_unfixable.rs | 62 +++ tests/ui/swap_with_temporary_unfixable.stderr | 125 ++++++ tests/ui/transmute.rs | 30 +- tests/ui/transmute.stderr | 120 +++--- tests/ui/transmute_null_to_fn.rs | 1 + tests/ui/transmute_null_to_fn.stderr | 12 +- tests/ui/transmute_ptr_to_ptr.fixed | 4 +- tests/ui/transmute_ptr_to_ptr.rs | 4 +- tests/ui/transmute_ptr_to_ref.fixed | 104 ++--- tests/ui/transmute_ptr_to_ref.rs | 104 ++--- tests/ui/transmute_ptr_to_ref.stderr | 120 +++--- tests/ui/transmuting_null.rs | 1 + tests/ui/transmuting_null.stderr | 6 +- tests/ui/type_complexity.rs | 3 +- tests/ui/type_complexity.stderr | 30 +- tests/ui/uninit_vec.rs | 12 +- tests/ui/uninit_vec.stderr | 49 ++- tests/ui/unnecessary_cast_unfixable.rs | 6 +- tests/ui/unnecessary_cast_unfixable.stderr | 6 +- tests/ui/unnecessary_filter_map.rs | 7 +- tests/ui/unnecessary_filter_map.stderr | 53 +-- tests/ui/unnecessary_find_map.rs | 1 - tests/ui/unnecessary_find_map.stderr | 30 +- tests/ui/unnecessary_iter_cloned.fixed | 2 +- tests/ui/unnecessary_iter_cloned.rs | 2 +- tests/ui/unnecessary_lazy_eval.fixed | 4 + tests/ui/unnecessary_lazy_eval.rs | 4 + tests/ui/unnecessary_operation.fixed | 7 +- tests/ui/unnecessary_operation.rs | 7 +- tests/ui/unnecessary_operation.stderr | 40 +- .../ui/unnecessary_os_str_debug_formatting.rs | 1 + ...unnecessary_os_str_debug_formatting.stderr | 12 +- tests/ui/unnecessary_path_debug_formatting.rs | 1 + .../unnecessary_path_debug_formatting.stderr | 18 +- tests/ui/unnecessary_to_owned.fixed | 7 +- tests/ui/unnecessary_to_owned.rs | 7 +- tests/ui/unnecessary_to_owned.stderr | 174 ++++---- tests/ui/unnested_or_patterns.fixed | 13 + tests/ui/unnested_or_patterns.rs | 13 + tests/ui/unnested_or_patterns.stderr | 38 +- tests/ui/unwrap_or.fixed | 2 +- tests/ui/unwrap_or.rs | 2 +- tests/ui/used_underscore_items.rs | 2 +- triagebot.toml | 24 ++ 746 files changed, 13925 insertions(+), 7188 deletions(-) rename rinja.toml => askama.toml (100%) create mode 100644 book/src/development/infrastructure/benchmarking.md create mode 100644 clippy_lints/src/casts/manual_dangling_ptr.rs create mode 100644 clippy_lints/src/loops/char_indices_as_byte_indices.rs create mode 100644 clippy_lints/src/manual_abs_diff.rs delete mode 100644 clippy_lints/src/manual_unwrap_or_default.rs delete mode 100644 clippy_lints/src/matches/match_on_vec_items.rs create mode 100644 clippy_lints/src/methods/swap_with_temporary.rs create mode 100644 clippy_lints/src/redundant_test_prefix.rs delete mode 100644 clippy_lints/src/utils/internal_lints.rs delete mode 100644 clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs delete mode 100644 clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs delete mode 100644 clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs create mode 100644 clippy_lints_internal/Cargo.toml rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/almost_standard_lint_formulation.rs (92%) rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/collapsible_calls.rs (97%) create mode 100644 clippy_lints_internal/src/interning_literals.rs rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/invalid_paths.rs (79%) create mode 100644 clippy_lints_internal/src/lib.rs rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/lint_without_lint_pass.rs (90%) rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/msrv_attr_impl.rs (93%) rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/outer_expn_data_pass.rs (92%) rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/produce_ice.rs (79%) rename {clippy_lints/src/utils/internal_lints => clippy_lints_internal/src}/unnecessary_def_path.rs (97%) create mode 100644 clippy_lints_internal/src/unsorted_clippy_utils_paths.rs delete mode 100644 clippy_utils/src/sym_helper.rs create mode 100644 lintcheck/ci-config/clippy.toml rename rust-toolchain => rust-toolchain.toml (85%) delete mode 100644 tests/ui-internal/interning_defined_symbol.fixed delete mode 100644 tests/ui-internal/interning_defined_symbol.rs delete mode 100644 tests/ui-internal/interning_defined_symbol.stderr create mode 100644 tests/ui-internal/interning_literals.fixed create mode 100644 tests/ui-internal/interning_literals.rs create mode 100644 tests/ui-internal/interning_literals.stderr create mode 100644 tests/ui-internal/interning_literals_unfixable.rs create mode 100644 tests/ui-internal/interning_literals_unfixable.stderr delete mode 100644 tests/ui-internal/slow_symbol_comparisons.fixed delete mode 100644 tests/ui-internal/slow_symbol_comparisons.rs delete mode 100644 tests/ui-internal/slow_symbol_comparisons.stderr delete mode 100644 tests/ui-internal/unnecessary_symbol_str.fixed delete mode 100644 tests/ui-internal/unnecessary_symbol_str.rs delete mode 100644 tests/ui-internal/unnecessary_symbol_str.stderr create mode 100644 tests/ui-toml/collapsible_if/clippy.toml create mode 100644 tests/ui-toml/collapsible_if/collapsible_if.fixed create mode 100644 tests/ui-toml/collapsible_if/collapsible_if.rs create mode 100644 tests/ui-toml/collapsible_if/collapsible_if.stderr create mode 100644 tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed create mode 100644 tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs create mode 100644 tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr create mode 100644 tests/ui-toml/toml_invalid_path/clippy.toml create mode 100644 tests/ui-toml/toml_invalid_path/conf_invalid_path.rs create mode 100644 tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr create mode 100644 tests/ui/blocks_in_conditions_2021.fixed create mode 100644 tests/ui/blocks_in_conditions_2021.rs create mode 100644 tests/ui/blocks_in_conditions_2021.stderr create mode 100644 tests/ui/char_indices_as_byte_indices.fixed create mode 100644 tests/ui/char_indices_as_byte_indices.rs create mode 100644 tests/ui/char_indices_as_byte_indices.stderr create mode 100644 tests/ui/collapsible_if_let_chains.fixed create mode 100644 tests/ui/collapsible_if_let_chains.rs create mode 100644 tests/ui/collapsible_if_let_chains.stderr create mode 100644 tests/ui/crashes/ice-13544-original.rs create mode 100644 tests/ui/crashes/ice-13544-reduced.rs create mode 100644 tests/ui/filter_map_bool_then_unfixable.rs create mode 100644 tests/ui/filter_map_bool_then_unfixable.stderr create mode 100644 tests/ui/ignore_without_reason.rs create mode 100644 tests/ui/ignore_without_reason.stderr create mode 100644 tests/ui/len_without_is_empty_expect.rs create mode 100644 tests/ui/len_without_is_empty_expect.stderr create mode 100644 tests/ui/manual_abs_diff.fixed create mode 100644 tests/ui/manual_abs_diff.rs create mode 100644 tests/ui/manual_abs_diff.stderr create mode 100644 tests/ui/manual_dangling_ptr.fixed create mode 100644 tests/ui/manual_dangling_ptr.rs create mode 100644 tests/ui/manual_dangling_ptr.stderr delete mode 100644 tests/ui/match_on_vec_items.rs delete mode 100644 tests/ui/match_on_vec_items.stderr create mode 100644 tests/ui/misnamed_getters_2021.fixed create mode 100644 tests/ui/misnamed_getters_2021.rs create mode 100644 tests/ui/misnamed_getters_2021.stderr create mode 100644 tests/ui/needless_pass_by_ref_mut_2021.rs create mode 100644 tests/ui/redundant_test_prefix.fixed create mode 100644 tests/ui/redundant_test_prefix.rs create mode 100644 tests/ui/redundant_test_prefix.stderr create mode 100644 tests/ui/redundant_test_prefix_noautofix.rs create mode 100644 tests/ui/redundant_test_prefix_noautofix.stderr create mode 100644 tests/ui/search_is_some_fixable_none_2021.fixed create mode 100644 tests/ui/search_is_some_fixable_none_2021.rs create mode 100644 tests/ui/search_is_some_fixable_none_2021.stderr create mode 100644 tests/ui/search_is_some_fixable_some_2021.fixed create mode 100644 tests/ui/search_is_some_fixable_some_2021.rs create mode 100644 tests/ui/search_is_some_fixable_some_2021.stderr create mode 100644 tests/ui/swap_with_temporary.fixed create mode 100644 tests/ui/swap_with_temporary.rs create mode 100644 tests/ui/swap_with_temporary.stderr create mode 100644 tests/ui/swap_with_temporary_unfixable.rs create mode 100644 tests/ui/swap_with_temporary_unfixable.stderr diff --git a/.github/workflows/clippy_changelog.yml b/.github/workflows/clippy_changelog.yml index a2657bfea490..1e97154bf8a3 100644 --- a/.github/workflows/clippy_changelog.yml +++ b/.github/workflows/clippy_changelog.yml @@ -24,7 +24,7 @@ jobs: - name: Check Changelog if: ${{ github.event_name == 'pull_request' }} run: | - body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR_NUMBER" | \ + body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" | \ python -c "import sys, json; print(json.load(sys.stdin)['body'])") output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g") if [ -z "$output" ]; then diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index 741e74573317..07d5a08304e8 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -66,7 +66,7 @@ jobs: run: cargo test --features internal -- --skip dogfood - name: Test clippy_lints - run: cargo test --features internal + run: cargo test working-directory: clippy_lints - name: Test clippy_utils diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index 80523d91f4fc..880ebd6e5d5c 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -42,7 +42,7 @@ jobs: run: cargo test --features internal - name: Test clippy_lints - run: cargo test --features internal + run: cargo test working-directory: clippy_lints - name: Test clippy_utils diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b42f3e7712f1..ede19c11257e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,6 +8,10 @@ on: tags: - rust-1.** +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + env: TARGET_BRANCH: 'gh-pages' SHA: '${{ github.sha }}' diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index d487c7d94985..70c805903d36 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -66,7 +66,7 @@ jobs: - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml + run: env CLIPPY_CONF_DIR="$PWD/lintcheck/ci-config" ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml - name: Upload base JSON uses: actions/upload-artifact@v4 @@ -97,7 +97,7 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml + run: env CLIPPY_CONF_DIR="$PWD/lintcheck/ci-config" ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml - name: Upload head JSON uses: actions/upload-artifact@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf4b51ff0fe..2b62c9a59aa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,68 @@ document. ## Unreleased / Beta / In Rust Nightly -[609cd310...master](https://github.com/rust-lang/rust-clippy/compare/609cd310...master) +[3e3715c3...master](https://github.com/rust-lang/rust-clippy/compare/3e3715c3...master) + +## Rust 1.86 + +Current stable, released 2025-04-03 + +[View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-12-27T15%3A11%3A38Z..2025-02-06T13%3A57%3A58Z+base%3Amaster) + +### New Lints + +* Added [`unneeded_struct_pattern`] to `style` [#13465](https://github.com/rust-lang/rust-clippy/pull/13465) +* Added [`doc_overindented_list_items`] to `style` [#13711](https://github.com/rust-lang/rust-clippy/pull/13711) +* Added [`manual_ok_err`] to `complexity` [#13740](https://github.com/rust-lang/rust-clippy/pull/13740) +* Added [`non_std_lazy_statics`] to `pedantic` [#13770](https://github.com/rust-lang/rust-clippy/pull/13770) +* Added [`manual_repeat_n`] to `style` [#13858](https://github.com/rust-lang/rust-clippy/pull/13858) +* Added [`manual_option_as_slice`] to `complexity` [#13901](https://github.com/rust-lang/rust-clippy/pull/13901) +* Added [`double_ended_iterator_last`] to `perf` [#13922](https://github.com/rust-lang/rust-clippy/pull/13922) +* Added [`useless_nonzero_new_unchecked`] to `complexity` [#13993](https://github.com/rust-lang/rust-clippy/pull/13993) +* Added [`sliced_string_as_bytes`] to `perf` [#14002](https://github.com/rust-lang/rust-clippy/pull/14002) +* Added [`unnecessary_semicolon`] to `pedantic` [#14032](https://github.com/rust-lang/rust-clippy/pull/14032) +* Added [`return_and_then`] to `restriction` [#14051](https://github.com/rust-lang/rust-clippy/pull/14051) +* Added [`manual_slice_fill`] to `style` [#14082](https://github.com/rust-lang/rust-clippy/pull/14082) +* Added [`precedence_bits`] to `restriction` [#14115](https://github.com/rust-lang/rust-clippy/pull/14115) + +### Moves and Deprecations + +* Moved [`redundant_locals`] to `suspicious` (from `correctness`, now warn-by-default) + [#13747](https://github.com/rust-lang/rust-clippy/pull/13747) +* Moved [`format_push_string`] to `pedantic` (from `restriction`) + [#13894](https://github.com/rust-lang/rust-clippy/pull/13894) +* Moved [`format_collect`] to `pedantic` (from `perf`, now allow-by-default) + [#13894](https://github.com/rust-lang/rust-clippy/pull/13894) +* Moved [`mutex_integer`] to `restriction` (from `nursery`) [#14110](https://github.com/rust-lang/rust-clippy/pull/14110) + +### Enhancements + +* Add `lint-inconsistent-struct-field-initializers` configuration option to [`inconsistent_struct_constructor`] + [#13737](https://github.com/rust-lang/rust-clippy/pull/13737) +* [`len_zero`] now also triggers if deref target implements `is_empty()` + [#13871](https://github.com/rust-lang/rust-clippy/pull/13871) +* [`obfuscated_if_else`] now also triggers for the `.then(..).unwrap_or(..)` pattern + [#14021](https://github.com/rust-lang/rust-clippy/pull/14021) + +### False Positive Fixes + +* [`trailing_empty_array`] no longer triggers in tests [#13844](https://github.com/rust-lang/rust-clippy/pull/13844) +* [`missing_const_for_fn`] no longer triggers in tests [#13945](https://github.com/rust-lang/rust-clippy/pull/13945) +* [`significant_drop_in_scrutinee`]: do not falsely warn for temporaries created by `.await` expansion + [#13985](https://github.com/rust-lang/rust-clippy/pull/13985) + +### ICE Fixes + +* [`borrow_interior_mutable_const`] Fix an ICE that can occur when taking a reference to a tuple/`struct` field of an + interior mutable `const` [#13877](https://github.com/rust-lang/rust-clippy/pull/13877) + +### Others + +* Clippy now uses Rust edition 2024 [#13751](https://github.com/rust-lang/rust-clippy/pull/13751) ## Rust 1.85 -Current stable, released 2025-02-20 +Released 2025-02-20 [View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-11-15T19%3A31%3A08Z..2024-12-26T13%3A59%3A48Z+base%3Amaster) @@ -5516,6 +5573,7 @@ Released 2018-09-13 [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes [`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts [`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test +[`char_indices_as_byte_indices`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_indices_as_byte_indices [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp @@ -5681,6 +5739,7 @@ Released 2018-09-13 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond +[`ignore_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignore_without_reason [`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns [`impl_hash_borrow_with_str_and_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_hash_borrow_with_str_and_bytes [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params @@ -5783,12 +5842,14 @@ Released 2018-09-13 [`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion +[`manual_abs_diff`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp [`manual_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_contains +[`manual_dangling_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_dangling_ptr [`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map @@ -6055,6 +6116,7 @@ Released 2018-09-13 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes +[`redundant_test_prefix`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_test_prefix [`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations [`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference @@ -6156,6 +6218,7 @@ Released 2018-09-13 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow [`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref +[`swap_with_temporary`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_with_temporary [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr @@ -6346,6 +6409,7 @@ Released 2018-09-13 [`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types [`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish [`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests +[`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros @@ -6362,7 +6426,7 @@ Released 2018-09-13 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold -[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers +[`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold [`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else [`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools diff --git a/Cargo.toml b/Cargo.toml index f5a8e3dc387d..1cfc1c196c0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.87" +version = "0.1.88" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -27,6 +27,7 @@ clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } clippy_utils = { path = "clippy_utils" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } +clippy_lints_internal = { path = "clippy_lints_internal", optional = true } tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" @@ -43,7 +44,7 @@ walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -rinja = { version = "0.3", default-features = false, features = ["config"] } +askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } # UI test dependencies clippy_utils = { path = "clippy_utils" } @@ -58,8 +59,8 @@ tokio = { version = "1", features = ["io-util"] } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } [features] -integration = ["tempfile"] -internal = ["clippy_lints/internal", "tempfile"] +integration = ["dep:tempfile"] +internal = ["dep:clippy_lints_internal", "dep:tempfile"] [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] diff --git a/rinja.toml b/askama.toml similarity index 100% rename from rinja.toml rename to askama.toml diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 19328fdd3cd4..39fe7358ed87 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -30,6 +30,7 @@ - [Updating the Changelog](development/infrastructure/changelog_update.md) - [Release a New Version](development/infrastructure/release.md) - [The Clippy Book](development/infrastructure/book.md) + - [Benchmarking Clippy](development/infrastructure/benchmarking.md) - [Proposals](development/proposals/README.md) - [Roadmap 2021](development/proposals/roadmap-2021.md) - [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 0b9010f01071..e5e82ede4fdf 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -99,6 +99,7 @@ struct A; impl A { pub fn fo(&self) {} pub fn foo(&self) {} + //~^ foo_functions pub fn food(&self) {} } @@ -106,12 +107,14 @@ impl A { trait B { fn fo(&self) {} fn foo(&self) {} + //~^ foo_functions fn food(&self) {} } // Plain functions fn fo() {} fn foo() {} +//~^ foo_functions fn food() {} fn main() { @@ -122,17 +125,24 @@ fn main() { } ``` -Now we can run the test with `TESTNAME=foo_functions cargo uibless`, currently -this test is meaningless though. +Note that we are adding comment annotations with the name of our lint to mark +lines where we expect an error. Except for very specific situations +(`//@check-pass`), at least one error marker must be present in a test file for +it to be accepted. + +Once we have implemented our lint we can run `TESTNAME=foo_functions cargo +uibless` to generate the `.stderr` file. If our lint makes use of structured +suggestions then this command will also generate the corresponding `.fixed` +file. While we are working on implementing our lint, we can keep running the UI test. That allows us to check if the output is turning into what we want by checking the `.stderr` file that gets updated on every test run. -Running `TESTNAME=foo_functions cargo uitest` should pass on its own. When we -commit our lint, we need to commit the generated `.stderr` files, too. In -general, you should only commit files changed by `cargo bless` for the -specific lint you are creating/editing. +Once we have implemented our lint running `TESTNAME=foo_functions cargo uitest` +should pass on its own. When we commit our lint, we need to commit the generated + `.stderr` and if applicable `.fixed` files, too. In general, you should only + commit files changed by `cargo bless` for the specific lint you are creating/editing. > _Note:_ you can run multiple test files by specifying a comma separated list: > `TESTNAME=foo_functions,test2,test3`. diff --git a/book/src/development/basics.md b/book/src/development/basics.md index 931e5c3a2942..4219724ed5df 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -147,7 +147,7 @@ following: First, take note of the toolchain [override](https://rust-lang.github.io/rustup/overrides.html) in -`/rust-toolchain`. We will use this override to install Clippy into the right +`/rust-toolchain.toml`. We will use this override to install Clippy into the right toolchain. > Tip: You can view the active toolchain for the current directory with `rustup diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 051febc2ca5d..2e39f279eae4 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -159,19 +159,21 @@ paths for Clippy can be found in [paths.rs][paths] To check if our type defines a method called `some_method`: ```rust -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::return_ty; +use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{sym, return_ty}; impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { // Check if item is a method/function if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // Check the method is named `some_method` - && impl_item.ident.name.as_str() == "some_method" + // + // Add `some_method` to `clippy_utils::sym` if it's not already there + && impl_item.ident.name == sym::some_method // We can also check it has a parameter `self` && signature.decl.implicit_self.has_implicit_self() // We can go further and even check if its return type is `String` - && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)) + && is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String) { // ... } diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index 169cecd7d11d..cb6d7b740dbd 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -9,7 +9,7 @@ lint involves some boilerplate code. A lint type is the category of items and expressions in which your lint focuses on. -As of the writing of this documentation update, there are 12 _types_ of lints +As of the writing of this documentation update, there are 11 _types_ of lints besides the numerous standalone lints living under `clippy_lints/src/`: - `cargo` @@ -23,7 +23,6 @@ besides the numerous standalone lints living under `clippy_lints/src/`: - `transmute` - `types` - `unit_types` -- `utils / internal` (Clippy internal lints) These types group together lints that share some common behaviors. For instance, `functions` groups together lints that deal with some aspects of functions in diff --git a/book/src/development/infrastructure/benchmarking.md b/book/src/development/infrastructure/benchmarking.md new file mode 100644 index 000000000000..a3ebce922f6c --- /dev/null +++ b/book/src/development/infrastructure/benchmarking.md @@ -0,0 +1,55 @@ +# Benchmarking Clippy + +Benchmarking Clippy is similar to using our Lintcheck tool, in fact, it even +uses the same tool! Just by adding a `--perf` flag it will transform Lintcheck +into a very simple but powerful benchmarking tool! + +It requires having the [`perf` tool][perf] installed, as `perf` is what's actually +profiling Clippy under the hood. + +The lintcheck `--perf` tool generates a series of `perf.data` in the +`target/lintcheck/sources/-` directories. Each `perf.data` +corresponds to the package which is contained. + +Lintcheck uses the `-g` flag, meaning that you can get stack traces for richer +analysis, including with tools such as [flamegraph][flamegraph-perf] +(or [`flamegraph-rs`][flamegraph-rs]). + +Currently, we only measure instruction count, as it's the most reproducible metric +and [rustc-perf][rustc-perf] also considers it the main number to focus on. + +## Benchmarking a PR + +Having a benchmarking tool directly implemented into lintcheck gives us the +ability to benchmark any given PR just by making a before and after + +Here's the way you can get into any PR, benchmark it, and then benchmark +`master`. + +The first `perf.data` will not have any numbers appended, but any subsequent +benchmark will be written to `perf.data.number` with a number growing for 0. +All benchmarks are compressed so that you can + +```bash +git fetch upstream pull//head: +git switch BRANCHNAME + +# Bench +cargo lintcheck --perf + +# Get last common commit, checkout that +LAST_COMMIT=$(git log BRANCHNAME..master --oneline | tail -1 | cut -c 1-11) +git switch -c temporary $LAST_COMMIT + +# We're now on master + +# Bench +cargo lintcheck --perf +perf diff ./target/lintcheck/sources/CRATE/perf.data ./target/lintcheck/sources/CRATE/perf.data.0 +``` + + +[perf]: https://perfwiki.github.io/main/ +[flamegraph-perf]: https://github.com/brendangregg/FlameGraph +[flamegraph-rs]: https://github.com/flamegraph-rs/flamegraph +[rustc-perf]: https://github.com/rust-lang/rustc-perf diff --git a/book/src/development/infrastructure/release.md b/book/src/development/infrastructure/release.md index 8b080c099b81..a429e0d953c4 100644 --- a/book/src/development/infrastructure/release.md +++ b/book/src/development/infrastructure/release.md @@ -88,9 +88,6 @@ git push upstream stable After updating the `stable` branch, tag the HEAD commit and push it to the Clippy repo. -> Note: Only push the tag once the Deploy GitHub action of the `beta` branch is -> finished. Otherwise the deploy for the tag might fail. - ```bash git tag rust-1.XX.0 # XX should be exchanged with the corresponding version git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index da1ad586607f..2bbdf47a8358 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -86,7 +86,7 @@ to be run inside the `rust` directory): 4. Bump the nightly version in the Clippy repository by running these commands: ```bash cargo dev sync update_nightly - git commit -m "Bump nightly version -> YYYY-MM-DD" rust-toolchain clippy_utils/README.md + git commit -m "Bump nightly version -> YYYY-MM-DD" rust-toolchain.toml clippy_utils/README.md ``` 5. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or diff --git a/book/src/development/writing_tests.md b/book/src/development/writing_tests.md index d4cca2a72f0b..1da54322fcf7 100644 --- a/book/src/development/writing_tests.md +++ b/book/src/development/writing_tests.md @@ -41,20 +41,23 @@ Update the file with some examples to get started: struct A; impl A { pub fn fo(&self) {} - pub fn foo(&self) {} //~ ERROR: function called "foo" + pub fn foo(&self) {} + //~^ foo_functions pub fn food(&self) {} } // Default trait methods trait B { fn fo(&self) {} - fn foo(&self) {} //~ ERROR: function called "foo" + fn foo(&self) {} + //~^ foo_functions fn food(&self) {} } // Plain functions fn fo() {} -fn foo() {} //~ ERROR: function called "foo" +fn foo() {} +//~^ foo_functions fn food() {} fn main() { @@ -66,19 +69,38 @@ fn main() { ``` Without actual lint logic to emit the lint when we see a `foo` function name, -this test will just pass, because no lint will be emitted. However, we can now -run the test with the following command: +this test will fail, because we expect errors at lines marked with +`//~^ foo_functions`. However, we can now run the test with the following command: ```sh $ TESTNAME=foo_functions cargo uitest ``` -Clippy will compile and it will conclude with an `ok` for the tests: +Clippy will compile and it will fail complaining it didn't receive any errors: ``` ...Clippy warnings and test outputs... -test compile_test ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s +error: diagnostic code `clippy::foo_functions` not found on line 8 + --> tests/ui/foo_functions.rs:9:10 + | +9 | //~^ foo_functions + | ^^^^^^^^^^^^^ expected because of this pattern + | + +error: diagnostic code `clippy::foo_functions` not found on line 16 + --> tests/ui/foo_functions.rs:17:10 + | +17 | //~^ foo_functions + | ^^^^^^^^^^^^^ expected because of this pattern + | + +error: diagnostic code `clippy::foo_functions` not found on line 23 + --> tests/ui/foo_functions.rs:24:6 + | +24 | //~^ foo_functions + | ^^^^^^^^^^^^^ expected because of this pattern + | + ``` This is normal. After all, we wrote a bunch of Rust code but we haven't really diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 3726d6e8a869..2314d1beac7e 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -425,6 +425,33 @@ Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. * [`incompatible_msrv`](https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv) +## `check-inconsistent-struct-field-initializers` +Whether to suggest reordering constructor fields when initializers are present. + +Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the +suggested code would compile, it can change semantics if the initializer expressions have side effects. The +following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: + +```rust +struct MyStruct { + vector: Vec, + length: usize +} +fn main() { + let vector = vec![1,2,3]; + MyStruct { length: vector.len(), vector}; +} +``` + +[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 + +**Default Value:** `false` + +--- +**Affected lints:** +* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor) + + ## `check-private-items` Whether to also run the listed lints on private items. @@ -613,31 +640,15 @@ The maximum size of the `Err`-variant in a `Result` returned from a function * [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) -## `lint-inconsistent-struct-field-initializers` -Whether to suggest reordering constructor fields when initializers are present. - -Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the -suggested code would compile, it can change semantics if the initializer expressions have side effects. The -following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: - -```rust -struct MyStruct { - vector: Vec, - length: usize -} -fn main() { - let vector = vec![1,2,3]; - MyStruct { length: vector.len(), vector}; -} -``` - -[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 +## `lint-commented-code` +Whether collapsible `if` chains are linted if they contain comments inside the parts +that would be collapsed. **Default Value:** `false` --- **Affected lints:** -* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor) +* [`collapsible_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if) ## `literal-representation-threshold` @@ -786,6 +797,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) * [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants) * [`lines_filter_map_ok`](https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok) +* [`manual_abs_diff`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff) * [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) * [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) * [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) @@ -793,6 +805,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten) * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [`manual_is_power_of_two`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) @@ -1059,7 +1072,8 @@ The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' ## `warn-on-all-wildcard-imports` -Whether to allow certain wildcard imports (prelude, super in tests). +Whether to emit warnings on all wildcard imports, including those from `prelude`, from `super` in tests, +or for `pub use` reexports. **Default Value:** `false` diff --git a/clippy.toml b/clippy.toml index f4789c9d0303..0a7724bbe4e6 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,15 +1,20 @@ avoid-breaking-exported-api = false -lint-inconsistent-struct-field-initializers = true +check-inconsistent-struct-field-initializers = true + +lint-commented-code = true [[disallowed-methods]] path = "rustc_lint::context::LintContext::lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" +allow-invalid = true [[disallowed-methods]] path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" +allow-invalid = true [[disallowed-methods]] path = "rustc_middle::ty::context::TyCtxt::node_span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" +allow-invalid = true diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 934725fccb8e..93fd2e35d1ba 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.87" +version = "0.1.88" # end autogenerated version edition = "2024" publish = false diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 798f8b3aa5a9..511cb84527d8 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -120,12 +120,7 @@ impl ConfError { Self { message: message.into(), suggestion, - span: Span::new( - file.start_pos + BytePos::from_usize(span.start), - file.start_pos + BytePos::from_usize(span.end), - SyntaxContext::root(), - None, - ), + span: span_from_toml_range(file, span), } } } @@ -176,11 +171,61 @@ macro_rules! default_text { }; } +macro_rules! deserialize { + ($map:expr, $ty:ty, $errors:expr, $file:expr) => {{ + let raw_value = $map.next_value::>()?; + let value_span = raw_value.span(); + let value = match <$ty>::deserialize(raw_value.into_inner()) { + Err(e) => { + $errors.push(ConfError::spanned( + $file, + e.to_string().replace('\n', " ").trim(), + None, + value_span, + )); + continue; + }, + Ok(value) => value, + }; + (value, value_span) + }}; + + ($map:expr, $ty:ty, $errors:expr, $file:expr, $replacements_allowed:expr) => {{ + let array = $map.next_value::>>()?; + let mut disallowed_paths_span = Range { + start: usize::MAX, + end: usize::MIN, + }; + let mut disallowed_paths = Vec::new(); + for raw_value in array { + let value_span = raw_value.span(); + let mut disallowed_path = match DisallowedPath::<$replacements_allowed>::deserialize(raw_value.into_inner()) + { + Err(e) => { + $errors.push(ConfError::spanned( + $file, + e.to_string().replace('\n', " ").trim(), + None, + value_span, + )); + continue; + }, + Ok(disallowed_path) => disallowed_path, + }; + disallowed_paths_span = union(&disallowed_paths_span, &value_span); + disallowed_path.set_span(span_from_toml_range($file, value_span)); + disallowed_paths.push(disallowed_path); + } + (disallowed_paths, disallowed_paths_span) + }}; +} + macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? + $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])? $(#[lints($($for_lints:ident),* $(,)?)])? $name:ident: $ty:ty = $default:expr, )*) => { @@ -218,42 +263,46 @@ macro_rules! define_Conf { let mut value_spans = HashMap::new(); let mut errors = Vec::new(); let mut warnings = Vec::new(); + + // Declare a local variable for each field available to a configuration file. $(let mut $name = None;)* + // could get `Field` here directly, but get `String` first for diagnostics while let Some(name) = map.next_key::>()? { - match Field::deserialize(name.get_ref().as_str().into_deserializer()) { + let field = match Field::deserialize(name.get_ref().as_str().into_deserializer()) { Err(e) => { let e: FieldError = e; errors.push(ConfError::spanned(self.0, e.error, e.suggestion, name.span())); + continue; } - $(Ok(Field::$name) => { + Ok(field) => field + }; + + match field { + $(Field::$name => { + // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning. $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? - let raw_value = map.next_value::>()?; - let value_span = raw_value.span(); - match <$ty>::deserialize(raw_value.into_inner()) { - Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), None, value_span)), - Ok(value) => match $name { - Some(_) => { - errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); - } - None => { - $name = Some(value); - value_spans.insert(name.get_ref().as_str().to_string(), value_span); - // $new_conf is the same as one of the defined `$name`s, so - // this variable is defined in line 2 of this function. - $(match $new_conf { - Some(_) => errors.push(ConfError::spanned(self.0, concat!( - "duplicate field `", stringify!($new_conf), - "` (provided as `", stringify!($name), "`)" - ), None, name.span())), - None => $new_conf = $name.clone(), - })? - }, - } + let (value, value_span) = + deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?); + // Was this field set previously? + if $name.is_some() { + errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); + continue; } + $name = Some(value); + value_spans.insert(name.get_ref().as_str().to_string(), value_span); + // If this is a deprecated field, was the new field (`$new_conf`) set previously? + // Note that `$new_conf` is one of the defined `$name`s. + $(match $new_conf { + Some(_) => errors.push(ConfError::spanned(self.0, concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ), None, name.span())), + None => $new_conf = $name.clone(), + })? })* // ignore contents of the third_party key - Ok(Field::third_party) => drop(map.next_value::()) + Field::third_party => drop(map.next_value::()) } } let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; @@ -275,6 +324,22 @@ macro_rules! define_Conf { }; } +fn union(x: &Range, y: &Range) -> Range { + Range { + start: cmp::min(x.start, y.start), + end: cmp::max(x.end, y.end), + } +} + +fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { + Span::new( + file.start_pos + BytePos::from_usize(span.start), + file.start_pos + BytePos::from_usize(span.end), + SyntaxContext::root(), + None, + ) +} + define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] @@ -461,6 +526,7 @@ define_Conf! { )] avoid_breaking_exported_api: bool = true, /// The list of types which may not be held across an await point. + #[disallowed_paths_allow_replacements = false] #[lints(await_holding_invalid_type)] await_holding_invalid_types: Vec = Vec::new(), /// DEPRECATED LINT: BLACKLISTED_NAME. @@ -474,6 +540,26 @@ define_Conf! { /// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. #[lints(incompatible_msrv)] check_incompatible_msrv_in_tests: bool = false, + /// Whether to suggest reordering constructor fields when initializers are present. + /// + /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the + /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The + /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: + /// + /// ```rust + /// struct MyStruct { + /// vector: Vec, + /// length: usize + /// } + /// fn main() { + /// let vector = vec![1,2,3]; + /// MyStruct { length: vector.len(), vector}; + /// } + /// ``` + /// + /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 + #[lints(inconsistent_struct_constructor)] + check_inconsistent_struct_field_initializers: bool = false, /// Whether to also run the listed lints on private items. #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)] check_private_items: bool = false, @@ -486,9 +572,11 @@ define_Conf! { #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] cyclomatic_complexity_threshold: u64 = 25, /// The list of disallowed macros, written as fully qualified paths. + #[disallowed_paths_allow_replacements = true] #[lints(disallowed_macros)] disallowed_macros: Vec = Vec::new(), /// The list of disallowed methods, written as fully qualified paths. + #[disallowed_paths_allow_replacements = true] #[lints(disallowed_methods)] disallowed_methods: Vec = Vec::new(), /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value @@ -497,6 +585,7 @@ define_Conf! { #[lints(disallowed_names)] disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(), /// The list of disallowed types, written as fully qualified paths. + #[disallowed_paths_allow_replacements = true] #[lints(disallowed_types)] disallowed_types: Vec = Vec::new(), /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -549,25 +638,15 @@ define_Conf! { /// The maximum size of the `Err`-variant in a `Result` returned from a function #[lints(result_large_err)] large_error_threshold: u64 = 128, + /// Whether collapsible `if` chains are linted if they contain comments inside the parts + /// that would be collapsed. + #[lints(collapsible_if)] + lint_commented_code: bool = false, /// Whether to suggest reordering constructor fields when initializers are present. + /// DEPRECATED CONFIGURATION: lint-inconsistent-struct-field-initializers /// - /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the - /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The - /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: - /// - /// ```rust - /// struct MyStruct { - /// vector: Vec, - /// length: usize - /// } - /// fn main() { - /// let vector = vec![1,2,3]; - /// MyStruct { length: vector.len(), vector}; - /// } - /// ``` - /// - /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 - #[lints(inconsistent_struct_constructor)] + /// Use the `check-inconsistent-struct-field-initializers` configuration instead. + #[conf_deprecated("Please use `check-inconsistent-struct-field-initializers` instead", check_inconsistent_struct_field_initializers)] lint_inconsistent_struct_field_initializers: bool = false, /// The lower bound for linting decimal literals #[lints(decimal_literal_representation)] @@ -635,6 +714,7 @@ define_Conf! { iter_kv_map, legacy_numeric_constants, lines_filter_map_ok, + manual_abs_diff, manual_bits, manual_c_str_literals, manual_clamp, @@ -642,6 +722,7 @@ define_Conf! { manual_flatten, manual_hash_one, manual_is_ascii_check, + manual_is_power_of_two, manual_let_else, manual_midpoint, manual_non_exhaustive, @@ -760,7 +841,8 @@ define_Conf! { /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' #[lints(verbose_bit_mask)] verbose_bit_mask_threshold: u64 = 1, - /// Whether to allow certain wildcard imports (prelude, super in tests). + /// Whether to emit warnings on all wildcard imports, including those from `prelude`, from `super` in tests, + /// or for `pub use` reexports. #[lints(wildcard_imports)] warn_on_all_wildcard_imports: bool = false, /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. @@ -981,7 +1063,23 @@ impl serde::de::Error for FieldError { // set and allows it. use fmt::Write; - let mut expected = expected.to_vec(); + let metadata = get_configuration_metadata(); + let deprecated = metadata + .iter() + .filter_map(|conf| { + if conf.deprecation_reason.is_some() { + Some(conf.name.as_str()) + } else { + None + } + }) + .collect::>(); + + let mut expected = expected + .iter() + .copied() + .filter(|name| !deprecated.contains(name)) + .collect::>(); expected.sort_unstable(); let (rows, column_widths) = calculate_dimensions(&expected); @@ -1064,7 +1162,13 @@ mod tests { fn configs_are_tested() { let mut names: HashSet = crate::get_configuration_metadata() .into_iter() - .map(|meta| meta.name.replace('_', "-")) + .filter_map(|meta| { + if meta.deprecation_reason.is_none() { + Some(meta.name.replace('_', "-")) + } else { + None + } + }) .collect(); let toml_files = WalkDir::new("../tests") diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 5d6e8b875166..c227b8900b74 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -13,6 +13,7 @@ rustc::untranslatable_diagnostic )] +extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_middle; diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 8faac9ecffea..5949eaca7bc1 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,5 +1,7 @@ -use clippy_utils::def_path_def_ids; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag}; +use rustc_hir::PrimTy; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -21,6 +23,17 @@ pub struct DisallowedPath { path: String, reason: Option, replacement: Option, + /// Setting `allow_invalid` to true suppresses a warning if `path` does not refer to an existing + /// definition. + /// + /// This could be useful when conditional compilation is used, or when a clippy.toml file is + /// shared among multiple projects. + allow_invalid: bool, + /// The span of the `DisallowedPath`. + /// + /// Used for diagnostics. + #[serde(skip_serializing)] + span: Span, } impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath { @@ -36,6 +49,8 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath, replacement: Option, + #[serde(rename = "allow-invalid")] + allow_invalid: Option, }, } @@ -58,7 +75,7 @@ impl DisallowedPath { &self.path } - pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> { + pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) { move |diag| { if let Some(replacement) = &self.replacement { diag.span_suggestion( @@ -72,6 +89,14 @@ impl DisallowedPath { } } } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } } impl DisallowedPathEnum { @@ -94,20 +119,87 @@ impl DisallowedPathEnum { Self::Simple(_) => None, } } + + fn allow_invalid(&self) -> bool { + match &self { + Self::WithReason { allow_invalid, .. } => allow_invalid.unwrap_or_default(), + Self::Simple(_) => false, + } + } } /// Creates a map of disallowed items to the reason they were disallowed. +#[allow(clippy::type_complexity)] pub fn create_disallowed_map( tcx: TyCtxt<'_>, - disallowed: &'static [DisallowedPath], -) -> DefIdMap<(&'static str, &'static DisallowedPath)> { - disallowed - .iter() - .map(|x| (x.path(), x.path().split("::").collect::>(), x)) - .flat_map(|(name, path, disallowed_path)| { - def_path_def_ids(tcx, &path).map(move |id| (id, (name, disallowed_path))) - }) - .collect() + disallowed_paths: &'static [DisallowedPath], + def_kind_predicate: impl Fn(DefKind) -> bool, + predicate_description: &str, + allow_prim_tys: bool, +) -> ( + DefIdMap<(&'static str, &'static DisallowedPath)>, + FxHashMap)>, +) { + let mut def_ids: DefIdMap<(&'static str, &'static DisallowedPath)> = DefIdMap::default(); + let mut prim_tys: FxHashMap)> = + FxHashMap::default(); + for disallowed_path in disallowed_paths { + let path = disallowed_path.path(); + let mut resolutions = clippy_utils::def_path_res(tcx, &path.split("::").collect::>()); + + let mut found_def_id = None; + let mut found_prim_ty = false; + resolutions.retain(|res| match res { + Res::Def(def_kind, def_id) => { + found_def_id = Some(*def_id); + def_kind_predicate(*def_kind) + }, + Res::PrimTy(_) => { + found_prim_ty = true; + allow_prim_tys + }, + _ => false, + }); + + if resolutions.is_empty() { + let span = disallowed_path.span(); + + if let Some(def_id) = found_def_id { + tcx.sess.dcx().span_warn( + span, + format!( + "expected a {predicate_description}, found {} {}", + tcx.def_descr_article(def_id), + tcx.def_descr(def_id) + ), + ); + } else if found_prim_ty { + tcx.sess.dcx().span_warn( + span, + format!("expected a {predicate_description}, found a primitive type",), + ); + } else if !disallowed_path.allow_invalid { + tcx.sess.dcx().span_warn( + span, + format!("`{path}` does not refer to an existing {predicate_description}"), + ); + } + } + + for res in resolutions { + match res { + Res::Def(_, def_id) => { + def_ids.insert(def_id, (path, disallowed_path)); + }, + Res::PrimTy(ty) => { + prim_tys.insert(ty, (path, disallowed_path)); + }, + _ => unreachable!(), + } + } + } + + (def_ids, prim_tys) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 9280369c23b8..c1ffaf269c6f 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -13,6 +13,7 @@ #[allow(unused_extern_crates)] extern crate rustc_driver; extern crate rustc_lexer; +extern crate rustc_literal_escaper; pub mod dogfood; pub mod fmt; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 074dea4ab77b..83f8e66b3347 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -170,7 +170,6 @@ enum DevCommand { "restriction", "cargo", "nursery", - "internal", ], default_value = "nursery", )] @@ -334,7 +333,7 @@ struct SyncCommand { #[derive(Subcommand)] enum SyncSubcommand { #[command(name = "update_nightly")] - /// Update nightly version in rust-toolchain and `clippy_utils` + /// Update nightly version in `rust-toolchain.toml` and `clippy_utils` UpdateNightly, } diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs index 2966629cf70a..ecd80215f7e8 100644 --- a/clippy_dev/src/setup/toolchain.rs +++ b/clippy_dev/src/setup/toolchain.rs @@ -62,7 +62,7 @@ pub fn create(standalone: bool, force: bool, release: bool, name: &str) { println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); if !standalone { - println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain.toml` changes"); } } diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs index 3522d182e90a..a6b65e561c22 100644 --- a/clippy_dev/src/sync.rs +++ b/clippy_dev/src/sync.rs @@ -10,7 +10,7 @@ pub fn update_nightly() { let date = Utc::now().format("%Y-%m-%d").to_string(); replace_region_in_file( UpdateMode::Change, - Path::new("rust-toolchain"), + Path::new("rust-toolchain.toml"), "# begin autogenerated nightly\n", "# end autogenerated nightly", |res| { diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index b80ee5aac7e7..d848a97f86d2 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,7 +1,8 @@ use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file}; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; -use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape}; +use rustc_lexer::{LiteralKind, TokenKind, tokenize}; +use rustc_literal_escaper::{Mode, unescape_unicode}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::{self, Write}; @@ -37,9 +38,8 @@ fn generate_lint_files( deprecated_lints: &[DeprecatedLint], renamed_lints: &[RenamedLint], ) { - let internal_lints = Lint::internal_lints(lints); - let mut usable_lints = Lint::usable_lints(lints); - usable_lints.sort_by_key(|lint| lint.name.clone()); + let mut lints = lints.to_owned(); + lints.sort_by_key(|lint| lint.name.clone()); replace_region_in_file( update_mode, @@ -47,7 +47,7 @@ fn generate_lint_files( "[There are over ", " lints included in this crate!]", |res| { - write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); + write!(res, "{}", round_to_fifty(lints.len())).unwrap(); }, ); @@ -57,7 +57,7 @@ fn generate_lint_files( "[There are over ", " lints included in this crate!]", |res| { - write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); + write!(res, "{}", round_to_fifty(lints.len())).unwrap(); }, ); @@ -67,7 +67,7 @@ fn generate_lint_files( "\n", "", |res| { - for lint in usable_lints + for lint in lints .iter() .map(|l| &*l.name) .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) @@ -86,7 +86,7 @@ fn generate_lint_files( "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", "// end lints modules, do not remove this comment, it’s used in `update_lints`", |res| { - for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() { + for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() { writeln!(res, "mod {lint_mod};").unwrap(); } }, @@ -95,7 +95,7 @@ fn generate_lint_files( process_file( "clippy_lints/src/declared_lints.rs", update_mode, - &gen_declared_lints(internal_lints.iter(), usable_lints.iter()), + &gen_declared_lints(lints.iter()), ); let content = gen_deprecated_lints_test(deprecated_lints); @@ -106,10 +106,9 @@ fn generate_lint_files( } pub fn print_lints() { - let (lint_list, _, _) = gather_all(); - let usable_lints = Lint::usable_lints(&lint_list); - let usable_lint_count = usable_lints.len(); - let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter()); + let (lints, _, _) = gather_all(); + let lint_count = lints.len(); + let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter()); for (lint_group, mut lints) in grouped_by_lint_group { println!("\n## {lint_group}"); @@ -121,7 +120,7 @@ pub fn print_lints() { } } - println!("there are {usable_lint_count} lints"); + println!("there are {lint_count} lints"); } /// Runs the `rename_lint` command. @@ -402,53 +401,53 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io } } - if path.exists() { - if let Some(lint) = lints.iter().find(|l| l.name == name) { - if lint.module == name { - // The lint name is the same as the file, we can just delete the entire file - fs::remove_file(path)?; - } else { - // We can't delete the entire file, just remove the declaration + if path.exists() + && let Some(lint) = lints.iter().find(|l| l.name == name) + { + if lint.module == name { + // The lint name is the same as the file, we can just delete the entire file + fs::remove_file(path)?; + } else { + // We can't delete the entire file, just remove the declaration - if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { - // Remove clippy_lints/src/some_mod/some_lint.rs - let mut lint_mod_path = path.to_path_buf(); - lint_mod_path.set_file_name(name); - lint_mod_path.set_extension("rs"); + if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { + // Remove clippy_lints/src/some_mod/some_lint.rs + let mut lint_mod_path = path.to_path_buf(); + lint_mod_path.set_file_name(name); + lint_mod_path.set_extension("rs"); - let _ = fs::remove_file(lint_mod_path); - } - - let mut content = - fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); - - eprintln!( - "warn: you will have to manually remove any code related to `{name}` from `{}`", - path.display() - ); - - assert!( - content[lint.declaration_range.clone()].contains(&name.to_uppercase()), - "error: `{}` does not contain lint `{}`'s declaration", - path.display(), - lint.name - ); - - // Remove lint declaration (declare_clippy_lint!) - content.replace_range(lint.declaration_range.clone(), ""); - - // Remove the module declaration (mod xyz;) - let mod_decl = format!("\nmod {name};"); - content = content.replacen(&mod_decl, "", 1); - - remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); - fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); + let _ = fs::remove_file(lint_mod_path); } - remove_test_assets(name); - remove_lint(name, lints); - return Ok(true); + let mut content = + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + + eprintln!( + "warn: you will have to manually remove any code related to `{name}` from `{}`", + path.display() + ); + + assert!( + content[lint.declaration_range.clone()].contains(&name.to_uppercase()), + "error: `{}` does not contain lint `{}`'s declaration", + path.display(), + lint.name + ); + + // Remove lint declaration (declare_clippy_lint!) + content.replace_range(lint.declaration_range.clone(), ""); + + // Remove the module declaration (mod xyz;) + let mod_decl = format!("\nmod {name};"); + content = content.replacen(&mod_decl, "", 1); + + remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); + fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); } + + remove_test_assets(name); + remove_lint(name, lints); + return Ok(true); } Ok(false) @@ -527,22 +526,6 @@ impl Lint { } } - /// Returns all non-deprecated lints and non-internal lints - #[must_use] - fn usable_lints(lints: &[Self]) -> Vec { - lints - .iter() - .filter(|l| !l.group.starts_with("internal")) - .cloned() - .collect() - } - - /// Returns all internal lints - #[must_use] - fn internal_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.group == "internal").cloned().collect() - } - /// Returns the lints in a `HashMap`, grouped by the different lint groups #[must_use] fn by_lint_group(lints: impl Iterator) -> HashMap> { @@ -579,23 +562,14 @@ impl RenamedLint { /// Generates the code for registering lints #[must_use] -fn gen_declared_lints<'a>( - internal_lints: impl Iterator, - usable_lints: impl Iterator, -) -> String { - let mut details: Vec<_> = internal_lints - .map(|l| (false, &l.module, l.name.to_uppercase())) - .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase()))) - .collect(); +fn gen_declared_lints<'a>(lints: impl Iterator) -> String { + let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); details.sort_unstable(); let mut output = GENERATED_FILE_COMMENT.to_string(); output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); - for (is_public, module_name, lint_name) in details { - if !is_public { - output.push_str(" #[cfg(feature = \"internal\")]\n"); - } + for (module_name, lint_name) in details { let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); } output.push_str("];\n"); @@ -830,7 +804,7 @@ fn remove_line_splices(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - unescape::unescape_unicode(s, unescape::Mode::Str, &mut |range, ch| { + unescape_unicode(s, Mode::Str, &mut |range, ch| { if ch.is_ok() { res.push_str(&s[range]); } @@ -936,41 +910,6 @@ mod tests { assert_eq!(expected, result); } - #[test] - fn test_usable_lints() { - let lints = vec![ - Lint::new( - "should_assert_eq2", - "Not Deprecated", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new( - "should_assert_eq2", - "internal", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new( - "should_assert_eq2", - "internal_style", - "\"abc\"", - "module_name", - Range::default(), - ), - ]; - let expected = vec![Lint::new( - "should_assert_eq2", - "Not Deprecated", - "\"abc\"", - "module_name", - Range::default(), - )]; - assert_eq!(expected, Lint::usable_lints(&lints)); - } - #[test] fn test_by_lint_group() { let lints = vec![ diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index b87fcca13b1c..206816398f50 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -30,10 +30,10 @@ pub fn clippy_project_root() -> PathBuf { let current_dir = std::env::current_dir().unwrap(); for path in current_dir.ancestors() { let result = fs::read_to_string(path.join("Cargo.toml")); - if let Err(err) = &result { - if err.kind() == io::ErrorKind::NotFound { - continue; - } + if let Err(err) = &result + && err.kind() == io::ErrorKind::NotFound + { + continue; } let content = result.unwrap(); diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 54347043a13d..20951afccbb7 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.87" +version = "0.1.88" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -19,10 +19,7 @@ itertools = "0.12" quine-mc_cluskey = "0.2" regex-syntax = "0.8" serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", optional = true } -tempfile = { version = "3.3.0", optional = true } toml = "0.7.3" -regex = { version = "1.5", optional = true } unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } semver = "1.0" @@ -31,10 +28,6 @@ url = "2.2" [dev-dependencies] walkdir = "2.3" -[features] -# build clippy with internal lints enabled, off by default -internal = ["serde_json", "tempfile", "regex"] - [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] rustc_private = true diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index 57cabe437034..272444475c0c 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -5,6 +5,7 @@ use clippy_config::types::{ SourceItemOrderingWithinModuleItemGroupings, }; use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::is_cfg_test; use rustc_hir::{ AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant, VariantData, @@ -263,10 +264,11 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { continue; } - if let Some(cur_v) = cur_v { - if cur_v.ident.name.as_str() > variant.ident.name.as_str() && cur_v.span != variant.span { - Self::lint_member_name(cx, &variant.ident, &cur_v.ident); - } + if let Some(cur_v) = cur_v + && cur_v.ident.name.as_str() > variant.ident.name.as_str() + && cur_v.span != variant.span + { + Self::lint_member_name(cx, &variant.ident, &cur_v.ident); } cur_v = Some(variant); } @@ -278,10 +280,11 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { continue; } - if let Some(cur_f) = cur_f { - if cur_f.ident.name.as_str() > field.ident.name.as_str() && cur_f.span != field.span { - Self::lint_member_name(cx, &field.ident, &cur_f.ident); - } + if let Some(cur_f) = cur_f + && cur_f.ident.name.as_str() > field.ident.name.as_str() + && cur_f.span != field.span + { + Self::lint_member_name(cx, &field.ident, &cur_f.ident); } cur_f = Some(field); } @@ -342,7 +345,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { struct CurItem<'a> { item: &'a Item<'a>, order: usize, - name: String, + name: Option, } let mut cur_t: Option> = None; @@ -359,32 +362,36 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { // as no sorting by source map/line of code has to be applied. // for item in items { + if is_cfg_test(cx.tcx, item.hir_id()) { + continue; + } + if item.span.in_external_macro(cx.sess().source_map()) { continue; } - let ident = if let Some(ident) = item.kind.ident() { - ident - } else if let ItemKind::Impl(_) = item.kind - && !get_item_name(item).is_empty() - { - rustc_span::Ident::empty() // FIXME: a bit strange, is there a better way to do it? - } else { - continue; - }; - - if ident.name.as_str().starts_with('_') { - // Filters out unnamed macro-like impls for various derives, - // e.g. serde::Serialize or num_derive::FromPrimitive. - continue; - } - - if ident.name == rustc_span::sym::std && item.span.is_dummy() { - if let ItemKind::ExternCrate(None, _) = item.kind { - // Filters the auto-included Rust standard library. + if let Some(ident) = item.kind.ident() { + if ident.name.as_str().starts_with('_') { + // Filters out unnamed macro-like impls for various derives, + // e.g. serde::Serialize or num_derive::FromPrimitive. continue; } - println!("Unknown item: {item:?}"); + + if ident.name == rustc_span::sym::std && item.span.is_dummy() { + if let ItemKind::ExternCrate(None, _) = item.kind { + // Filters the auto-included Rust standard library. + continue; + } + if cfg!(debug_assertions) { + rustc_middle::bug!("unknown item: {item:?}"); + } + } + } else if let ItemKind::Impl(_) = item.kind + && get_item_name(item).is_some() + { + // keep going below + } else { + continue; } let item_kind = convert_module_item_kind(&item.kind); @@ -493,7 +500,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte /// further in the [Rust Reference, Paths Chapter][rust_ref]. /// /// [rust_ref]: https://doc.rust-lang.org/reference/paths.html#crate-1 -fn get_item_name(item: &Item<'_>) -> String { +fn get_item_name(item: &Item<'_>) -> Option { match item.kind { ItemKind::Impl(im) => { if let TyKind::Path(path) = im.self_ty.kind { @@ -513,27 +520,19 @@ fn get_item_name(item: &Item<'_>) -> String { } segs.push(String::new()); - segs.join("!!") + Some(segs.join("!!")) }, QPath::TypeRelative(_, _path_seg) => { // This case doesn't exist in the clippy tests codebase. - String::new() + None }, - QPath::LangItem(_, _) => String::new(), + QPath::LangItem(_, _) => None, } } else { // Impls for anything that isn't a named type can be skipped. - String::new() + None } }, - // FIXME: `Ident::empty` for anonymous items is a bit strange, is there - // a better way to do it? - _ => item - .kind - .ident() - .unwrap_or(rustc_span::Ident::empty()) - .name - .as_str() - .to_owned(), + _ => item.kind.ident().map(|name| name.as_str().to_owned()), } } diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 78102772927c..27e304a848e3 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -12,17 +12,17 @@ declare_clippy_lint! { /// regardless of whether good alternatives exist or not. If you want more /// precise lints for `as`, please consider using these separate lints: /// - /// - clippy::cast_lossless - /// - clippy::cast_possible_truncation - /// - clippy::cast_possible_wrap - /// - clippy::cast_precision_loss - /// - clippy::cast_sign_loss - /// - clippy::char_lit_as_u8 - /// - clippy::fn_to_numeric_cast - /// - clippy::fn_to_numeric_cast_with_truncation - /// - clippy::ptr_as_ptr - /// - clippy::unnecessary_cast - /// - invalid_reference_casting + /// - `clippy::cast_lossless` + /// - `clippy::cast_possible_truncation` + /// - `clippy::cast_possible_wrap` + /// - `clippy::cast_precision_loss` + /// - `clippy::cast_sign_loss` + /// - `clippy::char_lit_as_u8` + /// - `clippy::fn_to_numeric_cast` + /// - `clippy::fn_to_numeric_cast_with_truncation` + /// - `clippy::ptr_as_ptr` + /// - `clippy::unnecessary_cast` + /// - `invalid_reference_casting` /// /// There is a good explanation the reason why this lint should work in this /// way and how it is useful [in this diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index e5439a6d401b..9acff676d4f6 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -243,7 +243,7 @@ fn build_sugg<'tcx>( // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` Sugg::hir_with_applicability(cx, lhs, "_", app) } - .maybe_par(); + .maybe_paren(); // Determine whether we need to reference the argument to clone_from(). let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg); @@ -284,7 +284,7 @@ fn build_sugg<'tcx>( let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` - let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par(); + let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_paren(); let inner_type = cx.typeck_results().expr_ty(ref_expr); // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it // deref to a mutable reference. @@ -296,7 +296,7 @@ fn build_sugg<'tcx>( } else { // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` - Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr() + Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_paren().mut_addr() }; match call_kind { diff --git a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index fecf31664063..457692ed5dc5 100644 --- a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -8,17 +8,18 @@ use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { - if let Some(lint_name) = extract_clippy_lint(lint) { - if lint_name.as_str() == "restriction" && name != sym::allow { - span_lint_and_help( - cx, - BLANKET_CLIPPY_RESTRICTION_LINTS, - lint.span(), - "`clippy::restriction` is not meant to be enabled as a group", - None, - "enable the restriction lints you need individually", - ); - } + if let Some(lint_name) = extract_clippy_lint(lint) + && lint_name.as_str() == "restriction" + && name != sym::allow + { + span_lint_and_help( + cx, + BLANKET_CLIPPY_RESTRICTION_LINTS, + lint.span(), + "`clippy::restriction` is not meant to be enabled as a group", + None, + "enable the restriction lints you need individually", + ); } } } diff --git a/clippy_lints/src/attrs/deprecated_semver.rs b/clippy_lints/src/attrs/deprecated_semver.rs index d3153ec6613b..50943b36809d 100644 --- a/clippy_lints/src/attrs/deprecated_semver.rs +++ b/clippy_lints/src/attrs/deprecated_semver.rs @@ -6,10 +6,10 @@ use rustc_span::Span; use semver::Version; pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { - if let LitKind::Str(is, _) = lit.kind { - if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { - return; - } + if let LitKind::Str(is, _) = lit.kind + && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok()) + { + return; } span_lint( cx, diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 4c84e61b1f26..a851daaede71 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -36,10 +36,7 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc - || name == sym::cfg_attr_trace - || name == sym::rustc_on_unimplemented - || name == sym::reason { + if name == sym::doc || name == sym::cfg_attr_trace || name == sym::rustc_on_unimplemented || name == sym::reason { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index e04d2ad5d13b..f7f168cb2679 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -14,8 +14,9 @@ mod useless_attribute; mod utils; use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -448,6 +449,31 @@ declare_clippy_lint! { "duplicated attribute" } +declare_clippy_lint! { + /// ### What it does + /// Checks for ignored tests without messages. + /// + /// ### Why is this bad? + /// The reason for ignoring the test may not be obvious. + /// + /// ### Example + /// ```no_run + /// #[test] + /// #[ignore] + /// fn test() {} + /// ``` + /// Use instead: + /// ```no_run + /// #[test] + /// #[ignore = "Some good reason"] + /// fn test() {} + /// ``` + #[clippy::version = "1.85.0"] + pub IGNORE_WITHOUT_REASON, + pedantic, + "ignored tests without messages" +} + pub struct Attributes { msrv: Msrv, } @@ -532,6 +558,7 @@ impl_lint_pass!(PostExpansionEarlyAttributes => [ ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, DEPRECATED_SEMVER, + IGNORE_WITHOUT_REASON, USELESS_ATTRIBUTE, BLANKET_CLIPPY_RESTRICTION_LINTS, SHOULD_PANIC_WITHOUT_EXPECT, @@ -546,28 +573,27 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { - if let Some(items) = &attr.meta_item_list() { - if let Some(ident) = attr.ident() { - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes::check(cx, attr); - } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) + if let Some(items) = &attr.meta_item_list() + && let Some(ident) = attr.ident() + { + if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes::check(cx, attr); + } + if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes_without_reason::check(cx, ident.name, items, attr); + } + if is_lint_level(ident.name, attr.id) { + blanket_clippy_restriction_lints::check(cx, ident.name, items); + } + if items.is_empty() || !attr.has_name(sym::deprecated) { + return; + } + for item in items { + if let MetaItemInner::MetaItem(mi) = &item + && let MetaItemKind::NameValue(lit) = &mi.kind + && mi.has_name(sym::since) { - allow_attributes_without_reason::check(cx, ident.name, items, attr); - } - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); - } - if items.is_empty() || !attr.has_name(sym::deprecated) { - return; - } - for item in items { - if let MetaItemInner::MetaItem(mi) = &item - && let MetaItemKind::NameValue(lit) = &mi.kind - && mi.has_name(sym::since) - { - deprecated_semver::check(cx, item.span(), lit); - } + deprecated_semver::check(cx, item.span(), lit); } } } @@ -575,6 +601,22 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::should_panic) { should_panic_without_expect::check(cx, attr); } + + if attr.has_name(sym::ignore) + && match &attr.kind { + AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }), + AttrKind::DocComment(..) => true, + } + { + span_lint_and_help( + cx, + IGNORE_WITHOUT_REASON, + attr.span, + "`#[ignore]` without reason", + None, + "add a reason with `= \"..\"`", + ); + } } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) { diff --git a/clippy_lints/src/attrs/repr_attributes.rs b/clippy_lints/src/attrs/repr_attributes.rs index e5cfbaf952a7..df01c7fde181 100644 --- a/clippy_lints/src/attrs/repr_attributes.rs +++ b/clippy_lints/src/attrs/repr_attributes.rs @@ -30,7 +30,7 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], diag.warn( "unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI", ) - .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") + .help("qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") .span_label(packed_span, "`packed` representation set here"); }, ); diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1cb43ab02a30..d75b73280e63 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -14,75 +14,75 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { if attr.span.in_external_macro(cx.sess().source_map()) { return; } - if let Some(lint_list) = &attr.meta_item_list() { - if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) { - for lint in lint_list { - match item.kind { - ItemKind::Use(..) => { - let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else { - return; - }; + if let Some(lint_list) = &attr.meta_item_list() + && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) + { + for lint in lint_list { + match item.kind { + ItemKind::Use(..) => { + let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else { + return; + }; - if namespace.is_none() - && matches!( - name.as_str(), - "ambiguous_glob_reexports" - | "dead_code" - | "deprecated" - | "hidden_glob_reexports" - | "unreachable_pub" - | "unused" - | "unused_braces" - | "unused_import_braces" - | "unused_imports" - ) - { - return; - } + if namespace.is_none() + && matches!( + name.as_str(), + "ambiguous_glob_reexports" + | "dead_code" + | "deprecated" + | "hidden_glob_reexports" + | "unreachable_pub" + | "unused" + | "unused_braces" + | "unused_import_braces" + | "unused_imports" + ) + { + return; + } - if namespace == Some(sym::clippy) - && matches!( - name.as_str(), - "wildcard_imports" - | "enum_glob_use" - | "redundant_pub_crate" - | "macro_use_imports" - | "unsafe_removed_from_name" - | "module_name_repetitions" - | "single_component_path_imports" - | "disallowed_types" - | "unused_trait_names" - ) - { - return; - } - }, - ItemKind::ExternCrate(..) => { - if is_word(lint, sym::unused_imports) && skip_unused_imports { - return; - } - if is_word(lint, sym::unused_extern_crates) { - return; - } - }, - _ => {}, - } + if namespace == Some(sym::clippy) + && matches!( + name.as_str(), + "wildcard_imports" + | "enum_glob_use" + | "redundant_pub_crate" + | "macro_use_imports" + | "unsafe_removed_from_name" + | "module_name_repetitions" + | "single_component_path_imports" + | "disallowed_types" + | "unused_trait_names" + ) + { + return; + } + }, + ItemKind::ExternCrate(..) => { + if is_word(lint, sym::unused_imports) && skip_unused_imports { + return; + } + if is_word(lint, sym::unused_extern_crates) { + return; + } + }, + _ => {}, } - let line_span = first_line_of_span(cx, attr.span); + } + let line_span = first_line_of_span(cx, attr.span); - if let Some(src) = line_span.get_source_text(cx) { - if src.contains("#[") { - #[expect(clippy::collapsible_span_lint_calls)] - span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| { - diag.span_suggestion( - line_span, - "if you just forgot a `!`, use", - src.replacen("#[", "#![", 1), - Applicability::MaybeIncorrect, - ); - }); - } - } + if let Some(src) = line_span.get_source_text(cx) + && src.contains("#[") + { + #[expect(clippy::collapsible_span_lint_calls)] + span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| { + diag.span_suggestion( + line_span, + "if you just forgot a `!`, use", + src.replacen("#[", "#![", 1), + Applicability::MaybeIncorrect, + ); + }); } } } diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 92a0c7f9acbc..52d1d5b4c67a 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -179,9 +179,14 @@ pub struct AwaitHolding { impl AwaitHolding { pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - Self { - def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types), - } + let (def_ids, _) = create_disallowed_map( + tcx, + &conf.await_holding_invalid_types, + crate::disallowed_types::def_kind_predicate, + "type", + false, + ); + Self { def_ids } } } @@ -192,10 +197,9 @@ impl<'tcx> LateLintPass<'tcx> for AwaitHolding { def_id, .. }) = expr.kind + && let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) { - if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) { - self.check_interior_types(cx, coroutine_layout); - } + self.check_interior_types(cx, coroutine_layout); } } } diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 612712d16843..129e77478406 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::HasSession; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_else_clause, is_in_const_context}; +use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -46,18 +47,25 @@ declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::If(cond, then, Some(else_)) = expr.kind - && matches!(cond.kind, ExprKind::DropTemps(_)) + if !expr.span.from_expansion() + && let Some(higher::If { + cond, + then, + r#else: Some(r#else), + }) = higher::If::hir(expr) && let Some(then_lit) = as_int_bool_lit(then) - && let Some(else_lit) = as_int_bool_lit(else_) + && let Some(else_lit) = as_int_bool_lit(r#else) && then_lit != else_lit - && !expr.span.from_expansion() && !is_in_const_context(cx) { let ty = cx.typeck_results().expr_ty(then); - let mut applicability = Applicability::MachineApplicable; + let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; let snippet = { - let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + let mut sugg = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability); if !then_lit { sugg = !sugg; } @@ -72,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { s }; - let into_snippet = snippet.clone().maybe_par(); + let into_snippet = snippet.clone().maybe_paren(); let as_snippet = snippet.as_ty(ty); span_lint_and_then( @@ -91,10 +99,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { } } -fn as_int_bool_lit(e: &Expr<'_>) -> Option { - if let ExprKind::Block(b, _) = e.kind +fn as_int_bool_lit(expr: &Expr<'_>) -> Option { + if let ExprKind::Block(b, _) = expr.kind && b.stmts.is_empty() && let Some(e) = b.expr + && !e.span.from_expansion() && let ExprKind::Lit(lit) = e.kind && let LitKind::Int(x, _) = lit.node { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 7bb5dbee126e..bc6ba84772b3 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -13,7 +13,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does @@ -242,11 +242,11 @@ struct Hir2Qmm<'a, 'tcx, 'v> { impl<'v> Hir2Qmm<'_, '_, 'v> { fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec) -> Result, String> { for a in a { - if let ExprKind::Binary(binop, lhs, rhs) = &a.kind { - if binop.node == op { - v = self.extract(op, &[lhs, rhs], v)?; - continue; - } + if let ExprKind::Binary(binop, lhs, rhs) = &a.kind + && binop.node == op + { + v = self.extract(op, &[lhs, rhs], v)?; + continue; } v.push(self.run(a)?); } @@ -349,9 +349,13 @@ impl SuggestContext<'_, '_, '_> { if let Some(str) = simplify_not(self.cx, self.msrv, terminal) { self.output.push_str(&str); } else { - self.output.push('!'); - self.output - .push_str(&Sugg::hir_opt(self.cx, terminal)?.maybe_par().to_string()); + let mut app = Applicability::MachineApplicable; + let snip = Sugg::hir_with_context(self.cx, terminal, SyntaxContext::root(), "", &mut app); + // Ignore the case If the expression is inside a macro expansion, or the default snippet is used + if app != Applicability::MachineApplicable { + return None; + } + self.output.push_str(&(!snip).to_string()); } }, True | False | Not(_) => { @@ -414,12 +418,12 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio let lhs_snippet = lhs.span.get_source_text(cx)?; let rhs_snippet = rhs.span.get_source_text(cx)?; - if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { - if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { - // e.g. `(a as u64) < b`. Without the parens the `<` is - // interpreted as a start of generic arguments for `u64` - return Some(format!("({lhs_snippet}){op}{rhs_snippet}")); - } + if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) + && let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) + { + // e.g. `(a as u64) < b`. Without the parens the `<` is + // interpreted as a start of generic arguments for `u64` + return Some(format!("({lhs_snippet}){op}{rhs_snippet}")); } Some(format!("{lhs_snippet}{op}{rhs_snippet}")) diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 8892a9e6b6b0..7cde007a9b66 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -2,7 +2,7 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; +use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -73,6 +73,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { } }) && !is_from_proc_macro(cx, e) + && let e_ty = cx.typeck_results().expr_ty_adjusted(e) + // check if the reference is coercing to a mutable reference + && (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target)) && let Some(deref_text) = deref_target.span.get_source_text(cx) { span_lint_and_then( @@ -90,10 +93,10 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { // has deref trait -> give 2 help // doesn't have deref trait -> give 1 help - if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() { - if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { - return; - } + if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() + && !implements_trait(cx, *inner_ty, deref_trait_id, &[]) + { + return; } diag.span_suggestion( diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 64345c81a248..ad0a4f8cdf35 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,11 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::Msrv; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::{is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core}; +use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, AutoBorrow}; use rustc_span::BytePos; use super::BORROW_AS_PTR; @@ -29,10 +30,6 @@ pub(super) fn check<'tcx>( } let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) { - let operator_kind = match mutability { - Mutability::Not => "const", - Mutability::Mut => "mut", - }; // Make sure that the span to be replaced doesn't include parentheses, that could break the // suggestion. let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) { @@ -42,7 +39,7 @@ pub(super) fn check<'tcx>( } else { expr.span }; - (format!("&raw {operator_kind} {snip}"), span) + (format!("&raw {} {snip}", mutability.ptr_str()), span) } else { let Some(std_or_core) = std_or_core(cx) else { return false; @@ -59,3 +56,25 @@ pub(super) fn check<'tcx>( } false } + +/// Check for an implicit cast from reference to raw pointer outside an explicit `as`. +pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) { + if !expr.span.from_expansion() + && let ExprKind::AddrOf(BorrowKind::Ref, _, pointee) = expr.kind + && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..))) + && let [deref, borrow] = cx.typeck_results().expr_adjustments(expr) + && matches!(deref.kind, Adjust::Deref(..)) + && let Adjust::Borrow(AutoBorrow::RawPtr(mutability)) = borrow.kind + // Do not suggest taking a raw pointer to a temporary value + && !is_expr_temporary_value(cx, pointee) + { + span_lint_and_then(cx, BORROW_AS_PTR, expr.span, "implicit borrow as raw pointer", |diag| { + diag.span_suggestion_verbose( + expr.span.until(pointee.span), + "use a raw pointer instead", + format!("&raw {} ", mutability.ptr_str()), + Applicability::MachineApplicable, + ); + }); + } +} diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 8b3529e84fc6..164d3540253a 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -36,7 +36,7 @@ pub(super) fn check( span, format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()), + format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_paren()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 3ae43732dc03..0f066fae1184 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -42,7 +42,7 @@ pub(super) fn check( diag.span_suggestion_verbose( expr.span, "use `Into::into` instead", - format!("{}.into()", from_sugg.maybe_par()), + format!("{}.into()", from_sugg.maybe_paren()), applicability, ); }, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index ca973f4bb1aa..8742f5f1a0e0 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -64,11 +64,11 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { - if method.ident.as_str() == "clamp" { + if method.ident.as_str() == "clamp" //FIXME: make this a diagnostic item - if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { - return lo_bits.max(hi_bits); - } + && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) + { + return lo_bits.max(hi_bits); } nbits }, @@ -185,7 +185,7 @@ fn offer_suggestion( ) { let cast_to_snip = snippet(cx, cast_to_span, ".."); let suggestion = if cast_to_snip == "_" { - format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_par()) + format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_paren()) } else { format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) }; diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 57a135abc2e2..3fca0f897077 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -19,16 +19,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind { - if method_path.ident.name.as_str() == "cast" - && let Some(generic_args) = method_path.args - && let [GenericArg::Type(cast_to)] = generic_args.args - // There probably is no obvious reason to do this, just to be consistent with `as` cases. - && !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty()) - { - let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); - lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } + } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind + && method_path.ident.name.as_str() == "cast" + && let Some(generic_args) = method_path.args + && let [GenericArg::Type(cast_to)] = generic_args.args + // There probably is no obvious reason to do this, just to be consistent with `as` cases. + && !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty()) + { + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); + lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index c48f253606dc..a5b295c88b1c 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -21,42 +21,41 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) start_ty, end_ty, }) = expr_cast_chain_tys(cx, expr) + && let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) { - if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) { - let from_size = from_layout.size.bytes(); - let to_size = to_layout.size.bytes(); - if from_size != to_size && from_size != 0 && to_size != 0 && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { - span_lint_and_then( - cx, - CAST_SLICE_DIFFERENT_SIZES, - expr.span, - format!( - "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", - start_ty.ty, end_ty.ty, - ), - |diag| { - let ptr_snippet = source::snippet(cx, left_cast.span, ".."); + let from_size = from_layout.size.bytes(); + let to_size = to_layout.size.bytes(); + if from_size != to_size && from_size != 0 && to_size != 0 && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { + span_lint_and_then( + cx, + CAST_SLICE_DIFFERENT_SIZES, + expr.span, + format!( + "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", + start_ty.ty, end_ty.ty, + ), + |diag| { + let ptr_snippet = source::snippet(cx, left_cast.span, ".."); - let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl { - Mutability::Mut => ("_mut", "mut"), - Mutability::Not => ("", "const"), - }; - let sugg = format!( - "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)", - // get just the ty from the TypeAndMut so that the printed type isn't something like `mut - // T`, extract just the `T` - end_ty.ty - ); + let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl { + Mutability::Mut => ("_mut", "mut"), + Mutability::Not => ("", "const"), + }; + let sugg = format!( + "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)", + // get just the ty from the TypeAndMut so that the printed type isn't something like `mut + // T`, extract just the `T` + end_ty.ty + ); - diag.span_suggestion( - expr.span, - format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), - sugg, - rustc_errors::Applicability::HasPlaceholders, - ); - }, - ); - } + diag.span_suggestion( + expr.span, + format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), + sugg, + rustc_errors::Applicability::HasPlaceholders, + ); + }, + ); } } } diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs new file mode 100644 index 000000000000..8ace27eca895 --- /dev/null +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -0,0 +1,82 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::ty::is_normalizable; +use clippy_utils::{expr_or_init, match_def_path, path_def_id, paths, std_or_core}; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::MANUAL_DANGLING_PTR; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>) { + if let TyKind::Ptr(ref ptr_ty) = to.kind { + let init_expr = expr_or_init(cx, from); + if is_expr_const_aligned(cx, init_expr, ptr_ty.ty) + && let Some(std_or_core) = std_or_core(cx) + { + let sugg_fn = match ptr_ty.mutbl { + Mutability::Not => "ptr::dangling", + Mutability::Mut => "ptr::dangling_mut", + }; + + let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind { + format!("{std_or_core}::{sugg_fn}()") + } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_source_text(cx) { + format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") + } else { + return; + }; + + span_lint_and_sugg( + cx, + MANUAL_DANGLING_PTR, + expr.span, + "manual creation of a dangling pointer", + "use", + sugg, + Applicability::MachineApplicable, + ); + } + } +} + +// Checks if the given expression is a call to `align_of` whose generic argument matches the target +// type, or a positive constant literal that matches the target type's alignment. +fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> bool { + match expr.kind { + ExprKind::Call(fun, _) => is_align_of_call(cx, fun, to), + ExprKind::Lit(lit) => is_literal_aligned(cx, lit, to), + _ => false, + } +} + +fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool { + if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind + && let Some(fun_id) = path_def_id(cx, fun) + && match_def_path(cx, fun_id, &paths::ALIGN_OF) + && let Some(args) = path.segments.last().and_then(|seg| seg.args) + && let [GenericArg::Type(generic_ty)] = args.args + { + let typeck = cx.typeck_results(); + return typeck.node_type(generic_ty.hir_id) == typeck.node_type(to.hir_id); + } + false +} + +fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned, to: &Ty<'_>) -> bool { + let LitKind::Int(val, _) = lit.node else { return false }; + if val == 0 { + return false; + } + let to_mid_ty = cx.typeck_results().node_type(to.hir_id); + is_normalizable(cx, cx.param_env, to_mid_ty) + && cx + .tcx + .layout_of(cx.typing_env().as_query_input(to_mid_ty)) + .is_ok_and(|layout| { + let align = u128::from(layout.align.abi.bytes()); + u128::from(val) <= align + }) +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index dc2a1fa85bf5..76931fce209e 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -17,6 +17,7 @@ mod char_lit_as_u8; mod fn_to_numeric_cast; mod fn_to_numeric_cast_any; mod fn_to_numeric_cast_with_truncation; +mod manual_dangling_ptr; mod ptr_as_ptr; mod ptr_cast_constness; mod ref_as_ptr; @@ -71,7 +72,7 @@ declare_clippy_lint! { /// ### Example /// ```no_run /// let y: i8 = -1; - /// y as u128; // will return 18446744073709551615 + /// y as u64; // will return 18446744073709551615 /// ``` #[clippy::version = "pre 1.29.0"] pub CAST_SIGN_LOSS, @@ -759,6 +760,32 @@ declare_clippy_lint! { "detects `as *mut _` and `as *const _` conversion" } +declare_clippy_lint! { + /// ### What it does + /// Checks for casts of small constant literals or `mem::align_of` results to raw pointers. + /// + /// ### Why is this bad? + /// This creates a dangling pointer and is better expressed as + /// {`std`, `core`}`::ptr::`{`dangling`, `dangling_mut`}. + /// + /// ### Example + /// ```no_run + /// let ptr = 4 as *const u32; + /// let aligned = std::mem::align_of::() as *const u32; + /// let mut_ptr: *mut i64 = 8 as *mut _; + /// ``` + /// Use instead: + /// ```no_run + /// let ptr = std::ptr::dangling::(); + /// let aligned = std::ptr::dangling::(); + /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); + /// ``` + #[clippy::version = "1.87.0"] + pub MANUAL_DANGLING_PTR, + style, + "casting small constant literals to pointers to create dangling pointers" +} + pub struct Casts { msrv: Msrv, } @@ -795,6 +822,7 @@ impl_lint_pass!(Casts => [ ZERO_PTR, REF_AS_PTR, AS_POINTER_UNDERSCORE, + MANUAL_DANGLING_PTR, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -823,6 +851,10 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to); zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir); + if self.msrv.meets(cx, msrvs::MANUAL_DANGLING_PTR) { + manual_dangling_ptr::check(cx, expr, cast_from_expr, cast_to_hir); + } + if cast_to.is_numeric() { cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { @@ -846,6 +878,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts { } } + if self.msrv.meets(cx, msrvs::RAW_REF_OP) { + borrow_as_ptr::check_implicit_cast(cx, expr); + } cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, self.msrv); diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index d57e391b55d5..6f944914b8fd 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -81,7 +81,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { ( "try `pointer::cast`, a safer alternative", - format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), + format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_paren()), ) }; diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index cad9c1df273f..2471c7355518 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -53,7 +53,8 @@ pub(super) fn check<'tcx>( } if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) { - let sugg = Sugg::hir(cx, cast_expr, "_"); + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, cast_expr, expr.span.ctxt(), "_", &mut app); let constness = match *to_mutbl { Mutability::Not => "const", Mutability::Mut => "mut", @@ -65,8 +66,8 @@ pub(super) fn check<'tcx>( expr.span, "`as` casting between raw pointers while changing only its constness", format!("try `pointer::cast_{constness}`, a safer alternative"), - format!("{}.cast_{constness}()", sugg.maybe_par()), - Applicability::MachineApplicable, + format!("{}.cast_{constness}()", sugg.maybe_paren()), + app, ); } } diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 72953818a708..ae994e94a32b 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -130,11 +130,11 @@ pub(super) fn check<'tcx>( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = cast_expr.span.get_source_text(cx) { - if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { - lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); - return true; - } + if let Some(src) = cast_expr.span.get_source_text(cx) + && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) + { + lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + return true; } }, _ => {}, diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index b36c8662289c..8ada608049c7 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -253,11 +253,11 @@ fn get_types_from_cast<'a>( match limit.kind { // `from_type::from(_)` ExprKind::Call(path, _) => { - if let ExprKind::Path(ref path) = path.kind { + if let ExprKind::Path(ref path) = path.kind // `to_type` - if let Some(to_type) = get_implementing_type(path, types, func) { - return Some((from_type, to_type)); - } + && let Some(to_type) = get_implementing_type(path, types, func) + { + return Some((from_type, to_type)); } }, // `to_type::MAX` diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index a1ff20dee721..1d44c7e9c88b 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -62,6 +62,7 @@ impl CognitiveComplexity { let mut cc = 1u64; let mut returns = 0u64; + let mut prev_expr: Option<&ExprKind<'tcx>> = None; let _: Option = for_each_expr_without_closures(expr, |e| { match e.kind { ExprKind::If(_, _, _) => { @@ -73,9 +74,14 @@ impl CognitiveComplexity { } cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; }, - ExprKind::Ret(_) => returns += 1, + ExprKind::Ret(_) => { + if !matches!(prev_expr, Some(ExprKind::Ret(_))) { + returns += 1; + } + }, _ => {}, } + prev_expr = Some(&e.kind); ControlFlow::Continue(()) }); diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index e73bfc6ebf7a..20fae8a6775b 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,10 +1,12 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability}; -use clippy_utils::sugg::Sugg; -use rustc_ast::ast; +use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability}; +use rustc_ast::BinOpKind; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::declare_lint_pass; +use rustc_hir::{Block, Expr, ExprKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -75,105 +77,152 @@ declare_clippy_lint! { "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)" } -declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); +pub struct CollapsibleIf { + let_chains_enabled: bool, + lint_commented_code: bool, +} -impl EarlyLintPass for CollapsibleIf { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let ast::ExprKind::If(cond, then, else_) = &expr.kind +impl CollapsibleIf { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { + Self { + let_chains_enabled: tcx.features().let_chains(), + lint_commented_code: conf.lint_commented_code, + } + } + + fn check_collapsible_else_if(cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) { + if !block_starts_with_comment(cx, else_block) + && let Some(else_) = expr_block(else_block) + && cx.tcx.hir_attrs(else_.hir_id).is_empty() + && !else_.span.from_expansion() + && let ExprKind::If(..) = else_.kind + { + // Prevent "elseif" + // Check that the "else" is followed by whitespace + let up_to_else = then_span.between(else_block.span); + let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { + !c.is_whitespace() + } else { + false + }; + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COLLAPSIBLE_ELSE_IF, + else_block.span, + "this `else { if .. }` block can be collapsed", + "collapse nested if block", + format!( + "{}{}", + if requires_space { " " } else { "" }, + snippet_block_with_applicability(cx, else_.span, "..", Some(else_block.span), &mut applicability) + ), + applicability, + ); + } + } + + fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check: &Expr<'_>, then: &Block<'_>) { + if let Some(inner) = expr_block(then) + && cx.tcx.hir_attrs(inner.hir_id).is_empty() + && let ExprKind::If(check_inner, _, None) = &inner.kind + && self.eligible_condition(check_inner) + && let ctxt = expr.span.ctxt() + && inner.span.ctxt() == ctxt + && (self.lint_commented_code || !block_starts_with_comment(cx, then)) + { + span_lint_and_then( + cx, + COLLAPSIBLE_IF, + expr.span, + "this `if` statement can be collapsed", + |diag| { + let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span(); + let then_closing_bracket = { + let end = then.span.shrink_to_hi(); + end.with_lo(end.lo() - rustc_span::BytePos(1)) + .with_leading_whitespace(cx) + .into_span() + }; + let inner_if = inner.span.split_at(2).0; + let mut sugg = vec![ + // Remove the outer then block `{` + (then_open_bracket, String::new()), + // Remove the outer then block '}' + (then_closing_bracket, String::new()), + // Replace inner `if` by `&&` + (inner_if, String::from("&&")), + ]; + sugg.extend(parens_around(check)); + sugg.extend(parens_around(check_inner)); + + diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable); + }, + ); + } + } + + pub fn eligible_condition(&self, cond: &Expr<'_>) -> bool { + self.let_chains_enabled || !matches!(cond.kind, ExprKind::Let(..)) + } +} + +impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); + +impl LateLintPass<'_> for CollapsibleIf { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::If(cond, then, else_) = &expr.kind && !expr.span.from_expansion() { - if let Some(else_) = else_ { - check_collapsible_maybe_if_let(cx, then.span, else_); - } else if !matches!(cond.kind, ast::ExprKind::Let(..)) { - check_collapsible_no_if_let(cx, expr, cond, then); + if let Some(else_) = else_ + && let ExprKind::Block(else_, None) = else_.kind + { + Self::check_collapsible_else_if(cx, then.span, else_); + } else if else_.is_none() + && self.eligible_condition(cond) + && let ExprKind::Block(then, None) = then.kind + { + self.check_collapsible_if_if(cx, expr, cond, then); } } } } -fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool { +fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool { // We trim all opening braces and whitespaces and then check if the next string is a comment. - let trimmed_block_text = snippet_block(cx, expr.span, "..", None) + let trimmed_block_text = snippet_block(cx, block.span, "..", None) .trim_start_matches(|c: char| c.is_whitespace() || c == '{') .to_owned(); trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*") } -fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: &ast::Expr) { - if let ast::ExprKind::Block(ref block, _) = else_.kind - && !block_starts_with_comment(cx, block) - && let Some(else_) = expr_block(block) - && else_.attrs.is_empty() - && !else_.span.from_expansion() - && let ast::ExprKind::If(..) = else_.kind - { - // Prevent "elseif" - // Check that the "else" is followed by whitespace - let up_to_else = then_span.between(block.span); - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { - !c.is_whitespace() - } else { - false - }; - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - COLLAPSIBLE_ELSE_IF, - block.span, - "this `else { if .. }` block can be collapsed", - "collapse nested if block", - format!( - "{}{}", - if requires_space { " " } else { "" }, - snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability) - ), - applicability, - ); +/// If `block` is a block with either one expression or a statement containing an expression, +/// return the expression. We don't peel blocks recursively, as extra blocks might be intentional. +fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { + match block.stmts { + [] => block.expr, + [stmt] => { + if let StmtKind::Semi(expr) = stmt.kind { + Some(expr) + } else { + None + } + }, + _ => None, } } -fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) { - if !block_starts_with_comment(cx, then) - && let Some(inner) = expr_block(then) - && inner.attrs.is_empty() - && let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind - // Prevent triggering on `if c { if let a = b { .. } }`. - && !matches!(check_inner.kind, ast::ExprKind::Let(..)) - && let ctxt = expr.span.ctxt() - && inner.span.ctxt() == ctxt +/// If the expression is a `||`, suggest parentheses around it. +fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { + if let ExprKind::Binary(op, _, _) = expr.peel_drop_temps().kind + && op.node == BinOpKind::Or { - span_lint_and_then( - cx, - COLLAPSIBLE_IF, - expr.span, - "this `if` statement can be collapsed", - |diag| { - let mut app = Applicability::MachineApplicable; - let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app); - let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app); - diag.span_suggestion( - expr.span, - "collapse nested if block", - format!( - "if {} {}", - lhs.and(&rhs), - snippet_block(cx, content.span, "..", Some(expr.span)), - ), - app, // snippet - ); - }, - ); - } -} - -/// If the block contains only one expression, return it. -fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { - if let [stmt] = &*block.stmts - && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind - { - Some(expr) + vec![ + (expr.span.shrink_to_lo(), String::from("(")), + (expr.span.shrink_to_hi(), String::from(")")), + ] } else { - None + vec![] } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 0e7f01e44b04..9c3009a86cdc 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else { unreachable!(); }; - let lhs = Sugg::hir(cx, lhs, "..").maybe_par(); + let lhs = Sugg::hir(cx, lhs, "..").maybe_paren(); let rhs = Sugg::hir(cx, rhs, "..").addr(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 03ed9c657b30..42fbe6438d4e 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -256,7 +256,7 @@ fn lint_branches_sharing_code<'tcx>( let suggestion = reindent_multiline(&suggestion, true, indent); let span = span.with_hi(last_block.span.hi()); - // Improve formatting if the inner block has indention (i.e. normal Rust formatting) + // Improve formatting if the inner block has indentation (i.e. normal Rust formatting) let span = span .map_range(cx, |src, range| { (range.start > 4 && src.get(range.start - 4..range.start)? == " ") @@ -539,10 +539,10 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo .filter(|stmt| !ignore_span.overlaps(stmt.span)) .try_for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt)); - if let Some(expr) = block.expr { - if res.is_continue() { - res = intravisit::walk_expr(&mut walker, expr); - } + if let Some(expr) = block.expr + && res.is_continue() + { + res = intravisit::walk_expr(&mut walker, expr); } res.is_break() diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs index 4d908af4084f..9f82f8767279 100644 --- a/clippy_lints/src/declare_clippy_lint.rs +++ b/clippy_lints/src/declare_clippy_lint.rs @@ -165,17 +165,4 @@ macro_rules! declare_clippy_lint { $(, $eval_always)? } }; - - ( - $(#[doc = $lit:literal])* - pub $lint_name:ident, - internal, - $desc:literal - ) => { - declare_clippy_lint! {@ - $(#[doc = $lit])* - pub $lint_name, Allow, crate::LintCategory::Internal, $desc, - None, "0.0.0" - } - }; } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 39e451637070..2cccd6ba2702 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -3,36 +3,6 @@ // Manual edits will be overwritten. pub static LINTS: &[&crate::LintInfo] = &[ - #[cfg(feature = "internal")] - crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, crate::absolute_paths::ABSOLUTE_PATHS_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, @@ -52,6 +22,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::DUPLICATED_ATTRIBUTES_INFO, + crate::attrs::IGNORE_WITHOUT_REASON_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, @@ -96,6 +67,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::casts::FN_TO_NUMERIC_CAST_INFO, crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO, crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO, + crate::casts::MANUAL_DANGLING_PTR_INFO, crate::casts::PTR_AS_PTR_INFO, crate::casts::PTR_CAST_CONSTNESS_INFO, crate::casts::REF_AS_PTR_INFO, @@ -286,6 +258,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::literal_representation::UNREADABLE_LITERAL_INFO, crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO, crate::literal_string_with_formatting_args::LITERAL_STRING_WITH_FORMATTING_ARGS_INFO, + crate::loops::CHAR_INDICES_AS_BYTE_INDICES_INFO, crate::loops::EMPTY_LOOP_INFO, crate::loops::EXPLICIT_COUNTER_LOOP_INFO, crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, @@ -312,6 +285,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::macro_metavars_in_unsafe::MACRO_METAVARS_IN_UNSAFE_INFO, crate::macro_use::MACRO_USE_IMPORTS_INFO, crate::main_recursion::MAIN_RECURSION_INFO, + crate::manual_abs_diff::MANUAL_ABS_DIFF_INFO, crate::manual_assert::MANUAL_ASSERT_INFO, crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, @@ -334,7 +308,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, - crate::manual_unwrap_or_default::MANUAL_UNWRAP_OR_DEFAULT_INFO, crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO, crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO, crate::match_result_ok::MATCH_RESULT_OK_INFO, @@ -344,10 +317,10 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::matches::MANUAL_MAP_INFO, crate::matches::MANUAL_OK_ERR_INFO, crate::matches::MANUAL_UNWRAP_OR_INFO, + crate::matches::MANUAL_UNWRAP_OR_DEFAULT_INFO, crate::matches::MATCH_AS_REF_INFO, crate::matches::MATCH_BOOL_INFO, crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO, - crate::matches::MATCH_ON_VEC_ITEMS_INFO, crate::matches::MATCH_OVERLAPPING_ARM_INFO, crate::matches::MATCH_REF_PATS_INFO, crate::matches::MATCH_SAME_ARMS_INFO, @@ -488,6 +461,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::SUSPICIOUS_OPEN_OPTIONS_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, + crate::methods::SWAP_WITH_TEMPORARY_INFO, crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNBUFFERED_BYTES_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, @@ -664,6 +638,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::DEREF_BY_SLICING_INFO, crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, + crate::redundant_test_prefix::REDUNDANT_TEST_PREFIX_INFO, crate::redundant_type_annotations::REDUNDANT_TYPE_ANNOTATIONS_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, crate::ref_patterns::REF_PATTERNS_INFO, diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index bbd5dc15542d..f8a9037fc804 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,5 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_ty_alias; +use clippy_utils::source::SpanRangeExt as _; use hir::ExprKind; use hir::def::Res; use rustc_errors::Applicability; @@ -70,15 +71,26 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { && let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant() && !var.is_field_list_non_exhaustive() && !expr.span.from_expansion() && !qpath.span().from_expansion() + // do not suggest replacing an expression by a type name with placeholders + && !base.is_suggestable_infer_ty() { - span_lint_and_sugg( + let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())]; + if expr.span.with_source_text(cx, |s| s.starts_with('<')) == Some(true) { + // Remove `<`, '>` has already been removed by the existing removal expression. + removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new())); + } + span_lint_and_then( cx, DEFAULT_CONSTRUCTED_UNIT_STRUCTS, - expr.span.with_lo(qpath.qself_span().hi()), + expr.span, "use of `default` to create a unit struct", - "remove this call to `default`", - String::new(), - Applicability::MachineApplicable, + |diag| { + diag.multipart_suggestion( + "remove this call to `default`", + removals, + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index de66ead4f420..b60c11d79d48 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -42,6 +42,8 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "1.86.0"] ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), + #[clippy::version = "1.86.0"] + ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), // end deprecated lints. used by `cargo dev deprecate_lint` ]} diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 849c60b89b97..7da5a530eaa3 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1133,61 +1133,60 @@ fn report<'tcx>( impl<'tcx> Dereferencing<'tcx> { fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) { - if let Some(outer_pat) = self.ref_locals.get_mut(&local) { - if let Some(pat) = outer_pat { - // Check for auto-deref - if !matches!( - cx.typeck_results().expr_adjustments(e), - [ - Adjustment { - kind: Adjust::Deref(_), - .. - }, - Adjustment { - kind: Adjust::Deref(_), - .. - }, + if let Some(outer_pat) = self.ref_locals.get_mut(&local) + && let Some(pat) = outer_pat + // Check for auto-deref + && !matches!( + cx.typeck_results().expr_adjustments(e), + [ + Adjustment { + kind: Adjust::Deref(_), .. - ] - ) { - match get_parent_expr(cx, e) { - // Field accesses are the same no matter the number of references. - Some(Expr { - kind: ExprKind::Field(..), - .. - }) => (), - Some(&Expr { - span, - kind: ExprKind::Unary(UnOp::Deref, _), - .. - }) if !span.from_expansion() => { - // Remove explicit deref. - let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((span, snip.into())); - }, - Some(parent) if !parent.span.from_expansion() => { - // Double reference might be needed at this point. - if parent.precedence() == ExprPrecedence::Unambiguous { - // Parentheses would be needed here, don't lint. - *outer_pat = None; - } else { - pat.always_deref = false; - let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((e.span, format!("&{snip}"))); - } - }, - _ if !e.span.from_expansion() => { - // Double reference might be needed at this point. - pat.always_deref = false; - let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); - pat.replacements.push((e.span, format!("&{snip}"))); - }, - // Edge case for macros. The span of the identifier will usually match the context of the - // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc - // macros - _ => *outer_pat = None, + }, + Adjustment { + kind: Adjust::Deref(_), + .. + }, + .. + ] + ) + { + match get_parent_expr(cx, e) { + // Field accesses are the same no matter the number of references. + Some(Expr { + kind: ExprKind::Field(..), + .. + }) => (), + Some(&Expr { + span, + kind: ExprKind::Unary(UnOp::Deref, _), + .. + }) if !span.from_expansion() => { + // Remove explicit deref. + let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0; + pat.replacements.push((span, snip.into())); + }, + Some(parent) if !parent.span.from_expansion() => { + // Double reference might be needed at this point. + if parent.precedence() == ExprPrecedence::Unambiguous { + // Parentheses would be needed here, don't lint. + *outer_pat = None; + } else { + pat.always_deref = false; + let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; + pat.replacements.push((e.span, format!("&{snip}"))); } - } + }, + _ if !e.span.from_expansion() => { + // Double reference might be needed at this point. + pat.always_deref = false; + let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); + pat.replacements.push((e.span, format!("&{snip}"))); + }, + // Edge case for macros. The span of the identifier will usually match the context of the + // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc + // macros + _ => *outer_pat = None, } } } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 8d9222e4bf61..10331b3855b8 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -94,18 +94,18 @@ fn check_struct<'tcx>( ty_args: GenericArgsRef<'_>, typeck_results: &'tcx TypeckResults<'tcx>, ) { - if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { - if let Some(PathSegment { args, .. }) = p.segments.last() { - let args = args.map(|a| a.args).unwrap_or(&[]); + if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind + && let Some(PathSegment { args, .. }) = p.segments.last() + { + let args = args.map(|a| a.args).unwrap_or(&[]); - // ty_args contains the generic parameters of the type declaration, while args contains the - // arguments used at instantiation time. If both len are not equal, it means that some - // parameters were not provided (which means that the default values were used); in this - // case we will not risk suggesting too broad a rewrite. We won't either if any argument - // is a type or a const. - if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) { - return; - } + // ty_args contains the generic parameters of the type declaration, while args contains the + // arguments used at instantiation time. If both len are not equal, it means that some + // parameters were not provided (which means that the default values were used); in this + // case we will not risk suggesting too broad a rewrite. We won't either if any argument + // is a type or a const. + if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) { + return; } } @@ -188,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { self_ty, .. }) = item.kind - && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) + && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) && !item.span.from_expansion() && let Some(def_id) = trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::Default, def_id) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index c85aca8d04ef..06528f875a29 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { }) = item.kind { let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived); + let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id()); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); @@ -235,7 +235,7 @@ fn check_hash_peq<'tcx>( { // Look for the PartialEq implementations for `ty` cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { - let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id); if !hash_is_automatically_derived || peq_is_automatically_derived { return; @@ -278,7 +278,7 @@ fn check_ord_partial_ord<'tcx>( { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { - let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id); if partial_ord_is_automatically_derived == ord_is_automatically_derived { return; @@ -349,6 +349,10 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h { return; } + // The presence of `unsafe` fields prevents deriving `Clone` automatically + if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) { + return; + } span_lint_and_note( cx, @@ -426,10 +430,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result { - if let ExprKind::Block(block, _) = expr.kind { - if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { - return ControlFlow::Break(()); - } + if let ExprKind::Block(block, _) = expr.kind + && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + { + return ControlFlow::Break(()); } walk_expr(self, expr) @@ -479,7 +483,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some() } -/// Creates the `ParamEnv` used for the give type's derived `Eq` impl. +/// Creates the `ParamEnv` used for the given type's derived `Eq` impl. fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { // Initial map from generic index to param def. // Vec<(param_def, needs_eq)> diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 4b8a689e9947..fc6af204a74a 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -4,6 +4,7 @@ use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_hir::{ AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, @@ -72,8 +73,15 @@ pub struct DisallowedMacros { impl DisallowedMacros { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self { + let (disallowed, _) = create_disallowed_map( + tcx, + &conf.disallowed_macros, + |def_kind| matches!(def_kind, DefKind::Macro(_)), + "macro", + false, + ); Self { - disallowed: create_disallowed_map(tcx, &conf.disallowed_macros), + disallowed, seen: FxHashSet::default(), derive_src: None, earlies, diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 149cf1cf2def..1382dafa931e 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -63,9 +63,19 @@ pub struct DisallowedMethods { impl DisallowedMethods { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - Self { - disallowed: create_disallowed_map(tcx, &conf.disallowed_methods), - } + let (disallowed, _) = create_disallowed_map( + tcx, + &conf.disallowed_methods, + |def_kind| { + matches!( + def_kind, + DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn + ) + }, + "function", + false, + ); + Self { disallowed } } } @@ -74,12 +84,7 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (id, span) = match &expr.kind { - ExprKind::Path(path) - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = - cx.qpath_res(path, expr.hir_id) => - { - (id, expr.span) - }, + ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span), ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { (id, name.ident.span) }, diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 38903596414c..2bae82648ac7 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; -use clippy_config::types::DisallowedPath; +use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -60,22 +60,7 @@ pub struct DisallowedTypes { impl DisallowedTypes { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let mut def_ids = DefIdMap::default(); - let mut prim_tys = FxHashMap::default(); - for disallowed_path in &conf.disallowed_types { - let path: Vec<_> = disallowed_path.path().split("::").collect::>(); - for res in clippy_utils::def_path_res(tcx, &path) { - match res { - Res::Def(_, id) => { - def_ids.insert(id, (disallowed_path.path(), disallowed_path)); - }, - Res::PrimTy(ty) => { - prim_tys.insert(ty, (disallowed_path.path(), disallowed_path)); - }, - _ => {}, - } - } - } + let (def_ids, prim_tys) = create_disallowed_map(tcx, &conf.disallowed_types, def_kind_predicate, "type", true); Self { def_ids, prim_tys } } @@ -95,6 +80,19 @@ impl DisallowedTypes { } } +pub fn def_kind_predicate(def_kind: DefKind) -> bool { + matches!( + def_kind, + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::AssocTy + ) +} + impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 8cdaba88e509..7a1c7c675d2e 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -113,20 +113,20 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b s != "-" && s.contains('-') } - if let Ok(url) = Url::parse(word) { + if let Ok(url) = Url::parse(word) // try to get around the fact that `foo::bar` parses as a valid URL - if !url.cannot_be_a_base() { - span_lint_and_sugg( - cx, - DOC_MARKDOWN, - span, - "you should put bare URLs between `<`/`>` or make a proper Markdown link", - "try", - format!("<{word}>"), - Applicability::MachineApplicable, - ); - return; - } + && !url.cannot_be_a_base() + { + span_lint_and_sugg( + cx, + DOC_MARKDOWN, + span, + "you should put bare URLs between `<`/`>` or make a proper Markdown link", + "try", + format!("<{word}>"), + Applicability::MachineApplicable, + ); + return; } // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index e75abf28bace..039937e0207b 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -1,11 +1,14 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; -use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item}; -use clippy_utils::{is_doc_hidden, return_ty}; +use clippy_utils::macros::{is_panic, root_macro_call_first_node}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{fulfill_or_allowed, is_doc_hidden, method_chain_args, return_ty}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::{Span, sym}; +use std::ops::ControlFlow; pub fn check( cx: &LateContext<'_>, @@ -13,7 +16,6 @@ pub fn check( sig: FnSig<'_>, headers: DocHeaders, body_id: Option, - panic_info: Option<(Span, bool)>, check_private_items: bool, ) { if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) { @@ -46,13 +48,16 @@ pub fn check( ), _ => (), } - if !headers.panics && panic_info.is_some_and(|el| !el.1) { + if !headers.panics + && let Some(body_id) = body_id + && let Some(panic_span) = find_panic(cx, body_id) + { span_lint_and_note( cx, MISSING_PANICS_DOC, span, "docs for function which may panic missing `# Panics` section", - panic_info.map(|el| el.0), + Some(panic_span), "first possible panic found here", ); } @@ -89,3 +94,39 @@ pub fn check( } } } + +fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option { + let mut panic_span = None; + let typeck = cx.tcx.typeck_body(body_id); + for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && (is_panic(cx, macro_call.def_id) + || matches!( + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro) + )) + && !cx.tcx.hir_is_inside_const_context(expr.hir_id) + && !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id]) + && panic_span.is_none() + { + panic_span = Some(macro_call.span); + } + + // check for `unwrap` and `expect` for both `Option` and `Result` + if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"])) + && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs() + && matches!( + get_type_diagnostic_name(cx, receiver_ty), + Some(sym::Option | sym::Result) + ) + && !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id]) + && panic_span.is_none() + { + panic_span = Some(expr.span); + } + + // Visit all nodes to fulfill any `#[expect]`s after the first linted panic + ControlFlow::::Continue(()) + }); + panic_span +} diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 36fd396cc1df..ab77edf1147c 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -3,11 +3,8 @@ use clippy_config::Conf; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; -use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::Visitable; -use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args}; +use clippy_utils::{is_entrypoint_fn, is_trait_impl_item}; use pulldown_cmark::Event::{ Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, @@ -16,18 +13,15 @@ use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, It use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; +use rustc_hir::{Attribute, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -use rustc_middle::hir::nested_filter; -use rustc_middle::ty; use rustc_resolve::rustdoc::{ DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, }; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::edition::Edition; -use rustc_span::{Span, sym}; use std::ops::Range; use url::Url; @@ -194,6 +188,19 @@ declare_clippy_lint! { /// } /// } /// ``` + /// + /// Individual panics within a function can be ignored with `#[expect]` or + /// `#[allow]`: + /// + /// ```no_run + /// # use std::num::NonZeroUsize; + /// pub fn will_not_panic(x: usize) { + /// #[expect(clippy::missing_panics_doc, reason = "infallible")] + /// let y = NonZeroUsize::new(1).unwrap(); + /// + /// // If any panics are added in the future the lint will still catch them + /// } + /// ``` #[clippy::version = "1.51.0"] pub MISSING_PANICS_DOC, pedantic, @@ -657,20 +664,16 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { self.check_private_items, ); match item.kind { - ItemKind::Fn { sig, body: body_id, .. } => { + ItemKind::Fn { sig, body, .. } => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || item.span.in_external_macro(cx.tcx.sess.source_map())) { - let body = cx.tcx.hir_body(body_id); - - let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); missing_headers::check( cx, item.owner_id, sig, headers, - Some(body_id), - panic_info, + Some(body), self.check_private_items, ); } @@ -697,15 +700,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { if let TraitItemKind::Fn(sig, ..) = trait_item.kind && !trait_item.span.in_external_macro(cx.tcx.sess.source_map()) { - missing_headers::check( - cx, - trait_item.owner_id, - sig, - headers, - None, - None, - self.check_private_items, - ); + missing_headers::check(cx, trait_item.owner_id, sig, headers, None, self.check_private_items); } }, Node::ImplItem(impl_item) => { @@ -713,16 +708,12 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { && !impl_item.span.in_external_macro(cx.tcx.sess.source_map()) && !is_trait_impl_item(cx, impl_item.hir_id()) { - let body = cx.tcx.hir_body(body_id); - - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value); missing_headers::check( cx, impl_item.owner_id, sig, headers, Some(body_id), - panic_span, self.check_private_items, ); } @@ -880,19 +871,18 @@ fn check_for_code_clusters<'a, Events: Iterator{}", doc[start..end].replace('`', "")); - diag.span_suggestion_verbose( - span, - "wrap the entire group in `` tags", - sugg, - Applicability::MaybeIncorrect, - ); - diag.help("separate code snippets will be shown with a gap"); - }); - } + span_lint_and_then(cx, DOC_LINK_CODE, span, "code link adjacent to code text", |diag| { + let sugg = format!("{}", doc[start..end].replace('`', "")); + diag.span_suggestion_verbose( + span, + "wrap the entire group in `` tags", + sugg, + Applicability::MaybeIncorrect, + ); + diag.help("separate code snippets will be shown with a gap"); + }); } code_includes_link = false; code_starts_at = None; @@ -1169,72 +1159,6 @@ fn check_doc<'a, Events: Iterator, Range { - cx: &'a LateContext<'tcx>, - is_const: bool, - panic_span: Option, - typeck_results: &'tcx ty::TypeckResults<'tcx>, -} - -impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { - pub fn find_span( - cx: &'a LateContext<'tcx>, - typeck_results: &'tcx ty::TypeckResults<'tcx>, - body: impl Visitable<'tcx>, - ) -> Option<(Span, bool)> { - let mut vis = Self { - cx, - is_const: false, - panic_span: None, - typeck_results, - }; - body.visit(&mut vis); - vis.panic_span.map(|el| (el, vis.is_const)) - } -} - -impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.panic_span.is_some() { - return; - } - - if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) { - if is_panic(self.cx, macro_call.def_id) - || matches!( - self.cx.tcx.item_name(macro_call.def_id).as_str(), - "assert" | "assert_eq" | "assert_ne" - ) - { - self.is_const = self.cx.tcx.hir_is_inside_const_context(expr.hir_id); - self.panic_span = Some(macro_call.span); - } - } - - // check for `unwrap` and `expect` for both `Option` and `Result` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or(method_chain_args(expr, &["expect"])) { - let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) - || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) - { - self.panic_span = Some(expr.span); - } - } - - // and check sub-expressions - intravisit::walk_expr(self, expr); - } - - // Panics in const blocks will cause compilation to fail. - fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.cx.tcx - } -} - #[expect(clippy::range_plus_one)] // inclusive ranges aren't the same type fn looks_like_refdef(doc: &str, range: Range) -> Option> { if range.end < range.start { diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index bf549dcdb506..ec4538039a91 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -64,7 +64,10 @@ pub fn check( match parser.parse_item(ForceCollect::No) { Ok(Some(item)) => match &item.kind { ItemKind::Fn(box Fn { - ident, sig, body: Some(block), .. + ident, + sig, + body: Some(block), + .. }) if ident.name == sym::main => { if !ignore { get_test_spans(&item, *ident, &mut test_attr_spans); diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 617982f4da30..5c360ce6a5f7 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -144,10 +144,10 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { // .. // } fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool { - if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { - if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) { - return body.hir_id == drop_expr.hir_id; - } + if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) + && let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) + { + return body.hir_id == drop_expr.hir_id; } false } diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index c67dcd3c82b5..0c5f8bbf4ca5 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, snippet_indent}; use clippy_utils::tokenize_with_text; @@ -89,7 +91,7 @@ declare_clippy_lint! { #[derive(Debug)] struct ItemInfo { kind: &'static str, - name: Symbol, + name: Option, span: Span, mod_items: Option, } @@ -315,8 +317,12 @@ impl EmptyLineAfter { for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) { stop.comment_out(cx, &mut suggestions); } + let name = match info.name { + Some(name) => format!("{} `{name}`", info.kind).into(), + None => Cow::from("the following item"), + }; diag.multipart_suggestion_verbose( - format!("if the doc comment should not document `{}` comment it out", info.name), + format!("if the doc comment should not document {name} then comment it out"), suggestions, Applicability::MaybeIncorrect, ); @@ -381,13 +387,10 @@ impl EmptyLineAfter { ) { self.items.push(ItemInfo { kind: kind.descr(), - // FIXME: this `sym::empty` can be leaked, see - // https://github.com/rust-lang/rust/pull/138740#discussion_r2021979899 - name: if let Some(ident) = ident { ident.name } else { kw::Empty }, - span: if let Some(ident) = ident { - span.with_hi(ident.span.hi()) - } else { - span.with_hi(span.lo()) + name: ident.map(|ident| ident.name), + span: match ident { + Some(ident) => span.with_hi(ident.span.hi()), + None => span.shrink_to_lo(), }, mod_items: match kind { ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items @@ -447,7 +450,7 @@ impl EarlyLintPass for EmptyLineAfter { fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) { self.items.push(ItemInfo { kind: "crate", - name: kw::Crate, + name: Some(kw::Crate), span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()), mod_items: krate .items diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index 7d87f04fef9d..a38d6df89f2b 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,10 +1,15 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Item, ItemKind, Variant, VariantData}; +use clippy_utils::attrs::span_contains_cfg; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; -use rustc_lexer::TokenKind; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::declare_lint_pass; +use rustc_hir::def::CtorOf; +use rustc_hir::def::DefKind::Ctor; +use rustc_hir::def::Res::Def; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Path, QPath, Variant, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -70,10 +75,23 @@ declare_clippy_lint! { "finds enum variants with empty brackets" } -declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]); +#[derive(Debug)] +enum Usage { + Unused { redundant_use_sites: Vec }, + Used, + NoDefinition { redundant_use_sites: Vec }, +} -impl EarlyLintPass for EmptyWithBrackets { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { +#[derive(Default)] +pub struct EmptyWithBrackets { + // Value holds `Usage::Used` if the empty tuple variant was used as a function + empty_tuple_enum_variants: FxIndexMap, +} + +impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]); + +impl LateLintPass<'_> for EmptyWithBrackets { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Struct(ident, var_data, _) = &item.kind && has_brackets(var_data) && let span_after_ident = item.span.with_lo(ident.span.hi()) @@ -96,70 +114,175 @@ impl EarlyLintPass for EmptyWithBrackets { } } - fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) { + fn check_variant(&mut self, cx: &LateContext<'_>, variant: &Variant<'_>) { + // the span of the parentheses/braces let span_after_ident = variant.span.with_lo(variant.ident.span.hi()); - if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) { - span_lint_and_then( + if has_no_fields(cx, &variant.data, span_after_ident) { + match variant.data { + VariantData::Struct { .. } => { + // Empty struct variants can be linted immediately + span_lint_and_then( + cx, + EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + span_after_ident, + "enum variant has empty brackets", + |diagnostic| { + diagnostic.span_suggestion_hidden( + span_after_ident, + "remove the brackets", + "", + Applicability::MaybeIncorrect, + ); + }, + ); + }, + VariantData::Tuple(.., local_def_id) => { + // Don't lint reachable tuple enums + if cx.effective_visibilities.is_reachable(variant.def_id) { + return; + } + if let Some(entry) = self.empty_tuple_enum_variants.get_mut(&local_def_id) { + // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before the + // definition was encountered. Now that there's a definition, convert it + // to Usage::Unused. + if let Usage::NoDefinition { redundant_use_sites } = entry { + *entry = Usage::Unused { + redundant_use_sites: redundant_use_sites.clone(), + }; + } + } else { + self.empty_tuple_enum_variants.insert( + local_def_id, + Usage::Unused { + redundant_use_sites: vec![], + }, + ); + } + }, + VariantData::Unit(..) => {}, + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let Some(def_id) = check_expr_for_enum_as_function(expr) { + if let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) { + // Do not count expressions from macro expansion as a redundant use site. + if expr.span.from_expansion() { + return; + } + match self.empty_tuple_enum_variants.get_mut(&def_id) { + Some( + &mut (Usage::Unused { + ref mut redundant_use_sites, + } + | Usage::NoDefinition { + ref mut redundant_use_sites, + }), + ) => { + redundant_use_sites.push(parentheses_span); + }, + None => { + // The variant isn't in the IndexMap which means its definition wasn't encountered yet. + self.empty_tuple_enum_variants.insert( + def_id, + Usage::NoDefinition { + redundant_use_sites: vec![parentheses_span], + }, + ); + }, + _ => {}, + } + } else { + // The parentheses are not redundant. + self.empty_tuple_enum_variants.insert(def_id, Usage::Used); + } + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'_>) { + for (local_def_id, usage) in &self.empty_tuple_enum_variants { + // Ignore all variants with Usage::Used or Usage::NoDefinition + let Usage::Unused { redundant_use_sites } = usage else { + continue; + }; + // Attempt to fetch the Variant from LocalDefId. + let Node::Variant(variant) = cx.tcx.hir_node( + cx.tcx + .local_def_id_to_hir_id(cx.tcx.parent(local_def_id.to_def_id()).expect_local()), + ) else { + continue; + }; + // Span of the parentheses in variant definition + let span = variant.span.with_lo(variant.ident.span.hi()); + span_lint_hir_and_then( cx, EMPTY_ENUM_VARIANTS_WITH_BRACKETS, - span_after_ident, + variant.hir_id, + span, "enum variant has empty brackets", |diagnostic| { - diagnostic.span_suggestion_hidden( - span_after_ident, - "remove the brackets", - "", - Applicability::MaybeIncorrect, - ); + if redundant_use_sites.is_empty() { + // If there's no redundant use sites, the definition is the only place to modify. + diagnostic.span_suggestion_hidden( + span, + "remove the brackets", + "", + Applicability::MaybeIncorrect, + ); + } else { + let mut parentheses_spans: Vec<_> = + redundant_use_sites.iter().map(|span| (*span, String::new())).collect(); + parentheses_spans.push((span, String::new())); + diagnostic.multipart_suggestion( + "remove the brackets", + parentheses_spans, + Applicability::MaybeIncorrect, + ); + } }, ); } } } -fn has_no_ident_token(braces_span_str: &str) -> bool { - !rustc_lexer::tokenize(braces_span_str).any(|t| t.kind == TokenKind::Ident) +fn has_brackets(var_data: &VariantData<'_>) -> bool { + !matches!(var_data, VariantData::Unit(..)) } -fn has_brackets(var_data: &VariantData) -> bool { - !matches!(var_data, VariantData::Unit(_)) -} - -fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Span) -> bool { - if !var_data.fields().is_empty() { - return false; - } - +fn has_no_fields(cx: &LateContext<'_>, var_data: &VariantData<'_>, braces_span: Span) -> bool { + var_data.fields().is_empty() && // there might still be field declarations hidden from the AST // (conditionally compiled code using #[cfg(..)]) - - let Some(braces_span_str) = snippet_opt(cx, braces_span) else { - return false; - }; - - has_no_ident_token(braces_span_str.as_ref()) + !span_contains_cfg(cx, braces_span) } -#[cfg(test)] -mod unit_test { - use super::*; - - #[test] - fn test_has_no_ident_token() { - let input = "{ field: u8 }"; - assert!(!has_no_ident_token(input)); - - let input = "(u8, String);"; - assert!(!has_no_ident_token(input)); - - let input = " { - // test = 5 - } - "; - assert!(has_no_ident_token(input)); - - let input = " ();"; - assert!(has_no_ident_token(input)); +// If expression HIR ID and callee HIR ID are same, returns the span of the parentheses, else, +// returns None. +fn call_parentheses_span(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option { + if let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id) + && let ExprKind::Call(callee, ..) = parent.kind + && callee.hir_id == expr.hir_id + { + Some(parent.span.with_lo(expr.span.hi())) + } else { + None + } +} + +// Returns the LocalDefId of the variant being called as a function if it exists. +fn check_expr_for_enum_as_function(expr: &Expr<'_>) -> Option { + if let ExprKind::Path(QPath::Resolved( + _, + Path { + res: Def(Ctor(CtorOf::Variant, _), def_id), + .. + }, + )) = expr.kind + { + def_id.as_local() + } else { + None } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index dcfee0b6d3c6..182cb4e46d2b 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -95,14 +95,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { return; }; - if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy { - span_lint(cx, MAP_ENTRY, expr.span, lint_msg); - return; - } - if then_search.edits.is_empty() && else_search.edits.is_empty() { // No insertions return; + } else if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy { + // If there are other uses of the key, and the key is not copy, + // we cannot perform a fix automatically, but continue to emit a lint. + None } else if then_search.edits.is_empty() || else_search.edits.is_empty() { // if .. { insert } else { .. } or if .. { .. } else { insert } let ((then_str, entry_kind), else_str) = match (else_search.edits.is_empty(), contains_expr.negated) { @@ -123,10 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app), ), }; - format!( + Some(format!( "if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}", map_ty.entry_path(), - ) + )) } else { // if .. { insert } else { insert } let ((then_str, then_entry), (else_str, else_entry)) = if contains_expr.negated { @@ -142,13 +141,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { }; let indent_str = snippet_indent(cx, expr.span); let indent_str = indent_str.as_deref().unwrap_or(""); - format!( + Some(format!( "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\ {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}", reindent_multiline(&then_str, true, Some(4 + indent_str.len())), reindent_multiline(&else_str, true, Some(4 + indent_str.len())), entry = map_ty.entry_path(), - ) + )) } } else { if then_search.edits.is_empty() { @@ -163,17 +162,17 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { } else { then_search.snippet_occupied(cx, then_expr.span, &mut app) }; - format!( + Some(format!( "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}", map_ty.entry_path(), - ) + )) } else if let Some(insertion) = then_search.as_single_insertion() { let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; if contains_expr.negated { if insertion.value.can_have_side_effects() { - format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});") + Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")) } else { - format!("{map_str}.entry({key_str}).or_insert({value_str});") + Some(format!("{map_str}.entry({key_str}).or_insert({value_str});")) } } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. @@ -183,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { } else { let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app); if contains_expr.negated { - format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});") + Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")) } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. // This would need to be a different lint. @@ -192,7 +191,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { } }; - span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app); + if let Some(sugg) = sugg { + span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app); + } else { + span_lint(cx, MAP_ENTRY, expr.span, lint_msg); + } } } diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index f01b5c840d29..ec81294624ef 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -49,10 +49,10 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty)); if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) { - if let ty::Adt(adt, _) = ty.kind() { - if adt.is_enum() { - ty = adt.repr().discr_type().to_ty(cx.tcx); - } + if let ty::Adt(adt, _) = ty.kind() + && adt.is_enum() + { + ty = adt.repr().discr_type().to_ty(cx.tcx); } match ty.kind() { ty::Int(IntTy::Isize) => { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index e248f08789b2..2cb3b32babe8 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -72,10 +72,10 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { _: Span, fn_def_id: LocalDefId, ) { - if let Some(header) = fn_kind.header() { - if header.abi != ExternAbi::Rust { - return; - } + if let Some(header) = fn_kind.header() + && header.abi != ExternAbi::Rust + { + return; } let parent_id = cx @@ -93,12 +93,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { // find `self` ty for this trait if relevant if let ItemKind::Trait(_, _, _, _, _, items) = item.kind { for trait_item in items { - if trait_item.id.owner_id.def_id == fn_def_id { + if trait_item.id.owner_id.def_id == fn_def_id // be sure we have `self` parameter in this function - if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { - trait_self_ty = - Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty()); - } + && trait_item.kind == (AssocItemKind::Fn { has_self: true }) + { + trait_self_ty = Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty()); } } } @@ -142,22 +141,22 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool { impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - if cmt.place.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.place.base { - // FIXME(rust/#120456) - is `swap_remove` correct? - self.set.swap_remove(&lid); - } + if cmt.place.projections.is_empty() + && let PlaceBase::Local(lid) = cmt.place.base + { + // FIXME(rust/#120456) - is `swap_remove` correct? + self.set.swap_remove(&lid); } } fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { - if cmt.place.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.place.base { - // FIXME(rust/#120456) - is `swap_remove` correct? - self.set.swap_remove(&lid); - } + if cmt.place.projections.is_empty() + && let PlaceBase::Local(lid) = cmt.place.base + { + // FIXME(rust/#120456) - is `swap_remove` correct? + self.set.swap_remove(&lid); } } @@ -171,10 +170,11 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 - if let Some(trait_self_ty) = self.trait_self_ty { - if self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) { - return; - } + if let Some(trait_self_ty) = self.trait_self_ty + && self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower + && cmt.place.ty().contains(trait_self_ty) + { + return; } if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index f67d38d932b9..c868b782f43c 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -75,10 +75,10 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) { - if is_panic(self.lcx, macro_call.def_id) { - self.result.push(expr.span); - } + if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) + && is_panic(self.lcx, macro_call.def_id) + { + self.result.push(expr.span); } // check for `unwrap` diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index daa199779e3c..d5f0659f8427 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -154,7 +154,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su }; } - suggestion.maybe_par() + suggestion.maybe_paren() } fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { @@ -165,7 +165,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()), + format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_paren()), Applicability::MachineApplicable, ); } @@ -228,24 +228,24 @@ fn get_integer_from_float_constant(value: &Constant<'_>) -> Option { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) { - if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) + && let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { Some("exp") } else if F32(2.0) == value || F64(2.0) == value { Some("exp2") } else { None - } { - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "exponent for bases 2 and e can be computed more accurately", - "consider using", - format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])), - Applicability::MachineApplicable, - ); } + { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "exponent for bases 2 and e can be computed more accurately", + "consider using", + format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])), + Applicability::MachineApplicable, + ); } // Check argument @@ -254,13 +254,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()), + format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_paren()), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()), + format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_paren()), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -268,7 +268,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", - Sugg::hir(cx, receiver, "..").maybe_par(), + Sugg::hir(cx, receiver, "..").maybe_paren(), numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -289,55 +289,53 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) { - if value == Int(2) { - if let Some(parent) = get_parent_expr(cx, expr) { - if let Some(grandparent) = get_parent_expr(cx, parent) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind - { - if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { - return; - } - } + if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) + && value == Int(2) + && let Some(parent) = get_parent_expr(cx, expr) + { + if let Some(grandparent) = get_parent_expr(cx, parent) + && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind + && method_name.as_str() == "sqrt" + && detect_hypot(cx, receiver).is_some() + { + return; + } + + if let ExprKind::Binary( + Spanned { + node: op @ (BinOpKind::Add | BinOpKind::Sub), + .. + }, + lhs, + rhs, + ) = parent.kind + { + let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + + // Negate expr if original code has subtraction and expr is on the right side + let maybe_neg_sugg = |expr, hir_id| { + let sugg = Sugg::hir(cx, expr, ".."); + if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { + -sugg + } else { + sugg } + }; - if let ExprKind::Binary( - Spanned { - node: op @ (BinOpKind::Add | BinOpKind::Sub), - .. - }, - lhs, - rhs, - ) = parent.kind - { - let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; - - // Negate expr if original code has subtraction and expr is on the right side - let maybe_neg_sugg = |expr, hir_id| { - let sugg = Sugg::hir(cx, expr, ".."); - if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - -sugg - } else { - sugg - } - }; - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - parent.span, - "multiply and add expressions can be calculated more efficiently and accurately", - "consider using", - format!( - "{}.mul_add({}, {})", - Sugg::hir(cx, receiver, "..").maybe_par(), - maybe_neg_sugg(receiver, expr.hir_id), - maybe_neg_sugg(other_addend, other_addend.hir_id), - ), - Applicability::MachineApplicable, - ); - } - } + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + parent.span, + "multiply and add expressions can be calculated more efficiently and accurately", + "consider using", + format!( + "{}.mul_add({}, {})", + Sugg::hir(cx, receiver, "..").maybe_paren(), + maybe_neg_sugg(receiver, expr.hir_id), + maybe_neg_sugg(other_addend, other_addend.hir_id), + ), + Applicability::MachineApplicable, + ); } } } @@ -371,7 +369,7 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, lmul_lhs, "..").maybe_par(), + Sugg::hir(cx, lmul_lhs, "..").maybe_paren(), Sugg::hir(cx, rmul_lhs, "..") )); } @@ -403,7 +401,7 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, largs_0, "..").maybe_par(), + Sugg::hir(cx, largs_0, "..").maybe_paren(), Sugg::hir(cx, rargs_0, "..") )); } @@ -449,7 +447,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", - format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_par()), + format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_paren()), Applicability::MachineApplicable, ); } @@ -483,12 +481,12 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind { - if let Some(parent) = get_parent_expr(cx, expr) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind { - if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { - return; - } - } + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind + && method_name.as_str() == "sqrt" + && detect_hypot(cx, receiver).is_some() + { + return; } let maybe_neg_sugg = |expr| { @@ -566,15 +564,15 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// If the two expressions are not negations of each other, then it /// returns None. fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { - if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind { - if eq_expr_value(cx, expr1_negated, expr2) { - return Some((false, expr2)); - } + if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind + && eq_expr_value(cx, expr1_negated, expr2) + { + return Some((false, expr2)); } - if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind { - if eq_expr_value(cx, expr1, expr2_negated) { - return Some((true, expr1)); - } + if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind + && eq_expr_value(cx, expr1, expr2_negated) + { + return Some((true, expr1)); } None } @@ -591,11 +589,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { { let positive_abs_sugg = ( "manual implementation of `abs` method", - format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), + format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()), ); let negative_abs_sugg = ( "manual implementation of negation of `abs` method", - format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), + format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()), ); let sugg = if is_testing_positive(cx, cond, body) { if if_expr_positive { @@ -672,7 +670,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.log({})", - Sugg::hir(cx, largs_self, "..").maybe_par(), + Sugg::hir(cx, largs_self, "..").maybe_paren(), Sugg::hir(cx, rargs_self, ".."), ), Applicability::MachineApplicable, @@ -703,7 +701,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { - let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); + let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_paren()); if let ExprKind::Lit(literal) = mul_lhs.kind && let ast::LitKind::Float(ref value, float_type) = literal.node && float_type == ast::LitFloatType::Unsuffixed @@ -726,7 +724,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { - let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); + let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_paren()); if let ExprKind::Lit(literal) = mul_lhs.kind && let ast::LitKind::Float(ref value, float_type) = literal.node && float_type == ast::LitFloatType::Unsuffixed diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 5e3f6b6a1370..94e66769eb26 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { .into_owned() } else { let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); - format!("{}.to_string()", sugg.maybe_par()) + format!("{}.to_string()", sugg.maybe_paren()) }; span_useless_format(cx, call_site, sugg, applicability); } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 06224f57c5c5..8a3f8e1c5874 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -141,7 +141,7 @@ declare_clippy_lint! { /// format!("{var:.prec$}"); /// ``` /// - /// If allow-mixed-uninlined-format-args is set to false in clippy.toml, + /// If `allow-mixed-uninlined-format-args` is set to `false` in clippy.toml, /// the following code will also trigger the lint: /// ```no_run /// # let var = 42; @@ -159,7 +159,7 @@ declare_clippy_lint! { /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. #[clippy::version = "1.66.0"] pub UNINLINED_FORMAT_ARGS, - pedantic, + style, "using non-inlined variables in `format!` calls" } diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 5b42a40d850b..0535ecf5240f 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; -use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; +use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; use rustc_span::symbol::kw; -use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does @@ -185,13 +185,13 @@ impl FormatImplExpr<'_, '_> { && let trait_name = match placeholder.format_trait { FormatTrait::Display => sym::Display, FormatTrait::Debug => sym::Debug, - FormatTrait::LowerExp => sym!(LowerExp), - FormatTrait::UpperExp => sym!(UpperExp), - FormatTrait::Octal => sym!(Octal), + FormatTrait::LowerExp => sym::LowerExp, + FormatTrait::UpperExp => sym::UpperExp, + FormatTrait::Octal => sym::Octal, FormatTrait::Pointer => sym::Pointer, - FormatTrait::Binary => sym!(Binary), - FormatTrait::LowerHex => sym!(LowerHex), - FormatTrait::UpperHex => sym!(UpperHex), + FormatTrait::Binary => sym::Binary, + FormatTrait::LowerHex => sym::LowerHex, + FormatTrait::UpperHex => sym::UpperHex, } && trait_name == self.format_trait_impl.name && let Ok(index) = placeholder.argument.index diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index c8fe7ac73cb3..4b482f7b233b 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -138,27 +138,28 @@ impl EarlyLintPass for Formatting { /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind { - if !lhs.span.from_expansion() && !rhs.span.from_expansion() { - let eq_span = lhs.span.between(rhs.span); - if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind { - if let Some(eq_snippet) = snippet_opt(cx, eq_span) { - let op = op.as_str(); - let eqop_span = lhs.span.between(sub_rhs.span); - if eq_snippet.ends_with('=') { - span_lint_and_note( - cx, - SUSPICIOUS_ASSIGNMENT_FORMATTING, - eqop_span, - format!( - "this looks like you are trying to use `.. {op}= ..`, but you \ + if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind + && !lhs.span.from_expansion() + && !rhs.span.from_expansion() + { + let eq_span = lhs.span.between(rhs.span); + if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind + && let Some(eq_snippet) = snippet_opt(cx, eq_span) + { + let op = op.as_str(); + let eqop_span = lhs.span.between(sub_rhs.span); + if eq_snippet.ends_with('=') { + span_lint_and_note( + cx, + SUSPICIOUS_ASSIGNMENT_FORMATTING, + eqop_span, + format!( + "this looks like you are trying to use `.. {op}= ..`, but you \ really are doing `.. = ({op} ..)`" - ), - None, - format!("to remove this lint, use either `{op}=` or `= {op}`"), - ); - } - } + ), + None, + format!("to remove this lint, use either `{op}=` or `= {op}`"), + ); } } } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 7361546153c2..25b087e8484f 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { }; let sugg = - Sugg::hir_with_applicability(cx, expr, "", &mut Applicability::MachineApplicable).maybe_par(); + Sugg::hir_with_applicability(cx, expr, "", &mut Applicability::MachineApplicable).maybe_paren(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 854fe144c291..fa63876410f0 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind}; +use rustc_hir::{BlockCheckMode, Body, ExprKind, FnDecl, ImplicitSelfKind, UnsafeSource}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; @@ -40,14 +40,25 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: name }; - // Body must be &(mut) .name + // Body must be `&(mut) .name`, potentially in an `unsafe` block // self_data is not necessarily self, to also lint sub-getters, etc… let block_expr = if let ExprKind::Block(block, _) = body.value.kind && block.stmts.is_empty() && let Some(block_expr) = block.expr { - block_expr + if let ExprKind::Block(unsafe_block, _) = block_expr.kind + && unsafe_block.stmts.is_empty() + && matches!( + unsafe_block.rules, + BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + ) + && let Some(unsafe_block_expr) = unsafe_block.expr + { + unsafe_block_expr + } else { + block_expr + } } else { return; }; diff --git a/clippy_lints/src/functions/renamed_function_params.rs b/clippy_lints/src/functions/renamed_function_params.rs index 4495aeb5953e..2d22bb157a93 100644 --- a/clippy_lints/src/functions/renamed_function_params.rs +++ b/clippy_lints/src/functions/renamed_function_params.rs @@ -59,9 +59,7 @@ impl RenamedFnArgs { let mut renamed: Vec<(Span, String)> = vec![]; debug_assert!(default_idents.size_hint() == current_idents.size_hint()); - while let (Some(default_ident), Some(current_ident)) = - (default_idents.next(), current_idents.next()) - { + 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 diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 05dc47f6fe58..48d050aa36aa 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -47,16 +47,16 @@ pub(super) fn check_fn( } pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) { - if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { + if let hir::TraitItemKind::Fn(ref sig, _) = item.kind // don't lint extern functions decls, it's not their fault - if sig.header.abi == ExternAbi::Rust { - check_arg_number( - cx, - sig.decl, - item.span.with_hi(sig.decl.output.span().hi()), - too_many_arguments_threshold, - ); - } + && sig.header.abi == ExternAbi::Rust + { + check_arg_number( + cx, + sig.decl, + item.span.with_hi(sig.decl.output.span().hi()), + too_many_arguments_threshold, + ); } } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index fbbd33efd02d..9e94280fc074 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { |diag| { let mut app = Applicability::MachineApplicable; let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) - .maybe_par() + .maybe_paren() .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let method_body = if let Some(first_stmt) = then_block.stmts.first() { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 5f95464e4d49..076017a247b4 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro}; +use clippy_utils::{desugar_await, get_async_closure_expr, get_async_fn_body, is_async_fn, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -134,6 +134,10 @@ fn lint_implicit_returns( }, ExprKind::Match(_, arms, _) => { + if let Some(await_expr) = desugar_await(expr) { + lint_return(cx, await_expr.hir_id, await_expr.span); + return LintLocation::Inner; + } for arm in arms { let res = lint_implicit_returns( cx, @@ -153,18 +157,18 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; let _: Option = for_each_expr_without_closures(block, |e| { - if let ExprKind::Break(dest, sub_expr) = e.kind { - if dest.target_id.ok() == Some(expr.hir_id) { - if call_site_span.is_none() && e.span.ctxt() == ctxt { - // At this point sub_expr can be `None` in async functions which either diverge, or return - // the unit type. - if let Some(sub_expr) = sub_expr { - lint_break(cx, e.hir_id, e.span, sub_expr.span); - } - } else { - // the break expression is from a macro call, add a return to the loop - add_return = true; + if let ExprKind::Break(dest, sub_expr) = e.kind + && dest.target_id.ok() == Some(expr.hir_id) + { + if call_site_span.is_none() && e.span.ctxt() == ctxt { + // At this point sub_expr can be `None` in async functions which either diverge, or return + // the unit type. + if let Some(sub_expr) = sub_expr { + lint_break(cx, e.hir_id, e.span, sub_expr.span); } + } else { + // the break expression is from a macro call, add a return to the loop + add_return = true; } } ControlFlow::Continue(()) @@ -241,6 +245,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { Some(e) => e, None => return, } + } else if let Some(expr) = get_async_closure_expr(cx.tcx, body.value) { + expr } else { body.value }; diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 5d7d3ae3f24b..514e72a48682 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -239,7 +239,7 @@ fn check_subtraction( // This part of the condition is voluntarily split from the one before to ensure that // if `snippet_opt` fails, it won't try the next conditions. if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST)) - && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_par) + && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren) && let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr) { let sugg = format!( diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 430f24111832..6b89abdb0367 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -8,7 +8,7 @@ use rustc_hir::{ }; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt}; +use rustc_middle::ty::{self, AssocItem, ClauseKind, Generics, Ty, TyCtxt}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { assocs .filter_by_name_unhygienic(constraint.ident.name) .next() - .is_some_and(|assoc| assoc.is_type()) + .is_some_and(AssocItem::is_type) }) { emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index e1dd7872b9d4..e6129757e560 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -65,13 +65,13 @@ declare_clippy_lint! { } pub struct InconsistentStructConstructor { - lint_inconsistent_struct_field_initializers: bool, + check_inconsistent_struct_field_initializers: bool, } impl InconsistentStructConstructor { pub fn new(conf: &'static Conf) -> Self { Self { - lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers, + check_inconsistent_struct_field_initializers: conf.check_inconsistent_struct_field_initializers, } } } @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand); let applicability = if all_fields_are_shorthand { Applicability::MachineApplicable - } else if self.lint_inconsistent_struct_field_initializers { + } else if self.check_inconsistent_struct_field_initializers { Applicability::MaybeIncorrect } else { return; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 33431385c7de..99a393b4d53a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -2,13 +2,12 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; -use clippy_utils::{higher, is_from_proc_macro, is_in_test}; +use clippy_utils::{higher, is_from_proc_macro, is_in_test, sym}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -136,28 +135,28 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { let const_range = to_const_range(cx, range, size); - if let (Some(start), _) = const_range { - if start > size { - span_lint( - cx, - OUT_OF_BOUNDS_INDEXING, - range.start.map_or(expr.span, |start| start.span), - "range is out of bounds", - ); - return; - } + if let (Some(start), _) = const_range + && start > size + { + span_lint( + cx, + OUT_OF_BOUNDS_INDEXING, + range.start.map_or(expr.span, |start| start.span), + "range is out of bounds", + ); + return; } - if let (_, Some(end)) = const_range { - if end > size { - span_lint( - cx, - OUT_OF_BOUNDS_INDEXING, - range.end.map_or(expr.span, |end| end.span), - "range is out of bounds", - ); - return; - } + if let (_, Some(end)) = const_range + && end > size + { + span_lint( + cx, + OUT_OF_BOUNDS_INDEXING, + range.end.map_or(expr.span, |end| end.span), + "range is out of bounds", + ); + return; } if let (Some(_), Some(_)) = const_range { @@ -268,7 +267,7 @@ fn ty_has_applicable_get_function<'tcx>( index_expr: &Expr<'_>, ) -> bool { if let ty::Adt(_, _) = array_ty.kind() - && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| { + && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym::get).map(|m| { cx.tcx .fn_sig(m.def_id) .skip_binder() diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 960b9aa032be..427a1f825555 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -156,11 +156,12 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .and(cap); } } - if method.ident.name.as_str() == "flat_map" && args.len() == 1 { - if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { - let body = cx.tcx.hir_body(body); - return is_infinite(cx, body.value); - } + if method.ident.name.as_str() == "flat_map" + && args.len() == 1 + && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind + { + let body = cx.tcx.hir_body(body); + return is_infinite(cx, body.value); } Finite }, diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 4ae1119ab3a2..91f65d0b79ca 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -123,7 +123,7 @@ fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg expr.span, "manual implementation of `Instant::elapsed`", "try", - format!("{}.elapsed()", sugg.maybe_par()), + format!("{}.elapsed()", sugg.maybe_paren()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index fc575bff7e63..67ce57de254d 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -130,14 +130,14 @@ impl IntPlusOne { BinOpKind::Le => "<", _ => return None, }; - if let Some(snippet) = node.span.get_source_text(cx) { - if let Some(other_side_snippet) = other_side.span.get_source_text(cx) { - let rec = match side { - Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), - Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), - }; - return rec; - } + if let Some(snippet) = node.span.get_source_text(cx) + && let Some(other_side_snippet) = other_side.span.get_source_text(cx) + { + let rec = match side { + Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), + Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), + }; + return rec; } None } @@ -157,10 +157,10 @@ impl IntPlusOne { impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { - if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind { - if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) { - Self::emit_warning(cx, item, rec); - } + if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind + && let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) + { + Self::emit_warning(cx, item, rec); } } } diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index b42664340d1c..b0ecc5d52ddb 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -91,49 +91,49 @@ fn upcast_comparison_bounds_err<'tcx>( rhs: &'tcx Expr<'_>, invert: bool, ) { - if let Some((lb, ub)) = lhs_bounds { - if let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) { - if rel == Rel::Eq || rel == Rel::Ne { - if norm_rhs_val < lb || norm_rhs_val > ub { - err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); - } - } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val < lb - } else { - ub < norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val <= lb - } else { - ub <= norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } { - err_upcast_comparison(cx, span, lhs, true); - } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val >= ub - } else { - lb >= norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val > ub - } else { - lb > norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } { - err_upcast_comparison(cx, span, lhs, false); + if let Some((lb, ub)) = lhs_bounds + && let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) + { + if rel == Rel::Eq || rel == Rel::Ne { + if norm_rhs_val < lb || norm_rhs_val > ub { + err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); } + } else if match rel { + Rel::Lt => { + if invert { + norm_rhs_val < lb + } else { + ub < norm_rhs_val + } + }, + Rel::Le => { + if invert { + norm_rhs_val <= lb + } else { + ub <= norm_rhs_val + } + }, + Rel::Eq | Rel::Ne => unreachable!(), + } { + err_upcast_comparison(cx, span, lhs, true); + } else if match rel { + Rel::Lt => { + if invert { + norm_rhs_val >= ub + } else { + lb >= norm_rhs_val + } + }, + Rel::Le => { + if invert { + norm_rhs_val > ub + } else { + lb > norm_rhs_val + } + }, + Rel::Eq | Rel::Ne => unreachable!(), + } { + err_upcast_comparison(cx, span, lhs, false); } } } diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 977fd5fce15b..b1271a264b54 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -377,22 +377,21 @@ impl ItemNameRepetitions { "field name starts with the struct's name", ); } - if field_words.len() > item_name_words.len() { + if field_words.len() > item_name_words.len() // lint only if the end is not covered by the start - if field_words + && field_words .iter() .rev() .zip(item_name_words.iter().rev()) .all(|(a, b)| a == b) - { - span_lint_hir( - cx, - STRUCT_FIELD_NAMES, - field.hir_id, - field.span, - "field name ends with the struct's name", - ); - } + { + span_lint_hir( + cx, + STRUCT_FIELD_NAMES, + field.hir_id, + field.span, + "field name ends with the struct's name", + ); } } } @@ -445,57 +444,56 @@ impl LateLintPass<'_> for ItemNameRepetitions { let item_name = ident.name.as_str(); let item_camel = to_camel_case(item_name); - if !item.span.from_expansion() && is_present_in_source(cx, item.span) { - if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules { - // constants don't have surrounding modules - if !mod_camel.is_empty() { - if mod_name == &ident.name - && let ItemKind::Mod(..) = item.kind - && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public()) - { - span_lint( + if !item.span.from_expansion() && is_present_in_source(cx, item.span) + && let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules + // constants don't have surrounding modules + && !mod_camel.is_empty() + { + if mod_name == &ident.name + && let ItemKind::Mod(..) = item.kind + && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public()) + { + span_lint( + cx, + MODULE_INCEPTION, + item.span, + "module has the same name as its containing module", + ); + } + + // The `module_name_repetitions` lint should only trigger if the item has the module in its + // name. Having the same name is accepted. + if cx.tcx.visibility(item.owner_id).is_public() + && cx.tcx.visibility(mod_owner_id.def_id).is_public() + && item_camel.len() > mod_camel.len() + { + let matching = count_match_start(mod_camel, &item_camel); + let rmatching = count_match_end(mod_camel, &item_camel); + let nchars = mod_camel.chars().count(); + + let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric(); + + if matching.char_count == nchars { + match item_camel.chars().nth(nchars) { + Some(c) if is_word_beginning(c) => span_lint( cx, - MODULE_INCEPTION, - item.span, - "module has the same name as its containing module", - ); - } - - // The `module_name_repetitions` lint should only trigger if the item has the module in its - // name. Having the same name is accepted. - if cx.tcx.visibility(item.owner_id).is_public() - && cx.tcx.visibility(mod_owner_id.def_id).is_public() - && item_camel.len() > mod_camel.len() - { - let matching = count_match_start(mod_camel, &item_camel); - let rmatching = count_match_end(mod_camel, &item_camel); - let nchars = mod_camel.chars().count(); - - let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric(); - - if matching.char_count == nchars { - match item_camel.chars().nth(nchars) { - Some(c) if is_word_beginning(c) => span_lint( - cx, - MODULE_NAME_REPETITIONS, - ident.span, - "item name starts with its containing module's name", - ), - _ => (), - } - } - if rmatching.char_count == nchars - && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count]) - { - span_lint( - cx, - MODULE_NAME_REPETITIONS, - ident.span, - "item name ends with its containing module's name", - ); - } + MODULE_NAME_REPETITIONS, + ident.span, + "item name starts with its containing module's name", + ), + _ => (), } } + if rmatching.char_count == nchars + && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count]) + { + span_lint( + cx, + MODULE_NAME_REPETITIONS, + ident.span, + "item name ends with its containing module's name", + ); + } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 77085d52a32e..8c71d34c95f6 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,13 +2,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators}; +use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ - AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, + AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, QPath, TraitItemRef, TyKind, }; @@ -16,7 +16,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FnSig, Ty}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::sym; use rustc_span::{Ident, Span, Symbol}; use rustc_trait_selection::traits::supertrait_def_ids; @@ -143,7 +142,6 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() && let Some(local_id) = ty_id.as_local() && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) - && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id) && let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) { @@ -157,7 +155,17 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { }, _ => return, }; - check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind); + check_for_is_empty( + cx, + sig.span, + sig.decl.implicit_self, + output, + ty_id, + name, + kind, + item.hir_id(), + ty_hir_id, + ); } } @@ -180,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lt.init); - let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); + let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_paren(); span_lint_and_sugg( cx, @@ -202,7 +210,11 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { expr.span, lhs_expr, peel_ref_operators(cx, rhs_expr), - (method.ident.name == sym::ne).then_some("!").unwrap_or_default(), + if method.ident.name == sym::ne { + "!" + } else { + Default::default() + }, ); } @@ -282,15 +294,10 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden { let mut current_and_super_traits = DefIdSet::default(); fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); - let is_empty = sym!(is_empty); - let is_empty_method_found = current_and_super_traits .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) - .any(|i| { - i.is_method() - && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 - }); + .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) + .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); if !is_empty_method_found { span_lint( @@ -442,6 +449,7 @@ fn check_is_empty_sig<'tcx>( } /// Checks if the given type has an `is_empty` method with the appropriate signature. +#[expect(clippy::too_many_arguments)] fn check_for_is_empty( cx: &LateContext<'_>, span: Span, @@ -450,6 +458,8 @@ fn check_for_is_empty( impl_ty: DefId, item_name: Symbol, item_kind: &str, + len_method_hir_id: HirId, + ty_decl_hir_id: HirId, ) { // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to // find the correct inherent impls. @@ -459,12 +469,11 @@ fn check_for_is_empty( return; }; - let is_empty = Symbol::intern("is_empty"); let is_empty = cx .tcx .inherent_impls(impl_ty) .iter() - .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) + .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) .find(|item| item.is_fn()); let (msg, is_empty_span, self_kind) = match is_empty { @@ -505,14 +514,16 @@ fn check_for_is_empty( Some(_) => return, }; - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { - if let Some(span) = is_empty_span { - db.span_note(span, "`is_empty` defined here"); - } - if let Some(self_kind) = self_kind { - db.note(output.expected_sig(self_kind)); - } - }); + if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { + if let Some(span) = is_empty_span { + db.span_note(span, "`is_empty` defined here"); + } + if let Some(self_kind) = self_kind { + db.note(output.expected_sig(self_kind)); + } + }); + } } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { @@ -522,10 +533,10 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method - if let Some(name) = get_item_name(cx, method) { - if name.as_str() == "is_empty" { - return; - } + if let Some(name) = get_item_name(cx, method) + && name.as_str() == "is_empty" + { + return; } check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); @@ -572,7 +583,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lit1); - let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_par(); + let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_paren(); span_lint_and_sugg( cx, @@ -587,11 +598,11 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex } fn is_empty_string(expr: &Expr<'_>) -> bool { - if let ExprKind::Lit(lit) = expr.kind { - if let LitKind::Str(lit, _) = lit.node { - let lit = lit.as_str(); - return lit.is_empty(); - } + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Str(lit, _) = lit.node + { + let lit = lit.as_str(); + return lit.is_empty(); } false } @@ -618,11 +629,10 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { - let is_empty = sym!(is_empty); cx.tcx.inherent_impls(id).iter().any(|imp| { cx.tcx .associated_items(*imp) - .filter_by_name_unhygienic(is_empty) + .filter_by_name_unhygienic(sym::is_empty) .any(|item| is_is_empty(cx, item)) }) } @@ -630,10 +640,9 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool { match ty.kind() { ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { - let is_empty = sym!(is_empty); cx.tcx .associated_items(principal.def_id()) - .filter_by_name_unhygienic(is_empty) + .filter_by_name_unhygienic(sym::is_empty) .any(|item| is_is_empty(cx, item)) }), ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3fe3cd67e167..5fa8f6f4bf3d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -65,7 +65,6 @@ mod declare_clippy_lint; #[macro_use] extern crate clippy_utils; -#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; pub mod ctfe; // Very important lint, do not remove (rust#125116) @@ -205,6 +204,7 @@ mod loops; mod macro_metavars_in_unsafe; mod macro_use; mod main_recursion; +mod manual_abs_diff; mod manual_assert; mod manual_async_fn; mod manual_bits; @@ -226,7 +226,6 @@ mod manual_rotate; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; -mod manual_unwrap_or_default; mod map_unit_fn; mod match_result_ok; mod matches; @@ -320,6 +319,7 @@ mod redundant_locals; mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; +mod redundant_test_prefix; mod redundant_type_annotations; mod ref_option_ref; mod ref_patterns; @@ -412,21 +412,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; use utils::attr_collector::{AttrCollector, AttrStorage}; -/// Register all pre expansion lints -/// -/// Pre-expansion lints run before any macro expansion has happened. -/// -/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate -/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. -/// -/// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { - // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. - store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); - - store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); -} - #[derive(Default)] struct RegistrationGroups { all: Vec, @@ -439,8 +424,6 @@ struct RegistrationGroups { restriction: Vec, style: Vec, suspicious: Vec, - #[cfg(feature = "internal")] - internal: Vec, } impl RegistrationGroups { @@ -456,8 +439,6 @@ impl RegistrationGroups { store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction); store.register_group(true, "clippy::style", Some("clippy_style"), self.style); store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious); - #[cfg(feature = "internal")] - store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal); } } @@ -472,8 +453,6 @@ pub(crate) enum LintCategory { Restriction, Style, Suspicious, - #[cfg(feature = "internal")] - Internal, } #[allow(clippy::enum_glob_use)] @@ -495,8 +474,6 @@ impl LintCategory { Restriction => &mut groups.restriction, Style => &mut groups.style, Suspicious => &mut groups.suspicious, - #[cfg(feature = "internal")] - Internal => &mut groups.internal, } } } @@ -530,8 +507,6 @@ impl LintInfo { Restriction => "restriction", Style => "style", Suspicious => "suspicious", - #[cfg(feature = "internal")] - Internal => "internal", } } } @@ -589,6 +564,13 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_removed(name, reason); } + // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. + // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate + // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. + store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); + + store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); + let format_args_storage = FormatArgsStorage::default(); let format_args = format_args_storage.clone(); store.register_early_pass(move || { @@ -601,30 +583,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let attrs = attr_storage.clone(); store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone()))); - // all the internal lints - #[cfg(feature = "internal")] - { - store.register_early_pass(|| { - Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths) - }); - store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); - store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); - store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); - store.register_late_pass(|_| { - Box::::default() - }); - store.register_late_pass(|_| { - Box::::default() - }); - store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass)); - store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl)); - store.register_late_pass(|_| { - Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new()) - }); - store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons)); - } - store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); @@ -772,7 +730,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); - store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); + store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf))); store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); @@ -857,7 +815,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(write::Write::new(conf, format_args.clone()))); store.register_late_pass(move |_| Box::new(cargo::Cargo::new(conf))); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); - store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets)); + store.register_late_pass(|_| Box::new(empty_with_brackets::EmptyWithBrackets::default())); store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); @@ -879,6 +837,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(std_instead_of_core::StdReexports::new(conf))); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); + store.register_late_pass(move |_| Box::new(manual_abs_diff::ManualAbsDiff::new(conf))); store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf))); store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); @@ -960,7 +919,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(conf))); store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects)); - store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault)); store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed)); store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf))); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf))); @@ -971,7 +929,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); - store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); + store.register_late_pass(move |_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo::new(conf))); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); store.register_late_pass(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg)); store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); @@ -984,5 +942,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf))); store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); + store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index dabef18b98a9..5ef5e3a44f85 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -150,10 +150,10 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } = item.kind { check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv); - } else if let ItemKind::Impl(impl_) = item.kind { - if !item.span.from_expansion() { - report_extra_impl_lifetimes(cx, impl_); - } + } else if let ItemKind::Impl(impl_) = item.kind + && !item.span.from_expansion() + { + report_extra_impl_lifetimes(cx, impl_); } } @@ -300,8 +300,8 @@ fn could_use_elision<'tcx>( let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; - if let Some(trait_sig) = trait_sig - && non_elidable_self_type(cx, func, trait_sig.first().copied(), msrv) + if let Some(&[trait_sig]) = trait_sig + && non_elidable_self_type(cx, func, trait_sig, msrv) { return None; } @@ -310,11 +310,11 @@ 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, Some(first_ident), msrv) { + if non_elidable_self_type(cx, func, first_ident, msrv) { return None; } - let mut checker = BodyLifetimeChecker; + let mut checker = BodyLifetimeChecker::new(cx); if checker.visit_expr(body.value).is_break() { 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(Some(ident)) = ident +fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option, msrv: Msrv) -> bool { + if let Some(ident) = ident && ident.name == kw::SelfLower && !func.implicit_self.has_implicit_self() && let Some(self_ty) = func.inputs.first() @@ -911,10 +911,23 @@ fn elision_suggestions( Some(suggestions) } -struct BodyLifetimeChecker; +struct BodyLifetimeChecker<'tcx> { + tcx: TyCtxt<'tcx>, +} -impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { +impl<'tcx> BodyLifetimeChecker<'tcx> { + fn new(cx: &LateContext<'tcx>) -> Self { + Self { tcx: cx.tcx } + } +} + +impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker<'tcx> { type Result = ControlFlow<()>; + type NestedFilter = middle_nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> { if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 805de23408bf..7cbfa2d097ae 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -387,12 +387,11 @@ impl LiteralDigitGrouping { let first = groups.next().expect("At least one group"); - if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal { - if let Some(second_size) = groups.next() { - if !groups.all(|i| i == second_size) || first > second_size { - return Err(WarningType::UnusualByteGroupings); - } - } + if (radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal) + && let Some(second_size) = groups.next() + && (!groups.all(|i| i == second_size) || first > second_size) + { + return Err(WarningType::UnusualByteGroupings); } if let Some(second) = groups.next() { diff --git a/clippy_lints/src/literal_string_with_formatting_args.rs b/clippy_lints/src/literal_string_with_formatting_args.rs index 975e6833a35f..244e7c95122e 100644 --- a/clippy_lints/src/literal_string_with_formatting_args.rs +++ b/clippy_lints/src/literal_string_with_formatting_args.rs @@ -45,15 +45,14 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option = ControlFlow::Continue(()); + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr<'_>, body: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = iterable.kind + && let Some(method_id) = cx.typeck_results().type_dependent_def_id(iterable.hir_id) + && cx.tcx.is_diagnostic_item(sym::enumerate_method, method_id) + && let ExprKind::MethodCall(_, chars_recv, _, chars_span) = enumerate_recv.kind + && let Some(method_id) = cx.typeck_results().type_dependent_def_id(enumerate_recv.hir_id) + && cx.tcx.is_diagnostic_item(sym::str_chars, method_id) + { + if let PatKind::Tuple([pat, _], _) = pat.kind + && let PatKind::Binding(_, binding_id, ..) = pat.kind + { + // Destructured iterator element `(idx, _)`, look for uses of the binding + for_each_expr(cx, body, |expr| { + if path_to_local_id(expr, binding_id) { + check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv); + } + CONTINUE + }); + } else if let PatKind::Binding(_, binding_id, ..) = pat.kind { + // Bound as a tuple, look for `tup.0` + for_each_expr(cx, body, |expr| { + if let ExprKind::Field(e, field) = expr.kind + && path_to_local_id(e, binding_id) + && field.name == sym::integer(0) + { + check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv); + } + CONTINUE + }); + } + } +} + +fn check_index_usage<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + pat: &Pat<'_>, + enumerate_span: Span, + chars_span: Span, + chars_recv: &Expr<'_>, +) { + let Some(parent_expr) = index_consumed_at(cx, expr) else { + return; + }; + + let is_string_like = |ty: Ty<'_>| ty.is_str() || is_type_lang_item(cx, ty, LangItem::String); + let message = match parent_expr.kind { + ExprKind::MethodCall(segment, recv, ..) + // We currently only lint `str` methods (which `String` can deref to), so a `.is_str()` check is sufficient here + // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements + // `Index` directly and no deref to `str` would happen in that case). + if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str() + && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str()) + && eq_expr_value(cx, chars_recv, recv) => + { + "passing a character position to a method that expects a byte index" + }, + ExprKind::Index(target, ..) + if is_string_like(cx.typeck_results().expr_ty_adjusted(target).peel_refs()) + && eq_expr_value(cx, chars_recv, target) => + { + "indexing into a string with a character position where a byte index is expected" + }, + _ => return, + }; + + span_lint_hir_and_then( + cx, + CHAR_INDICES_AS_BYTE_INDICES, + expr.hir_id, + expr.span, + message, + |diag| { + diag.note("a character can take up more than one byte, so they are not interchangeable") + .span_note( + MultiSpan::from_spans(vec![pat.span, enumerate_span]), + "position comes from the enumerate iterator", + ) + .span_suggestion_verbose( + chars_span.to(enumerate_span), + "consider using `.char_indices()` instead", + "char_indices()", + Applicability::MaybeIncorrect, + ); + }, + ); +} + +/// Returns the expression which ultimately consumes the index. +/// This is usually the parent expression, i.e. `.split_at(idx)` for `idx`, +/// but for `.get(..idx)` we want to consider the method call the consuming expression, +/// which requires skipping past the range expression. +fn index_consumed_at<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) { + match node { + Node::Expr(expr) if higher::Range::hir(expr).is_some() => {}, + Node::ExprField(_) => {}, + Node::Expr(expr) => return Some(expr), + _ => break, + } + } + None +} diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 412c78cc8041..d0b26c91ffaf 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -2,6 +2,7 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, make_normalized_projection_with_regions, normalize_with_regions, @@ -11,7 +12,6 @@ use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, EarlyBinder, Ty}; -use rustc_span::sym; pub(super) fn check( cx: &LateContext<'_>, @@ -119,7 +119,7 @@ fn is_ref_iterable<'tcx>( && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id) && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = - make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty]) + make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym::IntoIter, [req_self_ty]) && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty) && into_iter_ty == req_res_ty { @@ -152,7 +152,7 @@ fn is_ref_iterable<'tcx>( // Using by value won't consume anything if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::None, self_ty)); @@ -169,7 +169,7 @@ fn is_ref_iterable<'tcx>( }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::reborrow(mutbl), self_ty)); @@ -183,7 +183,7 @@ fn is_ref_iterable<'tcx>( let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl); if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::borrow(mutbl), self_ty)); @@ -206,7 +206,7 @@ fn is_ref_iterable<'tcx>( && target != self_ty && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::auto_reborrow(mutbl), target)) @@ -224,7 +224,7 @@ fn is_ref_iterable<'tcx>( if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::Deref, target)) @@ -242,7 +242,7 @@ fn is_ref_iterable<'tcx>( if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::auto_borrow(mutbl), target)) diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 185d834becaf..e314bc2068b3 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -13,45 +13,45 @@ use rustc_span::sym; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { let pat_span = pat.span; - if let PatKind::Tuple(pat, _) = pat.kind { - if pat.len() == 2 { - let arg_span = arg.span; - let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { - ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { - (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl), - (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not), - _ => return, - }, + if let PatKind::Tuple(pat, _) = pat.kind + && pat.len() == 2 + { + let arg_span = arg.span; + let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { + ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { + (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl), + (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not), _ => return, - }; - let mutbl = match mutbl { - Mutability::Not => "", - Mutability::Mut => "_mut", - }; - let arg = match arg.kind { - ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr, - _ => arg, - }; + }, + _ => return, + }; + let mutbl = match mutbl { + Mutability::Not => "", + Mutability::Mut => "_mut", + }; + let arg = match arg.kind { + ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr, + _ => arg, + }; - if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) { - span_lint_and_then( - cx, - FOR_KV_MAP, - arg_span, - format!("you seem to want to iterate on a map's {kind}s"), - |diag| { - let map = sugg::Sugg::hir(cx, arg, "map"); - diag.multipart_suggestion( - "use the corresponding method", - vec![ - (pat_span, snippet(cx, new_pat_span, kind).into_owned()), - (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())), - ], - Applicability::MachineApplicable, - ); - }, - ); - } + if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) { + span_lint_and_then( + cx, + FOR_KV_MAP, + arg_span, + format!("you seem to want to iterate on a map's {kind}s"), + |diag| { + let map = sugg::Sugg::hir(cx, arg, "map"); + diag.multipart_suggestion( + "use the corresponding method", + vec![ + (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())), + ], + Applicability::MachineApplicable, + ); + }, + ); } } } diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index aa8a2934f89b..35737f3eafe2 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -3,6 +3,7 @@ use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -35,6 +36,7 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind && is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome) && path_res(cx, inner_ret) == Res::Local(binding_id) + && !contains_return_break_continue_macro(cond) && let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr) { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 701567a7d84e..d9c4b526da99 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -28,37 +28,37 @@ pub(super) fn check<'tcx>( end: Some(end), limits, }) = higher::Range::hir(arg) - { // the var must be a single name - if let PatKind::Binding(_, canonical_id, _, _) = pat.kind { - let mut starts = vec![Start { - id: canonical_id, - kind: StartKind::Range, - }]; + && let PatKind::Binding(_, canonical_id, _, _) = pat.kind + { + let mut starts = vec![Start { + id: canonical_id, + kind: StartKind::Range, + }]; - // This is one of few ways to return different iterators - // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434 - let mut iter_a = None; - let mut iter_b = None; + // This is one of few ways to return different iterators + // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434 + let mut iter_a = None; + let mut iter_b = None; - if let ExprKind::Block(block, _) = body.kind { - if let Some(loop_counters) = get_loop_counters(cx, block, expr) { - starts.extend(loop_counters); - } - iter_a = Some(get_assignments(block, &starts)); - } else { - iter_b = Some(get_assignment(body)); + if let ExprKind::Block(block, _) = body.kind { + if let Some(loop_counters) = get_loop_counters(cx, block, expr) { + starts.extend(loop_counters); } + iter_a = Some(get_assignments(block, &starts)); + } else { + iter_b = Some(get_assignment(body)); + } - let assignments = iter_a.into_iter().flatten().chain(iter_b); + let assignments = iter_a.into_iter().flatten().chain(iter_b); - let big_sugg = assignments - // The only statements in the for loops can be indexed assignments from - // indexed retrievals (except increments of loop counters). - .map(|o| { - o.and_then(|(lhs, rhs)| { - let rhs = fetch_cloned_expr(rhs); - if let ExprKind::Index(base_left, idx_left, _) = lhs.kind + let big_sugg = assignments + // The only statements in the for loops can be indexed assignments from + // indexed retrievals (except increments of loop counters). + .map(|o| { + o.and_then(|(lhs, rhs)| { + let rhs = fetch_cloned_expr(rhs); + if let ExprKind::Index(base_left, idx_left, _) = lhs.kind && let ExprKind::Index(base_right, idx_right, _) = rhs.kind && let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left)) && get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some() @@ -68,42 +68,41 @@ pub(super) fn check<'tcx>( && !local_used_in(cx, canonical_id, base_right) // Source and destination must be different && path_to_local(base_left) != path_to_local(base_right) - { - Some(( - ty, - IndexExpr { - base: base_left, - idx: start_left, - idx_offset: offset_left, - }, - IndexExpr { - base: base_right, - idx: start_right, - idx_offset: offset_right, - }, - )) - } else { - None - } - }) + { + Some(( + ty, + IndexExpr { + base: base_left, + idx: start_left, + idx_offset: offset_left, + }, + IndexExpr { + base: base_right, + idx: start_right, + idx_offset: offset_right, + }, + )) + } else { + None + } }) - .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src))) - .collect::>>() - .filter(|v| !v.is_empty()) - .map(|v| v.join("\n ")); + }) + .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src))) + .collect::>>() + .filter(|v| !v.is_empty()) + .map(|v| v.join("\n ")); - if let Some(big_sugg) = big_sugg { - span_lint_and_sugg( - cx, - MANUAL_MEMCPY, - expr.span, - "it looks like you're manually copying between slices", - "try replacing the loop by", - big_sugg, - Applicability::Unspecified, - ); - return true; - } + if let Some(big_sugg) = big_sugg { + span_lint_and_sugg( + cx, + MANUAL_MEMCPY, + expr.span, + "it looks like you're manually copying between slices", + "try replacing the loop by", + big_sugg, + Applicability::Unspecified, + ); + return true; } } false @@ -184,7 +183,12 @@ fn build_manual_memcpy_suggestion<'tcx>( { dst_base_str } else { - format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into() + format!( + "{dst_base_str}[{}..{}]", + dst_offset.maybe_paren(), + dst_limit.maybe_paren() + ) + .into() }; let method_str = if is_copy(cx, elem_ty) { @@ -196,7 +200,12 @@ fn build_manual_memcpy_suggestion<'tcx>( let src = if is_array_length_equal_to_range(cx, start, end, src.base) { src_base_str } else { - format!("{src_base_str}[{}..{}]", src_offset.maybe_par(), src_limit.maybe_par()).into() + format!( + "{src_base_str}[{}..{}]", + src_offset.maybe_paren(), + src_limit.maybe_paren() + ) + .into() }; format!("{dst}.{method_str}(&{src});") diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs index 4473a3343c7c..9527e258db8a 100644 --- a/clippy_lints/src/loops/manual_while_let_some.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -81,15 +81,15 @@ fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, } fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { - if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { - if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind { - let offending_arg = args - .iter() - .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span)); + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind + && let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind + { + let offending_arg = args + .iter() + .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span)); - if let Some(offending_arg) = offending_arg { - report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span); - } + if let Some(offending_arg) = offending_arg { + report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span); } } } diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 4b0bf5a4b3c9..2b66827e82ee 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -1,3 +1,4 @@ +mod char_indices_as_byte_indices; mod empty_loop; mod explicit_counter_loop; mod explicit_into_iter_loop; @@ -740,6 +741,49 @@ declare_clippy_lint! { "manually filling a slice with a value" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of a character position yielded by `.chars().enumerate()` in a context where a **byte index** is expected, + /// such as an argument to a specific `str` method or indexing into a `str` or `String`. + /// + /// ### Why is this bad? + /// A character (more specifically, a Unicode scalar value) that is yielded by `str::chars` can take up multiple bytes, + /// so a character position does not necessarily have the same byte index at which the character is stored. + /// Thus, using the character position where a byte index is expected can unexpectedly return wrong values + /// or panic when the string consists of multibyte characters. + /// + /// For example, the character `a` in `äa` is stored at byte index 2 but has the character position 1. + /// Using the character position 1 to index into the string will lead to a panic as it is in the middle of the first character. + /// + /// Instead of `.chars().enumerate()`, the correct iterator to use is `.char_indices()`, which yields byte indices. + /// + /// This pattern is technically fine if the strings are known to only use the ASCII subset, + /// though in those cases it would be better to use `bytes()` directly to make the intent clearer, + /// but there is also no downside to just using `.char_indices()` directly and supporting non-ASCII strings. + /// + /// You may also want to read the [chapter on strings in the Rust Book](https://doc.rust-lang.org/book/ch08-02-strings.html) + /// which goes into this in more detail. + /// + /// ### Example + /// ```no_run + /// # let s = "..."; + /// for (idx, c) in s.chars().enumerate() { + /// let _ = s[idx..]; // ⚠️ Panics for strings consisting of multibyte characters + /// } + /// ``` + /// Use instead: + /// ```no_run + /// # let s = "..."; + /// for (idx, c) in s.char_indices() { + /// let _ = s[idx..]; + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub CHAR_INDICES_AS_BYTE_INDICES, + correctness, + "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected" +} + pub struct Loops { msrv: Msrv, enforce_iter_loop_reborrow: bool, @@ -777,6 +821,7 @@ impl_lint_pass!(Loops => [ UNUSED_ENUMERATE_INDEX, INFINITE_LOOP, MANUAL_SLICE_FILL, + CHAR_INDICES_AS_BYTE_INDICES, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -860,6 +905,7 @@ impl Loops { manual_flatten::check(cx, pat, arg, body, span, self.msrv); manual_find::check(cx, pat, arg, body, span, expr); unused_enumerate_index::check(cx, pat, arg, body); + char_indices_as_byte_indices::check(cx, pat, arg, body); } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index a24dd44790e1..70ca452013f9 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -82,14 +82,14 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { - if bk == ty::BorrowKind::Mutable { - if let PlaceBase::Local(id) = cmt.place.base { - if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { - self.span_low = Some(self.cx.tcx.hir_span(diag_expr_id)); - } - if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { - self.span_high = Some(self.cx.tcx.hir_span(diag_expr_id)); - } + if bk == ty::BorrowKind::Mutable + && let PlaceBase::Local(id) = cmt.place.base + { + if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { + self.span_low = Some(self.cx.tcx.hir_span(diag_expr_id)); + } + if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { + self.span_high = Some(self.cx.tcx.hir_span(diag_expr_id)); } } } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 0f62183eb33d..7837b18bcd36 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -31,155 +31,154 @@ pub(super) fn check<'tcx>( ref end, limits, }) = higher::Range::hir(arg) - { // the var must be a single name - if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind { - let mut visitor = VarVisitor { - cx, - var: canonical_id, - indexed_mut: FxHashSet::default(), - indexed_indirectly: FxHashMap::default(), - indexed_directly: FxIndexMap::default(), - referenced: FxHashSet::default(), - nonindex: false, - prefer_mutable: false, + && let PatKind::Binding(_, canonical_id, ident, _) = pat.kind + { + let mut visitor = VarVisitor { + cx, + var: canonical_id, + indexed_mut: FxHashSet::default(), + indexed_indirectly: FxHashMap::default(), + indexed_directly: FxIndexMap::default(), + referenced: FxHashSet::default(), + nonindex: false, + prefer_mutable: false, + }; + walk_expr(&mut visitor, body); + + // linting condition: we only indexed one variable, and indexed it directly + if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 { + let (indexed, (indexed_extent, indexed_ty)) = visitor + .indexed_directly + .into_iter() + .next() + .expect("already checked that we have exactly 1 element"); + + // ensure that the indexed variable was declared before the loop, see #601 + if let Some(indexed_extent) = indexed_extent { + let parent_def_id = cx.tcx.hir_get_parent_item(expr.hir_id); + let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id); + let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap(); + if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) { + return; + } + } + + // don't lint if the container that is indexed does not have .iter() method + let has_iter = has_iter_method(cx, indexed_ty); + if has_iter.is_none() { + return; + } + + // don't lint if the container that is indexed into is also used without + // indexing + if visitor.referenced.contains(&indexed) { + return; + } + + let starts_at_zero = is_integer_const(cx, start, 0); + + let skip = if starts_at_zero { + String::new() + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) { + return; + } else { + format!(".skip({})", snippet(cx, start.span, "..")) }; - walk_expr(&mut visitor, body); - // linting condition: we only indexed one variable, and indexed it directly - if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 { - let (indexed, (indexed_extent, indexed_ty)) = visitor - .indexed_directly - .into_iter() - .next() - .expect("already checked that we have exactly 1 element"); + let mut end_is_start_plus_val = false; - // ensure that the indexed variable was declared before the loop, see #601 - if let Some(indexed_extent) = indexed_extent { - let parent_def_id = cx.tcx.hir_get_parent_item(expr.hir_id); - let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id); - let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap(); - if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) { - return; + let take = if let Some(end) = *end { + let mut take_expr = end; + + if let ExprKind::Binary(ref op, left, right) = end.kind + && op.node == BinOpKind::Add + { + let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); + let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); + + if start_equal_left { + take_expr = right; + } else if start_equal_right { + take_expr = left; } + + end_is_start_plus_val = start_equal_left | start_equal_right; } - // don't lint if the container that is indexed does not have .iter() method - let has_iter = has_iter_method(cx, indexed_ty); - if has_iter.is_none() { - return; - } - - // don't lint if the container that is indexed into is also used without - // indexing - if visitor.referenced.contains(&indexed) { - return; - } - - let starts_at_zero = is_integer_const(cx, start, 0); - - let skip = if starts_at_zero { + if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) { return; } else { - format!(".skip({})", snippet(cx, start.span, "..")) - }; - - let mut end_is_start_plus_val = false; - - let take = if let Some(end) = *end { - let mut take_expr = end; - - if let ExprKind::Binary(ref op, left, right) = end.kind { - if op.node == BinOpKind::Add { - let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); - let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); - - if start_equal_left { - take_expr = right; - } else if start_equal_right { - take_expr = left; - } - - end_is_start_plus_val = start_equal_left | start_equal_right; - } - } - - if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { - String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) { - return; - } else { - match limits { - ast::RangeLimits::Closed => { - let take_expr = sugg::Sugg::hir(cx, take_expr, ""); - format!(".take({})", take_expr + sugg::ONE) - }, - ast::RangeLimits::HalfOpen => { - format!(".take({})", snippet(cx, take_expr.span, "..")) - }, - } - } - } else { - String::new() - }; - - let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) { - ("mut ", "iter_mut") - } else { - ("", "iter") - }; - - let take_is_empty = take.is_empty(); - let mut method_1 = take; - let mut method_2 = skip; - - if end_is_start_plus_val { - mem::swap(&mut method_1, &mut method_2); - } - - if visitor.nonindex { - span_lint_and_then( - cx, - NEEDLESS_RANGE_LOOP, - arg.span, - format!("the loop variable `{}` is used to index `{indexed}`", ident.name), - |diag| { - diag.multipart_suggestion( - "consider using an iterator and enumerate()", - vec![ - (pat.span, format!("({}, )", ident.name)), - ( - arg.span, - format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), - ), - ], - Applicability::HasPlaceholders, - ); + match limits { + ast::RangeLimits::Closed => { + let take_expr = sugg::Sugg::hir(cx, take_expr, ""); + format!(".take({})", take_expr + sugg::ONE) }, - ); - } else { - let repl = if starts_at_zero && take_is_empty { - format!("&{ref_mut}{indexed}") - } else { - format!("{indexed}.{method}(){method_1}{method_2}") - }; - - span_lint_and_then( - cx, - NEEDLESS_RANGE_LOOP, - arg.span, - format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), - |diag| { - diag.multipart_suggestion( - "consider using an iterator", - vec![(pat.span, "".to_string()), (arg.span, repl)], - Applicability::HasPlaceholders, - ); + ast::RangeLimits::HalfOpen => { + format!(".take({})", snippet(cx, take_expr.span, "..")) }, - ); + } } + } else { + String::new() + }; + + let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) { + ("mut ", "iter_mut") + } else { + ("", "iter") + }; + + let take_is_empty = take.is_empty(); + let mut method_1 = take; + let mut method_2 = skip; + + if end_is_start_plus_val { + mem::swap(&mut method_1, &mut method_2); + } + + if visitor.nonindex { + span_lint_and_then( + cx, + NEEDLESS_RANGE_LOOP, + arg.span, + format!("the loop variable `{}` is used to index `{indexed}`", ident.name), + |diag| { + diag.multipart_suggestion( + "consider using an iterator and enumerate()", + vec![ + (pat.span, format!("({}, )", ident.name)), + ( + arg.span, + format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), + ), + ], + Applicability::HasPlaceholders, + ); + }, + ); + } else { + let repl = if starts_at_zero && take_is_empty { + format!("&{ref_mut}{indexed}") + } else { + format!("{indexed}.{method}(){method_1}{method_2}") + }; + + span_lint_and_then( + cx, + NEEDLESS_RANGE_LOOP, + arg.span, + format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), + |diag| { + diag.multipart_suggestion( + "consider using an iterator", + vec![(pat.span, "".to_string()), (arg.span, repl)], + Applicability::HasPlaceholders, + ); + }, + ); } } } @@ -346,10 +345,10 @@ impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> { for expr in args { let ty = self.cx.typeck_results().expr_ty_adjusted(expr); self.prefer_mutable = false; - if let ty::Ref(_, _, mutbl) = *ty.kind() { - if mutbl == Mutability::Mut { - self.prefer_mutable = true; - } + if let ty::Ref(_, _, mutbl) = *ty.kind() + && mutbl == Mutability::Mut + { + self.prefer_mutable = true; } self.visit_expr(expr); } @@ -361,10 +360,10 @@ impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> { iter::once(receiver).chain(args.iter()), ) { self.prefer_mutable = false; - if let ty::Ref(_, _, mutbl) = *ty.kind() { - if mutbl == Mutability::Mut { - self.prefer_mutable = true; - } + if let ty::Ref(_, _, mutbl) = *ty.kind() + && mutbl == Mutability::Mut + { + self.prefer_mutable = true; } self.visit_expr(expr); } diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index c3a2a38b5ec2..69c84bc7038e 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -244,10 +244,10 @@ fn never_loop_expr<'tcx>( }); combine_seq(first, || { // checks if break targets a block instead of a loop - if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind { - if let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) { - *reachable = true; - } + if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind + && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) + { + *reachable = true; } NeverLoopResult::Diverging }) diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 3c6fbef2bda8..2f6950b4380c 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -3,9 +3,7 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr, walk_local}; -use rustc_hir::{ - AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind -}; +use rustc_hir::{AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -265,7 +263,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic if impls_iterator { format!( "{}", - sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() + sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren() ) } else { // (&x).into_iter() ==> x.iter() @@ -283,12 +281,12 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic }; format!( "{}.{method_name}()", - sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(), + sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_paren(), ) }, _ => format!( "{}.into_iter()", - sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() + sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren() ), } } diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index df6e85611fb2..9071c9c95f9d 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -5,7 +5,8 @@ use itertools::Itertools; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; +use rustc_middle::lint::LevelAndSource; use rustc_session::impl_lint_pass; use rustc_span::{Span, SyntaxContext, sym}; use std::collections::BTreeMap; @@ -249,6 +250,20 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe { }) .flatten() .copied() + .inspect(|&unsafe_block| { + if let LevelAndSource { + level: Level::Expect, + lint_id: Some(id), + .. + } = cx.tcx.lint_level_at_node(MACRO_METAVARS_IN_UNSAFE, unsafe_block) + { + // Since we're going to deduplicate expanded unsafe blocks by its enclosing macro definition soon, + // which would lead to unfulfilled `#[expect()]`s in all other unsafe blocks that are filtered out + // except for the one we emit the warning at, we must manually fulfill the lint + // for all unsafe blocks here. + cx.fulfill_expectation(id); + } + }) .map(|id| { // Remove the syntax context to hide "in this macro invocation" in the diagnostic. // The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs new file mode 100644 index 000000000000..c515e41f242f --- /dev/null +++ b/clippy_lints/src/manual_abs_diff.rs @@ -0,0 +1,152 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher::If; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::HasSession as _; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::impl_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detects patterns like `if a > b { a - b } else { b - a }` and suggests using `a.abs_diff(b)`. + /// + /// ### Why is this bad? + /// Using `abs_diff` is shorter, more readable, and avoids control flow. + /// + /// ### Examples + /// ```no_run + /// # let (a, b) = (5_usize, 3_usize); + /// if a > b { + /// a - b + /// } else { + /// b - a + /// } + /// # ; + /// ``` + /// Use instead: + /// ```no_run + /// # let (a, b) = (5_usize, 3_usize); + /// a.abs_diff(b) + /// # ; + /// ``` + #[clippy::version = "1.86.0"] + pub MANUAL_ABS_DIFF, + complexity, + "using an if-else pattern instead of `abs_diff`" +} + +impl_lint_pass!(ManualAbsDiff => [MANUAL_ABS_DIFF]); + +pub struct ManualAbsDiff { + msrv: Msrv, +} + +impl ManualAbsDiff { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} + +impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if !expr.span.from_expansion() + && let Some(if_expr) = If::hir(expr) + && let Some(r#else) = if_expr.r#else + && let ExprKind::Binary(op, rhs, lhs) = if_expr.cond.kind + && let (BinOpKind::Gt | BinOpKind::Ge, mut a, mut b) | (BinOpKind::Lt | BinOpKind::Le, mut b, mut a) = + (op.node, rhs, lhs) + && let Some(ty) = self.are_ty_eligible(cx, a, b) + && is_sub_expr(cx, if_expr.then, a, b, ty) + && is_sub_expr(cx, r#else, b, a, ty) + { + span_lint_and_then( + cx, + MANUAL_ABS_DIFF, + expr.span, + "manual absolute difference pattern without using `abs_diff`", + |diag| { + if is_unsuffixed_numeral_lit(a) && !is_unsuffixed_numeral_lit(b) { + (a, b) = (b, a); + } + let applicability = { + let source_map = cx.sess().source_map(); + if span_contains_comment(source_map, if_expr.then.span) + || span_contains_comment(source_map, r#else.span) + { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } + }; + let sugg = format!( + "{}.abs_diff({})", + Sugg::hir(cx, a, "..").maybe_paren(), + Sugg::hir(cx, b, "..") + ); + diag.span_suggestion(expr.span, "replace with `abs_diff`", sugg, applicability); + }, + ); + } + } +} + +impl ManualAbsDiff { + /// Returns a type if `a` and `b` are both of it, and this lint can be applied to that + /// type (currently, any primitive int, or a `Duration`) + fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option> { + let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF); + let is_duration = + |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF); + + let a_ty = cx.typeck_results().expr_ty(a).peel_refs(); + (a_ty == cx.typeck_results().expr_ty(b).peel_refs() && (is_int(a_ty) || is_duration(a_ty))).then_some(a_ty) + } +} + +/// Checks if the given expression is a subtraction operation between two expected expressions, +/// i.e. if `expr` is `{expected_a} - {expected_b}`. +/// +/// If `expected_ty` is a signed primitive integer, this function will only return `Some` if the +/// subtraction expr is wrapped in a cast to the equivalent unsigned int. +fn is_sub_expr( + cx: &LateContext<'_>, + expr: &Expr<'_>, + expected_a: &Expr<'_>, + expected_b: &Expr<'_>, + expected_ty: Ty<'_>, +) -> bool { + let expr = peel_blocks(expr).kind; + + if let ty::Int(ty) = expected_ty.kind() { + let unsigned = Ty::new_uint(cx.tcx, ty.to_unsigned()); + + return if let ExprKind::Cast(expr, cast_ty) = expr + && cx.typeck_results().node_type(cast_ty.hir_id) == unsigned + { + is_sub_expr(cx, expr, expected_a, expected_b, unsigned) + } else { + false + }; + } + + if let ExprKind::Binary(op, a, b) = expr + && let BinOpKind::Sub = op.node + && eq_expr_value(cx, a, expected_a) + && eq_expr_value(cx, b, expected_b) + { + true + } else { + false + } +} + +fn is_unsuffixed_numeral_lit(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::Lit(lit) if lit.node.is_numeric() && lit.node.is_unsuffixed()) +} diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 83c16d4466d0..8378e15c581c 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { ExprKind::Unary(UnOp::Not, e) => (e, ""), _ => (cond, "!"), }; - let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); + let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_paren(); let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" }; let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}"); // we show to the user the suggestion without the comments, but when applying the fix, include the diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 50c8331eebab..02afe9f0997d 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -181,7 +181,7 @@ fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggest make_assignment, hir_with_ignore_attr, } = suggestion; - let input = Sugg::hir(cx, input, "..").maybe_par(); + let input = Sugg::hir(cx, input, "..").maybe_paren(); let min = Sugg::hir(cx, min, ".."); let max = Sugg::hir(cx, max, ".."); let semicolon = if make_assignment.is_some() { ";" } else { "" }; diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 9944c4f88048..444ecd5d2bb9 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,8 +1,9 @@ -use clippy_utils::SpanlessEq; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -11,9 +12,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; - -use clippy_config::Conf; declare_clippy_lint! { /// ### What it does @@ -141,8 +139,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.peel_refs().kind() { ty::Uint(_) => true, - ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")), - + ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings), _ => false, } } @@ -167,7 +164,7 @@ fn build_suggestion( rhs: &Expr<'_>, applicability: &mut Applicability, ) { - let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par(); + let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren(); let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric() && matches!( lhs.kind, diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index faf01a276a13..8ab49bd2ea8e 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -148,7 +148,7 @@ fn check_is_ascii( }; let default_snip = ".."; let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); + let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_paren(); let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))]; if let Some((ty_span, ty)) = ty_sugg { suggestion.push((ty_span, format!("{recv}: {ty}"))); diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index 841adfec4624..b4cd988329d3 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -1,13 +1,14 @@ -use clippy_utils::SpanlessEq; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use rustc_ast::LitKind; -use rustc_data_structures::packed::Pu128; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::ty_from_hir_ty; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Uint; -use rustc_session::declare_lint_pass; +use rustc_middle::ty; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does @@ -33,112 +34,111 @@ declare_clippy_lint! { "manually reimplementing `is_power_of_two`" } -declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); +pub struct ManualIsPowerOfTwo { + msrv: Msrv, +} + +impl_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); + +impl ManualIsPowerOfTwo { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } + + fn build_sugg(&self, cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + if is_in_const_context(cx) && !self.msrv.meets(cx, msrvs::CONST_IS_POWER_OF_TWO) { + return; + } -impl LateLintPass<'_> for ManualIsPowerOfTwo { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let mut applicability = Applicability::MachineApplicable; + let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability); - if let ExprKind::Binary(bin_op, left, right) = expr.kind - && bin_op.node == BinOpKind::Eq + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + format!("{}.is_power_of_two()", snippet.maybe_paren()), + applicability, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if !expr.span.from_expansion() + && let Some((lhs, rhs)) = unexpanded_binop_operands(expr, BinOpKind::Eq) { - // a.count_ones() == 1 - if let ExprKind::MethodCall(method_name, receiver, [], _) = left.kind - && method_name.ident.as_str() == "count_ones" - && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind() - && check_lit(right, 1) + if let Some(a) = count_ones_receiver(cx, lhs) + && is_integer_literal(rhs, 1) { - build_sugg(cx, expr, receiver, &mut applicability); - } - - // 1 == a.count_ones() - if let ExprKind::MethodCall(method_name, receiver, [], _) = right.kind - && method_name.ident.as_str() == "count_ones" - && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind() - && check_lit(left, 1) + self.build_sugg(cx, expr, a); + } else if let Some(a) = count_ones_receiver(cx, rhs) + && is_integer_literal(lhs, 1) { - build_sugg(cx, expr, receiver, &mut applicability); - } - - // a & (a - 1) == 0 - if let ExprKind::Binary(op1, left1, right1) = left.kind - && op1.node == BinOpKind::BitAnd - && let ExprKind::Binary(op2, left2, right2) = right1.kind - && op2.node == BinOpKind::Sub - && check_eq_expr(cx, left1, left2) - && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() - && check_lit(right2, 1) - && check_lit(right, 0) + self.build_sugg(cx, expr, a); + } else if is_integer_literal(rhs, 0) + && let Some(a) = is_and_minus_one(cx, lhs) { - build_sugg(cx, expr, left1, &mut applicability); - } - - // (a - 1) & a == 0; - if let ExprKind::Binary(op1, left1, right1) = left.kind - && op1.node == BinOpKind::BitAnd - && let ExprKind::Binary(op2, left2, right2) = left1.kind - && op2.node == BinOpKind::Sub - && check_eq_expr(cx, right1, left2) - && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() - && check_lit(right2, 1) - && check_lit(right, 0) + self.build_sugg(cx, expr, a); + } else if is_integer_literal(lhs, 0) + && let Some(a) = is_and_minus_one(cx, rhs) { - build_sugg(cx, expr, right1, &mut applicability); - } - - // 0 == a & (a - 1); - if let ExprKind::Binary(op1, left1, right1) = right.kind - && op1.node == BinOpKind::BitAnd - && let ExprKind::Binary(op2, left2, right2) = right1.kind - && op2.node == BinOpKind::Sub - && check_eq_expr(cx, left1, left2) - && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() - && check_lit(right2, 1) - && check_lit(left, 0) - { - build_sugg(cx, expr, left1, &mut applicability); - } - - // 0 == (a - 1) & a - if let ExprKind::Binary(op1, left1, right1) = right.kind - && op1.node == BinOpKind::BitAnd - && let ExprKind::Binary(op2, left2, right2) = left1.kind - && op2.node == BinOpKind::Sub - && check_eq_expr(cx, right1, left2) - && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() - && check_lit(right2, 1) - && check_lit(left, 0) - { - build_sugg(cx, expr, right1, &mut applicability); + self.build_sugg(cx, expr, a); } } } } -fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, applicability: &mut Applicability) { - let snippet = snippet_with_applicability(cx, receiver.span, "..", applicability); - - span_lint_and_sugg( - cx, - MANUAL_IS_POWER_OF_TWO, - expr.span, - "manually reimplementing `is_power_of_two`", - "consider using `.is_power_of_two()`", - format!("{snippet}.is_power_of_two()"), - *applicability, - ); -} - -fn check_lit(expr: &Expr<'_>, expected_num: u128) -> bool { - if let ExprKind::Lit(lit) = expr.kind - && let LitKind::Int(Pu128(num), _) = lit.node - && num == expected_num +/// Return the unsigned integer receiver of `.count_ones()` or the argument of +/// `::count_ones(…)`. +fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + let (method, ty, receiver) = if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind { + (method_name, cx.typeck_results().expr_ty_adjusted(receiver), receiver) + } else if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, func_name)) = func.kind { - return true; - } - false + (func_name, ty_from_hir_ty(cx, ty), arg) + } else { + return None; + }; + (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) } -fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { - SpanlessEq::new(cx).eq_expr(lhs, rhs) +/// Return `greater` if `smaller == greater - 1` +fn is_one_less<'tcx>( + cx: &LateContext<'tcx>, + greater: &'tcx Expr<'tcx>, + smaller: &Expr<'tcx>, +) -> Option<&'tcx Expr<'tcx>> { + if let Some((lhs, rhs)) = unexpanded_binop_operands(smaller, BinOpKind::Sub) + && SpanlessEq::new(cx).eq_expr(greater, lhs) + && is_integer_literal(rhs, 1) + && matches!(cx.typeck_results().expr_ty_adjusted(greater).kind(), ty::Uint(_)) + { + Some(greater) + } else { + None + } +} + +/// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v` +fn is_and_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + let (lhs, rhs) = unexpanded_binop_operands(expr, BinOpKind::BitAnd)?; + is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs)) +} + +/// Return the operands of the `expr` binary operation if the operator is `op` and none of the +/// operands come from expansion. +fn unexpanded_binop_operands<'hir>(expr: &Expr<'hir>, op: BinOpKind) -> Option<(&'hir Expr<'hir>, &'hir Expr<'hir>)> { + if let ExprKind::Binary(binop, lhs, rhs) = expr.kind + && binop.node == op + && !lhs.span.from_expansion() + && !rhs.span.from_expansion() + { + Some((lhs, rhs)) + } else { + None + } } diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs index 8dee29b2a0b5..e4ad3953b671 100644 --- a/clippy_lints/src/manual_option_as_slice.rs +++ b/clippy_lints/src/manual_option_as_slice.rs @@ -34,7 +34,7 @@ declare_clippy_lint! { /// _ = opt.as_slice(); /// _ = opt.as_slice(); /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.86.0"] pub MANUAL_OPTION_AS_SLICE, complexity, "manual `Option::as_slice`" diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 16dd1ad4e478..98e8b1f5cf92 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -92,10 +92,10 @@ fn check_into_iter( && let [filter_params] = filter_body.params { if match_map_type(cx, left_expr) { - if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind { - if let Some(sugg) = make_sugg(cx, key_pat, value_pat, left_expr, filter_body) { - make_span_lint_and_sugg(cx, parent_expr_span, sugg); - } + if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind + && let Some(sugg) = make_sugg(cx, key_pat, value_pat, left_expr, filter_body) + { + make_span_lint_and_sugg(cx, parent_expr_span, sugg); } // Cannot lint other cases because `retain` requires two parameters } else { @@ -196,22 +196,21 @@ fn check_to_owned( && let filter_body = cx.tcx.hir_body(closure.body) && let [filter_params] = filter_body.params && msrv.meets(cx, msrvs::STRING_RETAIN) + && let hir::PatKind::Ref(pat, _) = filter_params.pat.kind { - if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind { - make_span_lint_and_sugg( - cx, - parent_expr_span, - format!( - "{}.retain(|{}| {})", - snippet(cx, left_expr.span, ".."), - snippet(cx, pat.span, ".."), - snippet(cx, filter_body.value.span, "..") - ), - ); - } - // Be conservative now. Do nothing for the `Binding` case. - // TODO: Ideally, we can rewrite the lambda by stripping one level of reference + make_span_lint_and_sugg( + cx, + parent_expr_span, + format!( + "{}.retain(|{}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, pat.span, ".."), + snippet(cx, filter_body.value.span, "..") + ), + ); } + // Be conservative now. Do nothing for the `Binding` case. + // TODO: Ideally, we can rewrite the lambda by stripping one level of reference } fn make_sugg( diff --git a/clippy_lints/src/manual_rotate.rs b/clippy_lints/src/manual_rotate.rs index 07537fc65c08..06ee00c2cef3 100644 --- a/clippy_lints/src/manual_rotate.rs +++ b/clippy_lints/src/manual_rotate.rs @@ -101,7 +101,7 @@ impl LateLintPass<'_> for ManualRotate { (r_shift_dir, r_amount) }; let mut applicability = Applicability::MachineApplicable; - let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par(); + let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren(); span_lint_and_sugg( cx, MANUAL_ROTATE, diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index 5c2a711b5cb2..7ca3b7120667 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -113,15 +113,14 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, arg: &Expr<'_>) && is_expr_kind_empty_str(&arg.kind) { warn_then_suggest(cx, span); - } else if let QPath::Resolved(_, path) = qpath { + } else if let QPath::Resolved(_, path) = qpath // From::from(...) or TryFrom::try_from(...) - if let [path_seg1, path_seg2] = path.segments - && is_expr_kind_empty_str(&arg.kind) - && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) - || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)) - { - warn_then_suggest(cx, span); - } + && let [path_seg1, path_seg2] = path.segments + && is_expr_kind_empty_str(&arg.kind) + && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) + || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)) + { + warn_then_suggest(cx, span); } } } diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs deleted file mode 100644 index 87d2faa225c5..000000000000 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ /dev/null @@ -1,212 +0,0 @@ -use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::GenericArgKind; -use rustc_session::declare_lint_pass; -use rustc_span::sym; - -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::IfLetOrMatch; -use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{expr_type_is_certain, implements_trait}; -use clippy_utils::{is_default_equivalent, is_in_const_context, path_res, peel_blocks, span_contains_comment}; - -declare_clippy_lint! { - /// ### What it does - /// Checks if a `match` or `if let` expression can be simplified using - /// `.unwrap_or_default()`. - /// - /// ### Why is this bad? - /// It can be done in one call with `.unwrap_or_default()`. - /// - /// ### Example - /// ```no_run - /// let x: Option = Some(String::new()); - /// let y: String = match x { - /// Some(v) => v, - /// None => String::new(), - /// }; - /// - /// let x: Option> = Some(Vec::new()); - /// let y: Vec = if let Some(v) = x { - /// v - /// } else { - /// Vec::new() - /// }; - /// ``` - /// Use instead: - /// ```no_run - /// let x: Option = Some(String::new()); - /// let y: String = x.unwrap_or_default(); - /// - /// let x: Option> = Some(Vec::new()); - /// let y: Vec = x.unwrap_or_default(); - /// ``` - #[clippy::version = "1.79.0"] - pub MANUAL_UNWRAP_OR_DEFAULT, - suspicious, - "check if a `match` or `if let` can be simplified with `unwrap_or_default`" -} - -declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]); - -fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option { - if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind - && let PatKind::Binding(_, pat_id, _, _) = pat.kind - && let Some(def_id) = path.res.opt_def_id() - // Since it comes from a pattern binding, we need to get the parent to actually match - // against it. - && let Some(def_id) = cx.tcx.opt_parent(def_id) - && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) - || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id)) - { - Some(pat_id) - } else { - None - } -} - -fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind - && let Some(def_id) = path.res.opt_def_id() - // Since it comes from a pattern binding, we need to get the parent to actually match - // against it. - && let Some(def_id) = cx.tcx.opt_parent(def_id) - && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id) - { - Some(arm.body) - } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind - && let Some(def_id) = path.res.opt_def_id() - // Since it comes from a pattern binding, we need to get the parent to actually match - // against it. - && let Some(def_id) = cx.tcx.opt_parent(def_id) - && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id) - { - Some(arm.body) - } else if let PatKind::Wild = arm.pat.kind { - // We consider that the `Some` check will filter it out if it's not right. - Some(arm.body) - } else { - None - } -} - -fn get_some_and_none_bodies<'tcx>( - cx: &LateContext<'tcx>, - arm1: &'tcx Arm<'tcx>, - arm2: &'tcx Arm<'tcx>, -) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> { - if let Some(binding_id) = get_some(cx, arm1.pat) - && let Some(body_none) = get_none(cx, arm2) - { - Some(((arm1.body, binding_id), body_none)) - } else if let Some(binding_id) = get_some(cx, arm2.pat) - && let Some(body_none) = get_none(cx, arm1) - { - Some(((arm2.body, binding_id), body_none)) - } else { - None - } -} - -#[allow(clippy::needless_pass_by_value)] -fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) { - // Get expr_name ("if let" or "match" depending on kind of expression), the condition, the body for - // the some arm, the body for the none arm and the binding id of the some arm - let (expr_name, condition, body_some, body_none, binding_id) = match if_let_or_match { - IfLetOrMatch::Match(condition, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) - // Make sure there are no guards to keep things simple - if arm1.guard.is_none() - && arm2.guard.is_none() - // Get the some and none bodies and the binding id of the some arm - && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) => - { - ("match", condition, body_some, body_none, binding_id) - }, - IfLetOrMatch::IfLet(condition, pat, if_expr, Some(else_expr), _) - if let Some(binding_id) = get_some(cx, pat) => - { - ("if let", condition, if_expr, else_expr, binding_id) - }, - _ => { - // All other cases (match with number of arms != 2, if let without else, etc.) - return; - }, - }; - - // We check if the return type of the expression implements Default. - let expr_type = cx.typeck_results().expr_ty(expr); - if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) - && implements_trait(cx, expr_type, default_trait_id, &[]) - // We check if the initial condition implements Default. - && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1) - && let GenericArgKind::Type(condition_ty) = condition_ty.unpack() - && implements_trait(cx, condition_ty, default_trait_id, &[]) - // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind - && let Res::Local(local_id) = path.res - && local_id == binding_id - // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_none = peel_blocks(body_none) - && is_default_equivalent(cx, body_none) - && let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par) - { - // Machine applicable only if there are no comments present - let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - - // We now check if the condition is a None variant, in which case we need to specify the type - if path_res(cx, condition) - .opt_def_id() - .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant()) - { - return span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR_DEFAULT, - expr.span, - format!("{expr_name} can be simplified with `.unwrap_or_default()`"), - "replace it with", - format!("{receiver}::<{expr_type}>.unwrap_or_default()"), - applicability, - ); - } - - // We check if the expression type is still uncertain, in which case we ask the user to specify it - if !expr_type_is_certain(cx, condition) { - return span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR_DEFAULT, - expr.span, - format!("{expr_name} can be simplified with `.unwrap_or_default()`"), - format!("ascribe the type {expr_type} and replace your expression with"), - format!("{receiver}.unwrap_or_default()"), - Applicability::Unspecified, - ); - } - - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR_DEFAULT, - expr.span, - format!("{expr_name} can be simplified with `.unwrap_or_default()`"), - "replace it with", - format!("{receiver}.unwrap_or_default()"), - applicability, - ); - } -} - -impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) - && !expr.span.from_expansion() - && !is_in_const_context(cx) - { - handle(cx, if_let_or_match, expr); - } - } -} diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 56aead85e7c4..b607f8117eb8 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -101,10 +101,10 @@ fn is_unit_type(ty: Ty<'_>) -> bool { fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - if let ty::FnDef(id, _) = *ty.kind() { - if let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars() { - return is_unit_type(fn_type.output()); - } + if let ty::FnDef(id, _) = *ty.kind() + && let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars() + { + return is_unit_type(fn_type.output()); } false } diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 6f446bf95658..5b50efad3e44 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; @@ -99,7 +99,7 @@ fn check_arm<'tcx>( } else { String::new() }; - span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, msg, |diag| { + span_lint_hir_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.hir_id, inner_expr.span, msg, |diag| { let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); help_span.push_span_label(binding_span, "replace this binding"); help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index 4cc43e427ec6..abf723fa6f4c 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -41,10 +41,10 @@ fn get_cond_expr<'tcx>( fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> { // we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's // checked by `contains_unsafe_block` - if let ExprKind::Block(block, None) = expr.kind { - if block.stmts.is_empty() { - return block.expr; - } + if let ExprKind::Block(block, None) = expr.kind + && block.stmts.is_empty() + { + return block.expr; } None } @@ -61,13 +61,13 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> { // } // Returns true if resolves to `Some(x)`, `false` otherwise fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool { - if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) { + if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) // there can be not statements in the block as they would be removed when switching to `.filter` - if let ExprKind::Call(callee, [arg]) = inner_expr.kind { - return ctxt == expr.span.ctxt() - && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) - && path_to_local_id(arg, target); - } + && let ExprKind::Call(callee, [arg]) = inner_expr.kind + { + return ctxt == expr.span.ctxt() + && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) + && path_to_local_id(arg, target); } false } diff --git a/clippy_lints/src/matches/manual_ok_err.rs b/clippy_lints/src/matches/manual_ok_err.rs index 576e42a564c2..4959908dad63 100644 --- a/clippy_lints/src/matches/manual_ok_err.rs +++ b/clippy_lints/src/matches/manual_ok_err.rs @@ -85,7 +85,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool /// contains `Err(IDENT)`, `None` otherwise. fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'hir Ident)> { if let PatKind::TupleStruct(qpath, [arg], _) = &pat.kind - && let PatKind::Binding(BindingMode::NONE, _, ident, _) = &arg.kind + && let PatKind::Binding(BindingMode::NONE, _, ident, None) = &arg.kind && let res = cx.qpath_res(qpath, pat.hir_id) && let Res::Def(DefKind::Ctor(..), id) = res && let id @ Some(_) = cx.tcx.opt_parent(id) @@ -132,7 +132,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok } else { Applicability::MachineApplicable }; - let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_par(); + let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren(); let sugg = format!("{scrut}.{method}()"); // If the expression being expanded is the `if …` part of an `else if …`, it must be blockified. let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 2bf7ec8ab7dd..b64ae0b24d81 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,133 +1,219 @@ use clippy_utils::consts::ConstEvalCtxt; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; +use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, ResultErr}; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind}; -use rustc_lint::LateContext; -use rustc_middle::ty::Ty; +use rustc_hir::def::Res; +use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_span::sym; -use super::MANUAL_UNWRAP_OR; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::{expr_type_is_certain, get_type_diagnostic_name, implements_trait}; +use clippy_utils::{is_default_equivalent, is_lint_allowed, path_res, peel_blocks, span_contains_comment}; -pub(super) fn check_match<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, - scrutinee: &'tcx Expr<'_>, - arms: &'tcx [Arm<'_>], -) { - let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some((or_arm, unwrap_arm)) = applicable_or_arm(cx, arms) { - check_and_lint(cx, expr, unwrap_arm.pat, scrutinee, unwrap_arm.body, or_arm.body, ty); +use super::{MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT}; + +fn get_some(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option { + if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind + && let PatKind::Binding(_, pat_id, _, _) = pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && let Some(lang_item) = cx.tcx.lang_items().from_def_id(def_id) + && matches!(lang_item, LangItem::OptionSome | LangItem::ResultOk) + { + Some(pat_id) + } else { + None } } -pub(super) fn check_if_let<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - let_pat: &'tcx Pat<'_>, - let_expr: &'tcx Expr<'_>, - then_expr: &'tcx Expr<'_>, - else_expr: &'tcx Expr<'_>, -) { - let ty = cx.typeck_results().expr_ty(let_expr); - let then_ty = cx.typeck_results().expr_ty(then_expr); - // The signature is `fn unwrap_or(self: Option, default: T) -> T`. - // When `expr_adjustments(then_expr).is_empty()`, `T` should equate to `default`'s type. - // Otherwise, type error will occur. - if cx.typeck_results().expr_adjustments(then_expr).is_empty() - && let rustc_middle::ty::Adt(_did, args) = ty.kind() - && let Some(some_ty) = args.first().and_then(|arg| arg.as_type()) - && some_ty != then_ty +fn get_none<'tcx>(cx: &LateContext<'_>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> { + if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id) { + Some(arm.body) + } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id) + { + Some(arm.body) + } else if let PatKind::Wild = arm.pat.kind { + // We consider that the `Some` check will filter it out if it's not right. + Some(arm.body) + } else { + None + } +} + +fn get_some_and_none_bodies<'tcx>( + cx: &LateContext<'tcx>, + arm1: &'tcx Arm<'tcx>, + arm2: &'tcx Arm<'tcx>, +) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> { + if let Some(binding_id) = get_some(cx, arm1.pat) + && let Some(body_none) = get_none(cx, arm2) + { + Some(((arm1.body, binding_id), body_none)) + } else if let Some(binding_id) = get_some(cx, arm2.pat) + && let Some(body_none) = get_none(cx, arm1) + { + Some(((arm2.body, binding_id), body_none)) + } else { + None + } +} + +fn handle( + cx: &LateContext<'_>, + expr: &Expr<'_>, + expr_name: &'static str, + condition: &Expr<'_>, + body_some: &Expr<'_>, + body_none: &Expr<'_>, + binding_id: HirId, +) { + // Only deal with situations where both alternatives return the same non-adjusted type. + if cx.typeck_results().expr_ty(body_some) != cx.typeck_results().expr_ty(body_none) { return; } - check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty); -} -fn check_and_lint<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - let_pat: &'tcx Pat<'_>, - let_expr: &'tcx Expr<'_>, - then_expr: &'tcx Expr<'_>, - else_expr: &'tcx Expr<'_>, - ty: Ty<'tcx>, -) { - if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = let_pat.kind - && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id) - && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) - && (cx.tcx.lang_items().option_some_variant() == Some(variant_id) - || cx.tcx.lang_items().result_ok_variant() == Some(variant_id)) - && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind - && path_to_local_id(peel_blocks(then_expr), binding_hir_id) - && cx.typeck_results().expr_adjustments(then_expr).is_empty() - && let Some(ty_name) = find_type_name(cx, ty) - && let Some(or_body_snippet) = else_expr.span.get_source_text(cx) - && let Some(indent) = indent_of(cx, expr.span) - && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some() + let expr_type = cx.typeck_results().expr_ty(expr); + // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. + if let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind + && let Res::Local(local_id) = path.res + && local_id == binding_id { - lint(cx, expr, let_expr, ty_name, &or_body_snippet, indent); + // Machine applicable only if there are no comments present + let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + let receiver = Sugg::hir_with_applicability(cx, condition, "_", &mut applicability).maybe_paren(); + + // We now check the `None` arm is calling a method equivalent to `Default::default`. + if !is_lint_allowed(cx, MANUAL_UNWRAP_OR_DEFAULT, expr.hir_id) + // We check if the return type of the expression implements Default. + && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + && implements_trait(cx, expr_type, default_trait_id, &[]) + // We check if the initial condition implements Default. + && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1) + && let GenericArgKind::Type(condition_ty) = condition_ty.unpack() + && implements_trait(cx, condition_ty, default_trait_id, &[]) + && is_default_equivalent(cx, peel_blocks(body_none)) + { + // We now check if the condition is a None variant, in which case we need to specify the type + if path_res(cx, condition) + .opt_def_id() + .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant()) + { + return span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR_DEFAULT, + expr.span, + format!("{expr_name} can be simplified with `.unwrap_or_default()`"), + "replace it with", + format!("{receiver}::<{expr_type}>.unwrap_or_default()"), + applicability, + ); + } + + // We check if the expression type is still uncertain, in which case we ask the user to specify it + if !expr_type_is_certain(cx, condition) { + return span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR_DEFAULT, + expr.span, + format!("{expr_name} can be simplified with `.unwrap_or_default()`"), + format!("ascribe the type {expr_type} and replace your expression with"), + format!("{receiver}.unwrap_or_default()"), + Applicability::Unspecified, + ); + } + + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR_DEFAULT, + expr.span, + format!("{expr_name} can be simplified with `.unwrap_or_default()`"), + "replace it with", + format!("{receiver}.unwrap_or_default()"), + applicability, + ); + } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition)) + && cx.typeck_results().expr_adjustments(body_some).is_empty() + && let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx) + && let Some(indent) = indent_of(cx, expr.span) + && ConstEvalCtxt::new(cx).eval_simple(body_none).is_some() + { + let reindented_or_body = reindent_multiline(&or_body_snippet, true, Some(indent)); + let mut app = Applicability::MachineApplicable; + let suggestion = Sugg::hir_with_context(cx, condition, expr.span.ctxt(), "..", &mut app).maybe_paren(); + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR, + expr.span, + format!("this pattern reimplements `{ty_name}::unwrap_or`"), + "replace with", + format!("{suggestion}.unwrap_or({reindented_or_body})",), + app, + ); + } } } fn find_type_name<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'static str> { - if is_type_diagnostic_item(cx, ty, sym::Option) { - Some("Option") - } else if is_type_diagnostic_item(cx, ty, sym::Result) { - Some("Result") - } else { - None + match get_type_diagnostic_name(cx, ty)? { + sym::Option => Some("Option"), + sym::Result => Some("Result"), + _ => None, } } -fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&'a Arm<'a>, &'a Arm<'a>)> { - if arms.len() == 2 - && arms.iter().all(|arm| arm.guard.is_none()) - && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { - PatKind::Expr(PatExpr { - hir_id, - kind: PatExprKind::Path(qpath), - .. - }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone), - PatKind::TupleStruct(ref qpath, [pat], _) => { - matches!(pat.kind, PatKind::Wild) - && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr) - }, - _ => false, - }) - && let unwrap_arm = &arms[1 - idx] - && !contains_return_break_continue_macro(or_arm.body) - { - Some((or_arm, unwrap_arm)) - } else { - None - } -} - -fn lint<'tcx>( +pub fn check_match<'tcx>( cx: &LateContext<'tcx>, - expr: &Expr<'tcx>, - scrutinee: &'tcx Expr<'_>, - ty_name: &str, - or_body_snippet: &str, - indent: usize, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'tcx>, + arms: &'tcx [Arm<'tcx>], ) { - let reindented_or_body = reindent_multiline(or_body_snippet, true, Some(indent)); - - let mut app = Applicability::MachineApplicable; - let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR, - expr.span, - format!("this pattern reimplements `{ty_name}::unwrap_or`"), - "replace with", - format!("{suggestion}.unwrap_or({reindented_or_body})",), - app, - ); + if let [arm1, arm2] = arms + // Make sure there are no guards to keep things simple + && arm1.guard.is_none() + && arm2.guard.is_none() + // Get the some and none bodies and the binding id of the some arm + && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) + { + handle(cx, expr, "match", scrutinee, body_some, body_none, binding_id); + } +} + +pub fn check_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + pat: &'tcx Pat<'tcx>, + scrutinee: &'tcx Expr<'tcx>, + then_expr: &'tcx Expr<'tcx>, + else_expr: &'tcx Expr<'tcx>, +) { + if let Some(binding_id) = get_some(cx, pat) { + handle( + cx, + expr, + "if let", + scrutinee, + peel_blocks(then_expr), + peel_blocks(else_expr), + binding_id, + ); + } } diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index d29d1ea3e96d..f14b69d91ce4 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -76,17 +76,18 @@ where && first_attrs.is_empty() && iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty()) { - if let Some(last_pat) = last_pat_opt { - if !is_wild(last_pat) { - return false; - } + if let Some(last_pat) = last_pat_opt + && !is_wild(last_pat) + { + return false; } for arm in iter_without_last.clone() { - if let Some(pat) = arm.1 { - if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { - return false; - } + if let Some(pat) = arm.1 + && !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) + && is_some(pat.kind) + { + return false; } } @@ -113,10 +114,10 @@ where // strip potential borrows (#6503), but only if the type is a reference let mut ex_new = ex; - if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind { - if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() { - ex_new = ex_inner; - } + if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind + && let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() + { + ex_new = ex_inner; } span_lint_and_sugg( cx, diff --git a/clippy_lints/src/matches/match_on_vec_items.rs b/clippy_lints/src/matches/match_on_vec_items.rs deleted file mode 100644 index dd71560e169e..000000000000 --- a/clippy_lints/src/matches/match_on_vec_items.rs +++ /dev/null @@ -1,50 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem}; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::MATCH_ON_VEC_ITEMS; - -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { - if let Some(idx_expr) = is_vec_indexing(cx, scrutinee) - && let ExprKind::Index(vec, idx, _) = idx_expr.kind - { - // FIXME: could be improved to suggest surrounding every pattern with Some(_), - // but only when `or_patterns` are stabilized. - span_lint_and_sugg( - cx, - MATCH_ON_VEC_ITEMS, - scrutinee.span, - "indexing into a vector may panic", - "try", - format!("{}.get({})", snippet(cx, vec.span, ".."), snippet(cx, idx.span, "..")), - Applicability::MaybeIncorrect, - ); - } -} - -fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Index(array, index, _) = expr.kind - && is_vector(cx, array) - && !is_full_range(cx, index) - { - return Some(expr); - } - - None -} - -fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); - let ty = ty.peel_refs(); - is_type_diagnostic_item(cx, ty, sym::Vec) -} - -fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); - let ty = ty.peel_refs(); - is_type_lang_item(cx, ty, LangItem::RangeFull) -} diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 864923b27739..adda35869900 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; -use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability}; +use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_context}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; @@ -24,16 +24,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); let mut app = Applicability::MaybeIncorrect; - let mut snippet_body = snippet_block_with_context( - cx, - match_body.span, - arms[0].span.ctxt(), - "..", - Some(expr.span), - &mut app, - ) - .0 - .to_string(); + let ctxt = expr.span.ctxt(); + let mut snippet_body = snippet_block_with_context(cx, match_body.span, ctxt, "..", Some(expr.span), &mut app) + .0 + .to_string(); // Do we need to add ';' to suggestion ? if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) @@ -77,10 +71,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e span, format!( "let {} = {};\n{}let {} = {snippet_body};", - snippet_with_applicability(cx, bind_names, "..", &mut app), - snippet_with_applicability(cx, matched_vars, "..", &mut app), + snippet_with_context(cx, bind_names, ctxt, "..", &mut app).0, + snippet_with_context(cx, matched_vars, ctxt, "..", &mut app).0, " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut app) + snippet_with_context(cx, pat_span, ctxt, "..", &mut app).0 ), ), None => { @@ -178,24 +172,24 @@ fn sugg_with_curlies<'a>( let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0)); let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new()); - if let Some(parent_expr) = get_parent_expr(cx, match_expr) { - if let ExprKind::Closure { .. } = parent_expr.kind { - cbrace_end = format!("\n{indent}}}"); - // Fix body indent due to the closure - indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{indent}"); - } + if let Some(parent_expr) = get_parent_expr(cx, match_expr) + && let ExprKind::Closure { .. } = parent_expr.kind + { + cbrace_end = format!("\n{indent}}}"); + // Fix body indent due to the closure + indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); + cbrace_start = format!("{{\n{indent}"); } // If the parent is already an arm, and the body is another match statement, // we need curly braces around suggestion - if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id) { - if let ExprKind::Match(..) = arm.body.kind { - cbrace_end = format!("\n{indent}}}"); - // Fix body indent due to the match - indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{indent}"); - } + if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id) + && let ExprKind::Match(..) = arm.body.kind + { + cbrace_end = format!("\n{indent}}}"); + // Fix body indent due to the match + indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); + cbrace_start = format!("{{\n{indent}"); } let assignment_str = assignment.map_or_else(String::new, |span| { @@ -204,14 +198,17 @@ fn sugg_with_curlies<'a>( s }); + let ctxt = match_expr.span.ctxt(); let scrutinee = if needs_var_binding { format!( "let {} = {}", - snippet_with_applicability(cx, bind_names, "..", applicability), - snippet_with_applicability(cx, matched_vars, "..", applicability) + snippet_with_context(cx, bind_names, ctxt, "..", applicability).0, + snippet_with_context(cx, matched_vars, ctxt, "..", applicability).0 ) } else { - snippet_with_applicability(cx, matched_vars, "..", applicability).to_string() + snippet_with_context(cx, matched_vars, ctxt, "..", applicability) + .0 + .to_string() }; format!("{cbrace_start}{scrutinee};\n{indent}{assignment_str}{snippet_body}{cbrace_end}") diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index df1b83cbb516..65b93a095b92 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -26,10 +26,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm && let ty::Str = ty.kind() { let mut visitor = MatchExprVisitor { cx }; - if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee) { - if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) { - lint(cx, &case_method, bad_case_span, bad_case_sym.as_str()); - } + if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee) + && let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) + { + lint(cx, &case_method, bad_case_span, bad_case_sym.as_str()); } } } diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 11b588b33554..24b4a6758004 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -80,18 +80,20 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { path }, PatKind::TupleStruct(path, patterns, ..) => { - if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() { - if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) { - missing_variants.retain(|e| e.ctor_def_id() != Some(id)); - } + if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() + && arm.guard.is_none() + && patterns.iter().all(|p| !is_refutable(cx, p)) + { + missing_variants.retain(|e| e.ctor_def_id() != Some(id)); } path }, PatKind::Struct(path, patterns, ..) => { - if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() { - if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) { - missing_variants.retain(|e| e.def_id != id); - } + if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() + && arm.guard.is_none() + && patterns.iter().all(|p| !is_refutable(cx, p.pat)) + { + missing_variants.retain(|e| e.def_id != id); } path }, diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index d0d2025878e4..8ce8453360f7 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -26,11 +26,12 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if !matching_wild { // Looking for unused bindings (i.e.: `_e`) for pat in inner { - if let PatKind::Binding(_, id, ident, None) = pat.kind { - if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) { - ident_bind_name = ident.name; - matching_wild = true; - } + if let PatKind::Binding(_, id, ident, None) = pat.kind + && ident.as_str().starts_with('_') + && !is_local_used(cx, arm.body, id) + { + ident_bind_name = ident.name; + matching_wild = true; } } } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 2b9173e6f412..c6ebd6144c76 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -8,7 +8,6 @@ mod manual_utils; mod match_as_ref; mod match_bool; mod match_like_matches; -mod match_on_vec_items; mod match_ref_pats; mod match_same_arms; mod match_single_binding; @@ -724,38 +723,39 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `match vec[idx]` or `match vec[n..m]`. + /// Checks if a `match` or `if let` expression can be simplified using + /// `.unwrap_or_default()`. /// /// ### Why is this bad? - /// This can panic at runtime. + /// It can be done in one call with `.unwrap_or_default()`. /// /// ### Example - /// ```rust, no_run - /// let arr = vec![0, 1, 2, 3]; - /// let idx = 1; + /// ```no_run + /// let x: Option = Some(String::new()); + /// let y: String = match x { + /// Some(v) => v, + /// None => String::new(), + /// }; /// - /// match arr[idx] { - /// 0 => println!("{}", 0), - /// 1 => println!("{}", 3), - /// _ => {}, - /// } + /// let x: Option> = Some(Vec::new()); + /// let y: Vec = if let Some(v) = x { + /// v + /// } else { + /// Vec::new() + /// }; /// ``` - /// /// Use instead: - /// ```rust, no_run - /// let arr = vec![0, 1, 2, 3]; - /// let idx = 1; + /// ```no_run + /// let x: Option = Some(String::new()); + /// let y: String = x.unwrap_or_default(); /// - /// match arr.get(idx) { - /// Some(0) => println!("{}", 0), - /// Some(1) => println!("{}", 3), - /// _ => {}, - /// } + /// let x: Option> = Some(Vec::new()); + /// let y: Vec = x.unwrap_or_default(); /// ``` - #[clippy::version = "1.45.0"] - pub MATCH_ON_VEC_ITEMS, - pedantic, - "matching on vector elements can panic" + #[clippy::version = "1.79.0"] + pub MANUAL_UNWRAP_OR_DEFAULT, + suspicious, + "check if a `match` or `if let` can be simplified with `unwrap_or_default`" } declare_clippy_lint! { @@ -1040,7 +1040,7 @@ impl_lint_pass!(Matches => [ NEEDLESS_MATCH, COLLAPSIBLE_MATCH, MANUAL_UNWRAP_OR, - MATCH_ON_VEC_ITEMS, + MANUAL_UNWRAP_OR_DEFAULT, MATCH_STR_CASE_MISMATCH, SIGNIFICANT_DROP_IN_SCRUTINEE, TRY_ERR, @@ -1118,7 +1118,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_wild_enum::check(cx, ex, arms); match_as_ref::check(cx, ex, arms, expr); needless_match::check_match(cx, ex, arms, expr); - match_on_vec_items::check(cx, ex); match_str_case_mismatch::check(cx, ex, arms); redundant_guards::check(cx, arms, self.msrv); diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 7e65d586110e..6c5d7cab2036 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -67,10 +67,10 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) for arm in arms { let arm_expr = peel_blocks_with_stmt(arm.body); - if let Some(guard_expr) = &arm.guard { - if guard_expr.can_have_side_effects() { - return false; - } + if let Some(guard_expr) = &arm.guard + && guard_expr.can_have_side_effects() + { + return false; } if let PatKind::Wild = arm.pat.kind { diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 4184f8b9e6e8..d3136c89178e 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -11,17 +11,17 @@ use super::MATCH_OVERLAPPING_ARM; pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex)); - if !ranges.is_empty() { - if let Some((start, end)) = overlapping(&ranges) { - span_lint_and_note( - cx, - MATCH_OVERLAPPING_ARM, - start.span, - "some ranges overlap", - Some(end.span), - "overlaps with this", - ); - } + if !ranges.is_empty() + && let Some((start, end)) = overlapping(&ranges) + { + span_lint_and_note( + cx, + MATCH_OVERLAPPING_ARM, + start.span, + "some ranges overlap", + Some(end.span), + "overlaps with this", + ); } } } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 722ea7042dd7..db20be40f27e 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,7 +4,7 @@ use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; -use clippy_utils::{higher, is_expn_of, is_trait_method}; +use clippy_utils::{higher, is_expn_of, is_trait_method, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; @@ -12,7 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use std::fmt::Write; use std::ops::ControlFlow; @@ -138,9 +138,9 @@ fn find_method_and_type<'tcx>( Some(("is_some()", op_ty)) } else if Some(id) == lang_items.poll_ready_variant() { Some(("is_ready()", op_ty)) - } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V4)) { Some(("is_ipv4()", op_ty)) - } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V6)) { Some(("is_ipv6()", op_ty)) } else { None @@ -255,7 +255,7 @@ fn find_method_sugg_for_if_let<'tcx>( }; let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app) - .maybe_par() + .maybe_paren() .to_string(); diag.span_suggestion(span, "try", format!("{keyword} {sugg}.{good_method}"), app); @@ -279,7 +279,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op _ => op, }; let mut app = Applicability::MachineApplicable; - let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par(); + let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren(); let mut sugg = format!("{receiver_sugg}.{good_method}"); if let Some(guard) = maybe_guard { @@ -303,7 +303,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } let guard = Sugg::hir(cx, guard, ".."); - let _ = write!(sugg, " && {}", guard.maybe_par()); + let _ = write!(sugg, " && {}", guard.maybe_paren()); } span_lint_and_sugg( @@ -345,8 +345,8 @@ fn found_good_method<'tcx>( arms, path_left, path_right, - Item::Diag(sym::IpAddr, sym!(V4)), - Item::Diag(sym::IpAddr, sym!(V6)), + Item::Diag(sym::IpAddr, sym::V4), + Item::Diag(sym::IpAddr, sym::V6), "is_ipv4()", "is_ipv6()", ) @@ -437,8 +437,8 @@ fn get_good_method<'tcx>( "None" => (Item::Lang(OptionNone), "is_none()", "is_some()"), "Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"), "Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"), - "V4" => (Item::Diag(sym::IpAddr, sym!(V4)), "is_ipv4()", "is_ipv6()"), - "V6" => (Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv6()", "is_ipv4()"), + "V4" => (Item::Diag(sym::IpAddr, sym::V4), "is_ipv4()", "is_ipv6()"), + "V6" => (Item::Diag(sym::IpAddr, sym::V6), "is_ipv6()", "is_ipv4()"), _ => return None, }; return find_good_method_for_matches_macro( diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 37bac561a6e0..d7dc7604088f 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -182,17 +182,16 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { } fn has_sig_drop_attr_impl(&mut self, ty: Ty<'tcx>) -> bool { - if let Some(adt) = ty.ty_adt_def() { - if get_attr( + if let Some(adt) = ty.ty_adt_def() + && get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop", ) .count() > 0 - { - return true; - } + { + return true; } if !self.seen_types.insert(ty) { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 836c46240ce7..08c0caa4266c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, expr_block, snippet, snippet_block_with_context}; +use clippy_utils::source::{ + SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, +}; use clippy_utils::ty::implements_trait; use clippy_utils::{ is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, @@ -34,8 +36,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { #[rustfmt::skip] pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], expr: &'tcx Expr<'_>, contains_comments: bool) { if let [arm1, arm2] = arms - && arm1.guard.is_none() - && arm2.guard.is_none() + && !arms.iter().any(|arm| arm.guard.is_some() || arm.pat.span.from_expansion()) && !expr.span.from_expansion() // don't lint for or patterns for now, this makes // the lint noisy in unnecessary situations @@ -106,7 +107,7 @@ fn report_single_pattern( format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); - if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { + if ex.span.eq_ctxt(expr.span) && snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { let msg = "this pattern is irrefutable, `match` is useless"; let (sugg, help) = if is_unit_expr(arm.body) { (String::new(), "`match` expression can be removed") @@ -163,10 +164,10 @@ fn report_single_pattern( let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; let sugg = format!( "if {} == {}{} {}{els_str}", - snippet(cx, ex.span, ".."), + snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0, // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), - snippet(cx, arm.pat.span, ".."), + snippet_with_applicability(cx, arm.pat.span, "..", &mut app), expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) @@ -174,8 +175,8 @@ fn report_single_pattern( let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"; let sugg = format!( "if let {} = {} {}{els_str}", - snippet(cx, arm.pat.span, ".."), - snippet(cx, ex.span, ".."), + snippet_with_applicability(cx, arm.pat.span, "..", &mut app), + snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0, expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) diff --git a/clippy_lints/src/matches/wild_in_or_pats.rs b/clippy_lints/src/matches/wild_in_or_pats.rs index b75d1ab9a7aa..43102d78bfeb 100644 --- a/clippy_lints/src/matches/wild_in_or_pats.rs +++ b/clippy_lints/src/matches/wild_in_or_pats.rs @@ -15,18 +15,18 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) { return; } for arm in arms { - if let PatKind::Or(fields) = arm.pat.kind { + if let PatKind::Or(fields) = arm.pat.kind // look for multiple fields in this arm that contains at least one Wild pattern - if fields.len() > 1 && fields.iter().any(is_wild) { - span_lint_and_help( - cx, - WILDCARD_IN_OR_PATTERNS, - arm.pat.span, - "wildcard pattern covers any other pattern as it will match anyway", - None, - "consider handling `_` separately", - ); - } + && fields.len() > 1 && fields.iter().any(is_wild) + { + span_lint_and_help( + cx, + WILDCARD_IN_OR_PATTERNS, + arm.pat.span, + "wildcard pattern covers any other pattern as it will match anyway", + None, + "consider handling `_` separately", + ); } } } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index a0919947b3fc..a54d835b538c 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -145,7 +145,7 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E "consider `Option::take()` instead", format!( "{}.take()", - Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par() + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_paren() ), applicability, ); @@ -178,7 +178,7 @@ fn check_replace_option_with_some( "consider `Option::replace()` instead", format!( "{}.replace({})", - Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_par(), + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_paren(), snippet_with_applicability(cx, src_arg.span, "_", &mut applicability) ), applicability, @@ -304,14 +304,12 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { && let ExprKind::Path(ref func_qpath) = func.kind && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id) - { // Check that second argument is `Option::None` - if !check_replace_option_with_none(cx, src, dest, expr.span) - && !check_replace_option_with_some(cx, src, dest, expr.span, self.msrv) - && !check_replace_with_default(cx, src, dest, expr, self.msrv) - { - check_replace_with_uninit(cx, src, dest, expr.span); - } + && !check_replace_option_with_none(cx, src, dest, expr.span) + && !check_replace_option_with_some(cx, src, dest, expr.span, self.msrv) + && !check_replace_with_default(cx, src, dest, expr, self.msrv) + { + check_replace_with_uninit(cx, src, dest, expr.span); } } } diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 1e9b29f567f4..f8520c23ea50 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -192,10 +192,10 @@ impl BindInsteadOfMap { } fn is_variant(&self, cx: &LateContext<'_>, res: Res) -> bool { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item) { - return cx.tcx.parent(id) == variant_id; - } + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res + && let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item) + { + return cx.tcx.parent(id) == variant_id; } false } diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 18568e3661fe..d07870d4951e 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; @@ -16,14 +17,15 @@ pub(super) fn check<'tcx>( call_span: Span, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, + msrv: Msrv, ) { - if let ExprKind::MethodCall(path_segment, ..) = recv.kind { - if matches!( + if let ExprKind::MethodCall(path_segment, ..) = recv.kind + && matches!( path_segment.ident.name.as_str(), "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase" - ) { - return; - } + ) + { + return; } if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) @@ -58,11 +60,15 @@ pub(super) fn check<'tcx>( let suggestion_source = reindent_multiline( &format!( - "std::path::Path::new({}) + "std::path::Path::new({recv_source}) .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_source, - ext_str.strip_prefix('.').unwrap() + .{}|ext| ext.eq_ignore_ascii_case(\"{}\"))", + if msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) { + "is_some_and(" + } else { + "map_or(false, " + }, + ext_str.strip_prefix('.').unwrap(), ), true, Some(indent_of(cx, call_span).unwrap_or(0) + 4), diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 1ee27d90d054..2ecf3eb89798 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -40,10 +40,10 @@ pub(super) fn check( .map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target); let ty = cx.typeck_results().expr_ty(expr); - if let ty::Ref(_, inner, _) = arg_ty.kind() { - if let ty::Ref(..) = inner.kind() { - return; // don't report clone_on_copy - } + if let ty::Ref(_, inner, _) = arg_ty.kind() + && let ty::Ref(..) = inner.kind() + { + return; // don't report clone_on_copy } if is_copy(cx, ty) { diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index b5adc69e9a79..e666f31217cc 100644 --- a/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::implements_trait; +use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait}; use clippy_utils::{is_mutable, is_trait_method, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; @@ -27,10 +27,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id + && let self_ty = cx.typeck_results().expr_ty(self_expr) + && !has_non_owning_mutable_access(cx, self_ty) { let mut sugg = vec![(call_span, String::from("next_back()"))]; let mut dont_apply = false; + // if `self_expr` is a reference, it is mutable because it is used for `.last()` + // TODO: Change this to lint only when the referred iterator is not used later. If it is used later, + // changing to `next_back()` may change its behavior. if !(is_mutable(cx, self_expr) || self_type.is_ref()) { if let Some(hir_id) = path_to_local(self_expr) && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index daa6e0e7f940..f5688e370a47 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -54,10 +54,11 @@ pub(super) fn check<'tcx>( if is_type_lang_item(cx, arg_ty, hir::LangItem::String) { return false; } - if let ty::Ref(_, ty, ..) = arg_ty.kind() { - if ty.is_str() && can_be_static_str(cx, arg) { - return false; - } + if let ty::Ref(_, ty, ..) = arg_ty.kind() + && ty.is_str() + && can_be_static_str(cx, arg) + { + return false; } true } diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index ae300cd5fe56..da123f13d46f 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks}; +use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks, sym}; use hir::{Body, HirId, MatchSource, Pat}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -11,7 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol}; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; @@ -43,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool } fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { - is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_some) } fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { - is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok)) + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_ok) } #[derive(Debug, Copy, Clone)] @@ -429,16 +429,15 @@ fn is_find_or_filter<'a>( } fn acceptable_methods(method: &PathSegment<'_>) -> bool { - let methods: [Symbol; 8] = [ - sym::clone, - sym::as_ref, - sym!(copied), - sym!(cloned), - sym!(as_deref), - sym!(as_mut), - sym!(as_deref_mut), - sym!(to_owned), - ]; - - methods.contains(&method.ident.name) + matches!( + method.ident.name, + sym::clone + | sym::as_ref + | sym::copied + | sym::cloned + | sym::as_deref + | sym::as_mut + | sym::as_deref_mut + | sym::to_owned + ) } diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index f7e116c5310e..965993808f6b 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,10 +1,14 @@ use super::FILTER_MAP_BOOL_THEN; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; -use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks}; +use clippy_utils::{ + CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks, +}; +use rustc_ast::Mutability; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, HirId, Param, Pat}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Binder; use rustc_middle::ty::adjustment::Adjust; @@ -44,17 +48,69 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & && let Some(filter) = recv.span.get_source_text(cx) && let Some(map) = then_body.span.get_source_text(cx) { - span_lint_and_sugg( + span_lint_and_then( cx, FILTER_MAP_BOOL_THEN, call_span, "usage of `bool::then` in `filter_map`", - "use `filter` then `map` instead", - format!( - "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", - derefs = "*".repeat(needed_derefs) - ), - Applicability::MachineApplicable, + |diag| { + if can_filter_and_then_move_to_closure(cx, ¶m, recv, then_body) { + diag.span_suggestion( + call_span, + "use `filter` then `map` instead", + format!( + "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", + derefs = "*".repeat(needed_derefs) + ), + Applicability::MachineApplicable, + ); + } else { + diag.help("consider using `filter` then `map` instead"); + } + }, ); } } + +/// Returns a set of all bindings found in the given pattern. +fn find_bindings_from_pat(pat: &Pat<'_>) -> FxHashSet { + let mut bindings = FxHashSet::default(); + pat.walk(|p| { + if let rustc_hir::PatKind::Binding(_, hir_id, _, _) = p.kind { + bindings.insert(hir_id); + } + true + }); + bindings +} + +/// Returns true if we can take a closure parameter and have it in both the `filter` function and +/// the`map` function. This is not the case if: +/// +/// - The `filter` would contain an early return, +/// - `filter` and `then` contain captures, and any of those are &mut +fn can_filter_and_then_move_to_closure<'tcx>( + cx: &LateContext<'tcx>, + param: &Param<'tcx>, + filter: &'tcx Expr<'tcx>, + then: &'tcx Expr<'tcx>, +) -> bool { + if contains_return(filter) { + return false; + } + + let Some(filter_captures) = can_move_expr_to_closure(cx, filter) else { + return true; + }; + let Some(then_captures) = can_move_expr_to_closure(cx, then) else { + return true; + }; + + let param_bindings = find_bindings_from_pat(param.pat); + filter_captures.iter().all(|(hir_id, filter_cap)| { + param_bindings.contains(hir_id) + || !then_captures + .get(hir_id) + .is_some_and(|then_cap| matches!(*filter_cap | *then_cap, CaptureKind::Ref(Mutability::Mut))) + }) +} diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index f4840785584e..045363058d19 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,25 +1,31 @@ +use std::fmt::Write as _; + use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::Ty; +use rustc_middle::ty::GenericParamDefKind; use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>], func: &Expr<'_>) { if is_path_diagnostic_item(cx, func, sym::from_iter_fn) - && let ty = cx.typeck_results().expr_ty(expr) && let arg_ty = cx.typeck_results().expr_ty(&args[0]) && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) && implements_trait(cx, arg_ty, iter_id, &[]) { - // `expr` implements `FromIterator` trait - let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let turbofish = extract_turbofish(cx, expr, ty); + let mut app = Applicability::MaybeIncorrect; + let turbofish = match func.kind { + ExprKind::Path(QPath::TypeRelative(hir_ty, _)) => build_full_type(cx, hir_ty, &mut app), + ExprKind::Path(QPath::Resolved(Some(self_ty), _)) => build_full_type(cx, self_ty, &mut app), + _ => return, + }; + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_paren(); let sugg = format!("{iter_expr}.collect::<{turbofish}>()"); span_lint_and_sugg( cx, @@ -28,54 +34,47 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", sugg, - Applicability::MaybeIncorrect, + app, ); } } -fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> String { - fn strip_angle_brackets(s: &str) -> Option<&str> { - s.strip_prefix('<')?.strip_suffix('>') - } - - let call_site = expr.span.source_callsite(); - if let Some(snippet) = call_site.get_source_text(cx) - && let snippet_split = snippet.split("::").collect::>() - && let Some((_, elements)) = snippet_split.split_last() +/// Build a type which can be used in a turbofish syntax from `hir_ty`, either by copying the +/// existing generic arguments with the exception of elided lifetimes, or by inserting placeholders +/// for types and consts without default values. +fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applicability) -> String { + if let TyKind::Path(ty_qpath) = hir_ty.kind + && let QPath::Resolved(None, ty_path) = &ty_qpath + && let Res::Def(_, ty_did) = ty_path.res { - if let [type_specifier, _] = snippet_split.as_slice() - && let Some(type_specifier) = strip_angle_brackets(type_specifier) - && let Some((type_specifier, ..)) = type_specifier.split_once(" as ") - { - type_specifier.to_string() + let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::"); + let mut first = true; + let mut append = |arg: &str| { + write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap(); + first = false; + }; + if let Some(args) = ty_path.segments.last().and_then(|segment| segment.args) { + args.args + .iter() + .filter(|arg| !matches!(arg, GenericArg::Lifetime(lt) if lt.is_elided())) + .for_each(|arg| append(&snippet_with_applicability(cx, arg.span().source_callsite(), "_", app))); } else { - // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) - if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { - // remove the type specifier from the path elements - let without_ts = elements - .iter() - .filter_map(|e| { - if e == type_specifier { - None - } else { - Some((*e).to_string()) - } - }) - .collect::>(); - // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{type_specifier}", without_ts.join("::")) - } else { - // type is not explicitly specified so wildcards are needed - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` - let ty_str = ty.to_string(); - let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or(ty_str.len()); - let nb_wildcard = ty_str[start..end].split(',').count(); - let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{wildcards}>", elements.join("::")) - } + cx.tcx + .generics_of(ty_did) + .own_params + .iter() + .filter(|param| { + matches!( + param.kind, + GenericParamDefKind::Type { has_default: false, .. } + | GenericParamDefKind::Const { has_default: false, .. } + ) + }) + .for_each(|_| append("_")); } + ty_str.push_str([">", ""][usize::from(first)]); + ty_str } else { - ty.to_string() + snippet_with_applicability(cx, hir_ty.span.source_callsite(), "_", app).into() } } diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index 4c81b22861b4..545bef1a4c5b 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -14,15 +14,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ if expr.span.in_external_macro(cx.sess().source_map()) || !receiver.span.eq_ctxt(expr.span) { return; } - if let Some(parent) = get_parent_expr(cx, expr) { - if let Some(parent) = get_parent_expr(cx, parent) { - if is_inside_always_const_context(cx.tcx, expr.hir_id) - && let Some(macro_call) = root_macro_call(parent.span) - && is_assert_macro(cx, macro_call.def_id) - { - return; - } - } + if let Some(parent) = get_parent_expr(cx, expr) + && let Some(parent) = get_parent_expr(cx, parent) + && is_inside_always_const_context(cx.tcx, expr.hir_id) + && let Some(macro_call) = root_macro_call(parent.span) + && is_assert_macro(cx, macro_call.def_id) + { + return; } let init_expr = expr_or_init(cx, receiver); if !receiver.span.eq_ctxt(init_expr.span) { diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 49de83885a1c..17cc07b91c5d 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,16 +1,22 @@ use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{get_iterator_item_ty, is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::sym; use super::ITER_CLONED_COLLECT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) + let expr_ty = cx.typeck_results().expr_ty(expr); + if is_type_diagnostic_item(cx, expr_ty, sym::Vec) && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) + && let ty::Adt(_, args) = expr_ty.kind() + && let Some(iter_item_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty(recv)) + && let ty::Ref(_, iter_item_ty, _) = iter_item_ty.kind() + && *iter_item_ty == args.type_at(0) && let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) { span_lint_and_sugg( diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index bafabec7e069..adeff375c8aa 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -6,12 +6,12 @@ use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::QPath; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol}; /// /// Returns true if the expression is a method call to `method_name` @@ -154,7 +154,7 @@ fn expression_type( if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Option) && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder() && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def() - && is_method(cx, filter_arg, sym::Option, sym!(is_some), &[]) + && is_method(cx, filter_arg, sym::Option, sym::is_some, &[]) { return Some(FilterType::IsSome); } @@ -162,7 +162,7 @@ fn expression_type( if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Result) && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder() && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def() - && is_method(cx, filter_arg, sym::Result, sym!(is_ok), &[]) + && is_method(cx, filter_arg, sym::Result, sym::is_ok, &[]) { return Some(FilterType::IsOk); } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 94415fc91061..3ac9299ba915 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, } - && let ty = cx.typeck_results().expr_ty(recv) + && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) { let mut applicability = rustc_errors::Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 9b358235a40d..90d5d9df55ee 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -8,14 +8,14 @@ use rustc_span::sym; use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { - if is_trait_method(cx, expr, sym::Iterator) { - if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) { - span_lint( - cx, - ITERATOR_STEP_BY_ZERO, - expr.span, - "`Iterator::step_by(0)` will panic at runtime", - ); - } + if is_trait_method(cx, expr, sym::Iterator) + && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) + { + span_lint( + cx, + ITERATOR_STEP_BY_ZERO, + expr.span, + "`Iterator::step_by(0)` will panic at runtime", + ); } } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 13918ed11b87..18978a1d2bc8 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -106,15 +106,15 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { }; let check_lit = |expr: &hir::Expr<'_>, check_min: bool| { - if let hir::ExprKind::Lit(lit) = &expr.kind { - if let ast::LitKind::Int(value, _) = lit.node { - if value == maxval { - return Some(MinMax::Max); - } + if let hir::ExprKind::Lit(lit) = &expr.kind + && let ast::LitKind::Int(value, _) = lit.node + { + if value == maxval { + return Some(MinMax::Max); + } - if check_min && value == minval { - return Some(MinMax::Min); - } + if check_min && value == minval { + return Some(MinMax::Min); } } @@ -125,10 +125,10 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { return r; } - if ty.is_signed() { - if let hir::ExprKind::Unary(hir::UnOp::Neg, val) = &expr.kind { - return check_lit(val, true); - } + if ty.is_signed() + && let hir::ExprKind::Unary(hir::UnOp::Neg, val) = &expr.kind + { + return check_lit(val, true); } None diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 098721dc046f..8167e4f96053 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -77,7 +77,7 @@ pub(super) fn check( s @ Cow::Borrowed(_) => s, }, RepeatKind::String => Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app) - .maybe_par() + .maybe_paren() .to_string() .into(), }; diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 128b3695f48b..333a33f7527d 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -51,19 +51,19 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, Mutability::Not) => { - if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind { - if ident_eq(name, closure_expr) { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); - } + if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind + && ident_eq(name, closure_expr) + { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); } }, hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) => { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); - } + if ident_eq(name, inner) + && let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() + { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); } }, hir::ExprKind::MethodCall(method, obj, [], _) => { @@ -114,19 +114,17 @@ fn handle_path( ) { if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id() && cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id) - { // The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option` // and `Result`. - if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind() - && let args = args.as_slice() - && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type()) - && let ty::Ref(_, ty, Mutability::Not) = ty.kind() - && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind() - && lst.iter().all(|l| l.as_type() == Some(*ty)) - && !should_call_clone_as_function(cx, *ty) - { - lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); - } + && let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind() + && let args = args.as_slice() + && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type()) + && let ty::Ref(_, ty, Mutability::Not) = ty.kind() + && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind() + && lst.iter().all(|l| l.as_type() == Some(*ty)) + && !should_call_clone_as_function(cx, *ty) + { + lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); } } diff --git a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index 6cf0936c598f..a2a522a60687 100644 --- a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -41,7 +41,7 @@ fn extract_count_with_applicability( return Some(format!("{count}")); } let end_snippet = Sugg::hir_with_applicability(cx, end, "...", applicability) - .maybe_par() + .maybe_paren() .into_string(); if lower_bound == 0 { if range.limits == RangeLimits::Closed { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1d9296016e25..ad374dee516c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -114,6 +114,7 @@ mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; +mod swap_with_temporary; mod type_id_on_box; mod unbuffered_bytes; mod uninit_assumed_init; @@ -478,9 +479,6 @@ declare_clippy_lint! { /// Because you usually call `expect()` on the `Result` /// directly to get a better error message. /// - /// ### Known problems - /// The error type needs to implement `Debug` - /// /// ### Example /// ```no_run /// # let x = Ok::<_, ()>(()); @@ -2429,7 +2427,7 @@ declare_clippy_lint! { /// /// ### Limitations /// This lint currently only looks for usages of - /// `.then_some(..).unwrap_or(..)` and `.then(..).unwrap_or(..)`, but will be expanded + /// `.{then, then_some}(..).{unwrap_or, unwrap_or_else, unwrap_or_default}(..)`, but will be expanded /// to account for similar patterns. /// /// ### Example @@ -4286,7 +4284,7 @@ declare_clippy_lint! { /// ```no_run /// let last_arg = "echo hello world".split(' ').next_back(); /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.86.0"] pub DOUBLE_ENDED_ITERATOR_LAST, perf, "using `Iterator::last` on a `DoubleEndedIterator`" @@ -4478,12 +4476,59 @@ declare_clippy_lint! { /// ```no_run /// let _ = std::io::Error::other("bad".to_string()); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub IO_OTHER_ERROR, style, "calling `std::io::Error::new(std::io::ErrorKind::Other, _)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `std::mem::swap` with temporary values. + /// + /// ### Why is this bad? + /// Storing a new value in place of a temporary value which will + /// be dropped right after the `swap` is an inefficient way of performing + /// an assignment. The same result can be achieved by using a regular + /// assignment. + /// + /// ### Examples + /// ```no_run + /// fn replace_string(s: &mut String) { + /// std::mem::swap(s, &mut String::from("replaced")); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn replace_string(s: &mut String) { + /// *s = String::from("replaced"); + /// } + /// ``` + /// + /// Also, swapping two temporary values has no effect, as they will + /// both be dropped right after swapping them. This is likely an indication + /// of a bug. For example, the following code swaps the references to + /// the last element of the vectors, instead of swapping the elements + /// themselves: + /// + /// ```no_run + /// fn bug(v1: &mut [i32], v2: &mut [i32]) { + /// // Incorrect: swapping temporary references (`&mut &mut` passed to swap) + /// std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap()); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn correct(v1: &mut [i32], v2: &mut [i32]) { + /// std::mem::swap(v1.last_mut().unwrap(), v2.last_mut().unwrap()); + /// } + /// ``` + #[clippy::version = "1.88.0"] + pub SWAP_WITH_TEMPORARY, + complexity, + "detect swap with a temporary value" +} + #[expect(clippy::struct_excessive_bools)] pub struct Methods { avoid_breaking_exported_api: bool, @@ -4661,17 +4706,19 @@ impl_lint_pass!(Methods => [ UNBUFFERED_BYTES, MANUAL_CONTAINS, IO_OTHER_ERROR, + SWAP_WITH_TEMPORARY, ]); /// Extracts a method call name, args, and `Span` of the method name. pub fn method_call<'tcx>( recv: &'tcx Expr<'tcx>, ) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { - if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { - if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { - let name = path.ident.name.as_str(); - return Some((name, receiver, args, path.ident.span, call_span)); - } + if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind + && !args.iter().any(|e| e.span.from_expansion()) + && !receiver.span.from_expansion() + { + let name = path.ident.name.as_str(); + return Some((name, receiver, args, path.ident.span, call_span)); } None } @@ -4691,6 +4738,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { manual_c_str_literals::check(cx, expr, func, args, self.msrv); useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv); io_other_error::check(cx, expr, func, args, self.msrv); + swap_with_temporary::check(cx, expr, func, args); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -4992,7 +5040,7 @@ impl Methods { }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { - case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv); } path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles); }, @@ -5421,15 +5469,21 @@ impl Methods { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); }, Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or"); + obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or"); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("unwrap_or_default", []) => { - if let Some(("map", m_recv, [arg], span, _)) = method_call(recv) { - manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); + match method_call(recv) { + Some(("map", m_recv, [arg], span, _)) => { + manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); + }, + Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default"); + }, + _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, @@ -5441,7 +5495,15 @@ impl Methods { Some(("map", recv, [map_arg], _, _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or_else"); + obfuscated_if_else::check( + cx, + expr, + t_recv, + t_arg, + Some(u_arg), + then_method, + "unwrap_or_else", + ); }, _ => { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index e4a29b6560e5..6efaba525e3e 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -4,7 +4,9 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; +use clippy_utils::ty::{ + get_type_diagnostic_name, has_non_owning_mutable_access, make_normalized_projection, make_projection, +}; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, @@ -23,6 +25,7 @@ use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; +#[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, name_span: Span, @@ -30,6 +33,11 @@ pub(super) fn check<'tcx>( iter_expr: &'tcx Expr<'tcx>, call_span: Span, ) { + let iter_ty = cx.typeck_results().expr_ty(iter_expr); + if has_non_owning_mutable_access(cx, iter_ty) { + return; // don't lint if the iterator has side effects + } + match cx.tcx.parent_hir_node(collect_expr.hir_id) { Node::Expr(parent) => { check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr); @@ -377,20 +385,20 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { return; } - if let Some(hir_id) = path_to_local(recv) { - if let Some(index) = self.hir_id_uses_map.remove(&hir_id) { - if self - .illegal_mutable_capture_ids - .intersection(&self.current_mutably_captured_ids) - .next() - .is_none() - { - if let Some(hir_id) = self.current_statement_hir_id { - self.hir_id_uses_map.insert(hir_id, index); - } - } else { - self.uses[index] = None; + if let Some(hir_id) = path_to_local(recv) + && let Some(index) = self.hir_id_uses_map.remove(&hir_id) + { + if self + .illegal_mutable_capture_ids + .intersection(&self.current_mutably_captured_ids) + .next() + .is_none() + { + if let Some(hir_id) = self.current_statement_hir_id { + self.hir_id_uses_map.insert(hir_id, index); } + } else { + self.uses[index] = None; } } } diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 88b9c69f6f94..cd1b97f3c51b 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -9,26 +9,27 @@ use super::NEEDLESS_OPTION_TAKE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place - if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) { - if let Some(function_name) = source_of_temporary_value(recv) { - span_lint_and_then( - cx, - NEEDLESS_OPTION_TAKE, - expr.span, - "called `Option::take()` on a temporary value", - |diag| { - diag.note(format!( - "`{function_name}` creates a temporary value, so calling take() has no effect" - )); - diag.span_suggestion( - expr.span.with_lo(recv.span.hi()), - "remove", - "", - Applicability::MachineApplicable, - ); - }, - ); - } + if !recv.is_syntactic_place_expr() + && is_expr_option(cx, recv) + && let Some(function_name) = source_of_temporary_value(recv) + { + span_lint_and_then( + cx, + NEEDLESS_OPTION_TAKE, + expr.span, + "called `Option::take()` on a temporary value", + |diag| { + diag.note(format!( + "`{function_name}` creates a temporary value, so calling take() has no effect" + )); + diag.span_suggestion( + expr.span.with_lo(recv.span.hi()), + "remove", + "", + Applicability::MachineApplicable, + ); + }, + ); } } @@ -44,10 +45,10 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> { match expr.peel_borrows().kind { ExprKind::Call(function, _) => { - if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind { - if !func_path.segments.is_empty() { - return Some(func_path.segments[0].ident.name.as_str()); - } + if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind + && !func_path.segments.is_empty() + { + return Some(func_path.segments[0].ident.name.as_str()); } if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { return Some(func_path_segment.ident.name.as_str()); diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index 9a5ffdeaf4e8..1cc56de48763 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -14,14 +14,17 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, then_recv: &'tcx hir::Expr<'_>, then_arg: &'tcx hir::Expr<'_>, - unwrap_arg: &'tcx hir::Expr<'_>, + unwrap_arg: Option<&'tcx hir::Expr<'_>>, then_method_name: &str, unwrap_method_name: &str, ) { let recv_ty = cx.typeck_results().expr_ty(then_recv); if recv_ty.is_bool() { - let mut applicability = if switch_to_eager_eval(cx, then_arg) && switch_to_eager_eval(cx, unwrap_arg) { + let then_eager = switch_to_eager_eval(cx, then_arg); + let unwrap_eager = unwrap_arg.is_none_or(|arg| switch_to_eager_eval(cx, arg)); + + let mut applicability = if then_eager && unwrap_eager { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect @@ -36,16 +39,17 @@ pub(super) fn check<'tcx>( _ => return, }; - // FIXME: Add `unwrap_or_else` symbol + // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol let els = match unwrap_method_name { - "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability), - "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.kind => { + "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), + "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { let body = cx.tcx.hir_body(closure.body); snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, - "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.kind => { - snippet_with_applicability(cx, unwrap_arg.span, "_", &mut applicability) + "()" + "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { + snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()" }, + "unwrap_or_default" => "Default::default()".into(), _ => return, }; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6eeeea5d77c7..b78b082e460e 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -6,13 +6,13 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, + contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, sym, }; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use rustc_span::symbol::{self, Symbol, sym}; +use rustc_span::symbol::{self, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; @@ -66,8 +66,8 @@ pub(super) fn check<'tcx>( }; let sugg = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default), - ("or_insert", true) | ("or_insert_with", false) => sym!(or_default), + ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default, + ("or_insert", true) | ("or_insert_with", false) => sym::or_default, _ => return false, }; @@ -78,8 +78,7 @@ pub(super) fn check<'tcx>( .iter() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { - if assoc.is_method() - && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 + if assoc.is_method() && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 { Some(assoc.def_id) } else { diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index d318462e5841..8b51268da465 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -3,33 +3,33 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_enum_variant_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_enum_variant_ctor, sym}; use super::SEEK_FROM_CURRENT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) { - if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) { - let mut applicability = Applicability::MachineApplicable; - let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); + if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) + && implements_trait(cx, ty, def_id, &[]) + && arg_is_seek_from_current(cx, arg) + { + let mut applicability = Applicability::MachineApplicable; + let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEEK_FROM_CURRENT, - expr.span, - "using `SeekFrom::Current` to start from current position", - "replace with", - format!("{snip}.stream_position()"), - applicability, - ); - } + span_lint_and_sugg( + cx, + SEEK_FROM_CURRENT, + expr.span, + "using `SeekFrom::Current` to start from current position", + "replace with", + format!("{snip}.stream_position()"), + applicability, + ); } } @@ -37,14 +37,12 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Call(f, [arg]) = expr.kind && let ExprKind::Path(ref path) = f.kind && let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id() - && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id) - { + && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Current, ctor_call_id) // check if argument of `SeekFrom::Current` is `0` - if let ExprKind::Lit(lit) = arg.kind - && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node - { - return true; - } + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node + { + return true; } false diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7b1dd9e58c50..b8405a78f23a 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; +use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified, sym}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::SEEK_TO_START_INSTEAD_OF_REWIND; @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(func, [arg]) = arg.kind && let ExprKind::Path(ref path) = func.kind && let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id) + && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Start, ctor_call_id) && let ExprKind::Lit(lit) = arg.kind && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 4ccefb7ec9d7..d183457da25a 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -238,15 +238,14 @@ fn indirect_usage<'tcx>( unwrap_kind: Some(unwrap_kind), .. } = iter_usage + && parent_id == local_hir_id { - if parent_id == local_hir_id { - return Some(IndirectUsage { - name: ident.name, - span: stmt.span, - init_expr, - unwrap_kind, - }); - } + return Some(IndirectUsage { + name: ident.name, + span: stmt.span, + init_expr, + unwrap_kind, + }); } } diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 1bd48525f12d..788014d9bb63 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -13,11 +13,11 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr< && let closure_body = cx.tcx.hir_body(closure.body) && !cx.typeck_results().expr_ty(closure_body.value).is_unit() { - if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) { + if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) // A variable is used mutably inside of the closure. Suppress the lint. - if !map_mutated_vars.is_empty() { - return; - } + && !map_mutated_vars.is_empty() + { + return; } span_lint_and_help( cx, diff --git a/clippy_lints/src/methods/swap_with_temporary.rs b/clippy_lints/src/methods/swap_with_temporary.rs new file mode 100644 index 000000000000..de729fb343a3 --- /dev/null +++ b/clippy_lints/src/methods/swap_with_temporary.rs @@ -0,0 +1,125 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use rustc_ast::BorrowKind; +use rustc_errors::{Applicability, Diag}; +use rustc_hir::{Expr, ExprKind, Node, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::SWAP_WITH_TEMPORARY; + +const MSG_TEMPORARY: &str = "this expression returns a temporary value"; +const MSG_TEMPORARY_REFMUT: &str = "this is a mutable reference to a temporary value"; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) { + if let ExprKind::Path(QPath::Resolved(_, func_path)) = func.kind + && let Some(func_def_id) = func_path.res.opt_def_id() + && cx.tcx.is_diagnostic_item(sym::mem_swap, func_def_id) + { + match (ArgKind::new(&args[0]), ArgKind::new(&args[1])) { + (ArgKind::RefMutToTemp(left_temp), ArgKind::RefMutToTemp(right_temp)) => { + emit_lint_useless(cx, expr, &args[0], &args[1], left_temp, right_temp); + }, + (ArgKind::RefMutToTemp(left_temp), right) => emit_lint_assign(cx, expr, &right, &args[0], left_temp), + (left, ArgKind::RefMutToTemp(right_temp)) => emit_lint_assign(cx, expr, &left, &args[1], right_temp), + _ => {}, + } + } +} + +enum ArgKind<'tcx> { + // Mutable reference to a place, coming from a macro + RefMutToPlaceAsMacro(&'tcx Expr<'tcx>), + // Place behind a mutable reference + RefMutToPlace(&'tcx Expr<'tcx>), + // Temporary value behind a mutable reference + RefMutToTemp(&'tcx Expr<'tcx>), + // Any other case + Expr(&'tcx Expr<'tcx>), +} + +impl<'tcx> ArgKind<'tcx> { + fn new(arg: &'tcx Expr<'tcx>) -> Self { + if let ExprKind::AddrOf(BorrowKind::Ref, _, target) = arg.kind { + if target.is_syntactic_place_expr() { + if arg.span.from_expansion() { + ArgKind::RefMutToPlaceAsMacro(arg) + } else { + ArgKind::RefMutToPlace(target) + } + } else { + ArgKind::RefMutToTemp(target) + } + } else { + ArgKind::Expr(arg) + } + } +} + +// Emits a note either on the temporary expression if it can be found in the same context as the +// base and returns `true`, or on the mutable reference to the temporary expression otherwise and +// returns `false`. +fn emit_note(diag: &mut Diag<'_, ()>, base: &Expr<'_>, expr: &Expr<'_>, expr_temp: &Expr<'_>) -> bool { + if base.span.eq_ctxt(expr.span) { + diag.span_note(expr_temp.span.source_callsite(), MSG_TEMPORARY); + true + } else { + diag.span_note(expr.span.source_callsite(), MSG_TEMPORARY_REFMUT); + false + } +} + +fn emit_lint_useless( + cx: &LateContext<'_>, + expr: &Expr<'_>, + left: &Expr<'_>, + right: &Expr<'_>, + left_temp: &Expr<'_>, + right_temp: &Expr<'_>, +) { + span_lint_and_then( + cx, + SWAP_WITH_TEMPORARY, + expr.span, + "swapping temporary values has no effect", + |diag| { + emit_note(diag, expr, left, left_temp); + emit_note(diag, expr, right, right_temp); + }, + ); +} + +fn emit_lint_assign(cx: &LateContext<'_>, expr: &Expr<'_>, target: &ArgKind<'_>, reftemp: &Expr<'_>, temp: &Expr<'_>) { + span_lint_and_then( + cx, + SWAP_WITH_TEMPORARY, + expr.span, + "swapping with a temporary value is inefficient", + |diag| { + if !emit_note(diag, expr, reftemp, temp) { + return; + } + + // Make the suggestion only when the original `swap()` call is a statement + // or the last expression in a block. + if matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(..) | Node::Block(..)) { + let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + let assign_target = match target { + ArgKind::Expr(target) | ArgKind::RefMutToPlaceAsMacro(target) => { + Sugg::hir_with_context(cx, target, ctxt, "_", &mut applicability).deref() + }, + ArgKind::RefMutToPlace(target) => Sugg::hir_with_context(cx, target, ctxt, "_", &mut applicability), + ArgKind::RefMutToTemp(_) => unreachable!(), + }; + let assign_source = Sugg::hir_with_context(cx, temp, ctxt, "_", &mut applicability); + diag.span_suggestion( + expr.span, + "use assignment instead", + format!("{assign_target} = {assign_source}"), + applicability, + ); + } + }, + ); +} diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ca42a9ac04e0..f920f306bc1e 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,11 +1,10 @@ use super::utils::clone_or_copy_needed; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; @@ -45,30 +44,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome) && let hir::ExprKind::Path(_) = args[0].kind { - span_lint_and_sugg( + span_lint( cx, UNNECESSARY_FILTER_MAP, expr.span, - format!("{name} is unnecessary"), - "try removing the filter_map", - String::new(), - Applicability::MaybeIncorrect, + String::from("this call to `.filter_map(..)` is unnecessary"), ); + return; + } + if name == "filter_map" { + "map(..)" + } else { + "map(..).next()" } - if name == "filter_map" { "map" } else { "map(..).next()" } } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) { match cx.typeck_results().expr_ty(body.value).kind() { ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => { - if name == "filter_map" { "filter" } else { "find" } + if name == "filter_map" { "filter(..)" } else { "find(..)" } }, _ => return, } } else { return; }; - span_lint_and_sugg( + span_lint( cx, if name == "filter_map" { UNNECESSARY_FILTER_MAP @@ -76,10 +77,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a UNNECESSARY_FIND_MAP }, expr.span, - format!("this `.{name}` can be written more simply"), - "try instead", - sugg.to_string(), - Applicability::MaybeIncorrect, + format!("this `.{name}(..)` can be written more simply using `.{sugg}`"), ); } } diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 9f4080100da2..71e606add526 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -23,56 +23,61 @@ pub(super) fn check<'tcx>( let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); - if is_option || is_result || is_bool { - if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind { - let body = cx.tcx.hir_body(body); - let body_expr = &body.value; + if (is_option || is_result || is_bool) + && let hir::ExprKind::Closure(&hir::Closure { + body, + fn_decl, + kind: hir::ClosureKind::Closure, + .. + }) = arg.kind + { + let body = cx.tcx.hir_body(body); + let body_expr = &body.value; - if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { - return false; - } + if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { + return false; + } - if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { - let msg = if is_option { - "unnecessary closure used to substitute value for `Option::None`" - } else if is_result { - "unnecessary closure used to substitute value for `Result::Err`" - } else { - "unnecessary closure used with `bool::then`" - }; - let applicability = if body - .params - .iter() - // bindings are checked to be unused above - .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) - && matches!( - fn_decl.output, - FnRetTy::DefaultReturn(_) - | FnRetTy::Return(hir::Ty { - kind: hir::TyKind::Infer(()), - .. - }) - ) { - Applicability::MachineApplicable - } else { - // replacing the lambda may break type inference - Applicability::MaybeIncorrect - }; + if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { + let msg = if is_option { + "unnecessary closure used to substitute value for `Option::None`" + } else if is_result { + "unnecessary closure used to substitute value for `Result::Err`" + } else { + "unnecessary closure used with `bool::then`" + }; + let applicability = if body + .params + .iter() + // bindings are checked to be unused above + .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) + && matches!( + fn_decl.output, + FnRetTy::DefaultReturn(_) + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer(()), + .. + }) + ) { + Applicability::MachineApplicable + } else { + // replacing the lambda may break type inference + Applicability::MaybeIncorrect + }; - // This is a duplicate of what's happening in clippy_lints::methods::method_call, - // which isn't ideal, We want to get the method call span, - // but prefer to avoid changing the signature of the function itself. - if let hir::ExprKind::MethodCall(.., span) = expr.kind { - span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { - diag.span_suggestion_verbose( - span, - format!("use `{simplify_using}` instead"), - format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), - applicability, - ); - }); - return true; - } + // This is a duplicate of what's happening in clippy_lints::methods::method_call, + // which isn't ideal, We want to get the method call span, + // but prefer to avoid changing the signature of the function itself. + if let hir::ExprKind::MethodCall(.., span) = expr.kind { + span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { + diag.span_suggestion_verbose( + span, + format!("use `{simplify_using}` instead"), + format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), + applicability, + ); + }); + return true; } } } diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index d7bd522ddab9..b90748dd1585 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -76,7 +76,7 @@ pub(super) fn check<'a>( && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool)) && let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l } && switch_to_eager_eval(cx, non_binding_location) - // xor, because if its both then thats a strange edge case and + // xor, because if its both then that's a strange edge case and // we can just ignore it, since by default clippy will error on this && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id)) && !is_local_used(cx, non_binding_location, hir_id) @@ -92,7 +92,7 @@ pub(super) fn check<'a>( // we may need to add parens around the suggestion // in case the parent expression has additional method calls, // since for example `Some(5).map_or(false, |x| x == 5).then(|| 1)` - // being converted to `Some(5) == Some(5).then(|| 1)` isnt + // being converted to `Some(5) == Some(5).then(|| 1)` isn't // the same thing let inner_non_binding = Sugg::NonParen(Cow::Owned(format!( @@ -109,8 +109,8 @@ pub(super) fn check<'a>( let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) { match parent_expr.kind { - ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(), - ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(), + ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_paren(), + ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_paren(), _ => binop, } } else { diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 3611b341897a..b0cc7a785bc3 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -8,6 +8,9 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_span::symbol::sym; +/// Checks if `expr`, of type `ty`, corresponds to a slice or can be dereferenced to a slice, or if +/// `expr` is a method call to `.iter()` on such a type. In these cases, return the slice-like +/// expression. pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, diff --git a/clippy_lints/src/misc_early/builtin_type_shadow.rs b/clippy_lints/src/misc_early/builtin_type_shadow.rs index 662f7cd8500c..9ee1e2f3fd17 100644 --- a/clippy_lints/src/misc_early/builtin_type_shadow.rs +++ b/clippy_lints/src/misc_early/builtin_type_shadow.rs @@ -6,14 +6,14 @@ use rustc_lint::EarlyContext; use super::BUILTIN_TYPE_SHADOW; pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) { - if let GenericParamKind::Type { .. } = param.kind { - if let Some(prim_ty) = PrimTy::from_name(param.ident.name) { - span_lint( - cx, - BUILTIN_TYPE_SHADOW, - param.ident.span, - format!("this generic shadows the built-in type `{}`", prim_ty.name()), - ); - } + if let GenericParamKind::Type { .. } = param.kind + && let Some(prim_ty) = PrimTy::from_name(param.ident.name) + { + span_lint( + cx, + BUILTIN_TYPE_SHADOW, + param.ident.span, + format!("this generic shadows the built-in type `{}`", prim_ty.name()), + ); } } diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs index d5b5b2bf2dd1..3cb51671aaf1 100644 --- a/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/clippy_lints/src/misc_early/redundant_pattern.rs @@ -6,20 +6,20 @@ use rustc_lint::EarlyContext; use super::REDUNDANT_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind { - if let PatKind::Wild = right.kind { - span_lint_and_sugg( - cx, - REDUNDANT_PATTERN, - pat.span, - format!( - "the `{} @ _` pattern can be written as just `{}`", - ident.name, ident.name, - ), - "try", - format!("{}{}", ann.prefix_str(), ident.name), - Applicability::MachineApplicable, - ); - } + if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind + && let PatKind::Wild = right.kind + { + span_lint_and_sugg( + cx, + REDUNDANT_PATTERN, + pat.span, + format!( + "the `{} @ _` pattern can be written as just `{}`", + ident.name, ident.name, + ), + "try", + format!("{}{}", ann.prefix_str(), ident.name), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index 00f46629f102..fffaf40c9d14 100644 --- a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -7,30 +7,30 @@ use rustc_span::Span; use super::UNNEEDED_WILDCARD_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind { - if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) { - if let Some((left_index, left_pat)) = patterns[..rest_index] - .iter() - .rev() - .take_while(|pat| matches!(pat.kind, PatKind::Wild)) - .enumerate() - .last() - { - span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0); - } + if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind + && let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) + { + if let Some((left_index, left_pat)) = patterns[..rest_index] + .iter() + .rev() + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) + .enumerate() + .last() + { + span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0); + } - if let Some((right_index, right_pat)) = patterns[rest_index + 1..] - .iter() - .take_while(|pat| matches!(pat.kind, PatKind::Wild)) - .enumerate() - .last() - { - span_lint( - cx, - patterns[rest_index].span.shrink_to_hi().to(right_pat.span), - right_index == 0, - ); - } + if let Some((right_index, right_pat)) = patterns[rest_index + 1..] + .iter() + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) + .enumerate() + .last() + { + span_lint( + cx, + patterns[rest_index].span.shrink_to_hi().to(right_pat.span), + right_index == 0, + ); } } } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index d52fe7e7d5b9..394bc4aef1cc 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -111,10 +111,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { // Checks if impl_param_name is the same as one of type_param_names, // and is in a different position fn mismatch_param_name(i: usize, impl_param_name: &String, type_param_names: &FxHashMap<&String, usize>) -> bool { - if let Some(j) = type_param_names.get(impl_param_name) { - if i != *j { - return true; - } + if let Some(j) = type_param_names.get(impl_param_name) + && i != *j + { + return true; } false } diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index cdd6f4e5b033..c8e3462b24ef 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -3,14 +3,15 @@ use std::ops::ControlFlow; use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr, higher}; -use rustc_ast::{LitKind, RangeLimits}; +use rustc_ast::{BinOpKind, LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnindexMap; use rustc_errors::{Applicability, Diag}; -use rustc_hir::{BinOpKind, Block, Body, Expr, ExprKind, UnOp}; +use rustc_hir::{Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -134,18 +135,30 @@ fn assert_len_expr<'hir>( cx: &LateContext<'_>, expr: &'hir Expr<'hir>, ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> { - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) + let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind && let ExprKind::Binary(bin_op, left, right) = &condition.kind - - && let Some((cmp, asserted_len, slice_len)) = len_comparison(bin_op.node, left, right) - && let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind - && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice() - && method.ident.name == sym::len - // check if `then` block has a never type expression && let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind && cx.typeck_results().expr_ty(then_expr).is_never() + { + len_comparison(bin_op.node, left, right)? + } else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| { + match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::assert_eq_macro) => Some((macro_call, BinOpKind::Eq)), + Some(sym::assert_ne_macro) => Some((macro_call, BinOpKind::Ne)), + _ => None, + } + }) && let Some((left, right, _)) = find_assert_eq_args(cx, expr, macro_call.expn) + { + len_comparison(bin_op, left, right)? + } else { + return None; + }; + + if let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind + && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice() + && method.ident.name == sym::len { Some((cmp, asserted_len, recv)) } else { @@ -168,6 +181,7 @@ enum IndexEntry<'hir> { /// if the `assert!` asserts the right length. AssertWithIndex { highest_index: usize, + is_first_highest: bool, asserted_len: usize, assert_span: Span, slice: &'hir Expr<'hir>, @@ -177,6 +191,7 @@ enum IndexEntry<'hir> { /// Indexing without an `assert!` IndexWithoutAssert { highest_index: usize, + is_first_highest: bool, indexes: Vec, slice: &'hir Expr<'hir>, }, @@ -244,28 +259,41 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni assert_span, slice, } => { - *entry = IndexEntry::AssertWithIndex { - highest_index: index, - asserted_len: *asserted_len, - assert_span: *assert_span, - slice, - indexes: vec![expr.span], - comparison: *comparison, - }; + if slice.span.lo() > assert_span.lo() { + *entry = IndexEntry::AssertWithIndex { + highest_index: index, + is_first_highest: true, + asserted_len: *asserted_len, + assert_span: *assert_span, + slice, + indexes: vec![expr.span], + comparison: *comparison, + }; + } }, IndexEntry::IndexWithoutAssert { - highest_index, indexes, .. + highest_index, + indexes, + is_first_highest, + .. } | IndexEntry::AssertWithIndex { - highest_index, indexes, .. + highest_index, + indexes, + is_first_highest, + .. } => { indexes.push(expr.span); + if *is_first_highest { + (*is_first_highest) = *highest_index >= index; + } *highest_index = (*highest_index).max(index); }, } } else { indexes.push(IndexEntry::IndexWithoutAssert { highest_index: index, + is_first_highest: true, indexes: vec![expr.span], slice, }); @@ -284,15 +312,18 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un if let Some(entry) = entry { if let IndexEntry::IndexWithoutAssert { highest_index, + is_first_highest, indexes, slice, } = entry + && expr.span.lo() <= slice.span.lo() { *entry = IndexEntry::AssertWithIndex { highest_index: *highest_index, indexes: mem::take(indexes), + is_first_highest: *is_first_highest, slice, - assert_span: expr.span, + assert_span: expr.span.source_callsite(), comparison, asserted_len, }; @@ -301,7 +332,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un indexes.push(IndexEntry::StrayAssert { asserted_len, comparison, - assert_span: expr.span, + assert_span: expr.span.source_callsite(), slice, }); } @@ -325,12 +356,13 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap match *entry { IndexEntry::AssertWithIndex { highest_index, + is_first_highest, asserted_len, ref indexes, comparison, assert_span, slice, - } if indexes.len() > 1 => { + } if indexes.len() > 1 && !is_first_highest => { // if we have found an `assert!`, let's also check that it's actually right // and if it covers the highest index and if not, suggest the correct length let sugg = match comparison { @@ -378,8 +410,9 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap IndexEntry::IndexWithoutAssert { ref indexes, highest_index, + is_first_highest, slice, - } if indexes.len() > 1 => { + } if indexes.len() > 1 && !is_first_highest => { // if there was no `assert!` but more than one index, suggest // adding an `assert!` that covers the highest index report_lint( diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 38a19dd2999b..67537a251da7 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -139,12 +139,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { // Const fns are not allowed as methods in a trait. { let parent = cx.tcx.hir_get_parent_item(hir_id).def_id; - if parent != CRATE_DEF_ID { - if let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) { - if let hir::ItemKind::Trait(..) = &item.kind { - return; - } - } + if parent != CRATE_DEF_ID + && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) + && let hir::ItemKind::Trait(..) = &item.kind + { + return; } } @@ -156,9 +155,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - let mir = cx.tcx.optimized_mir(def_id); + let mir = cx.tcx.mir_drops_elaborated_and_const_checked(def_id); - if let Ok(()) = is_min_const_fn(cx, mir, self.msrv) + if let Ok(()) = is_min_const_fn(cx, &mir.borrow(), self.msrv) && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = cx.tcx.hir_node_by_def_id(def_id) { diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 28dc24274284..1932d2d5f978 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -209,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, self_path_did) = self_path.res && cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id) // don't trigger if this impl was derived - && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) + && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) && !item.span.from_expansion() // find `Debug::fmt` function && let Some(fmt_item) = items.iter().find(|i| i.ident.name == sym::fmt) @@ -224,11 +224,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { // NB: can't call cx.typeck_results() as we are not in a body && let typeck_results = cx.tcx.typeck_body(*body_id) && should_lint(cx, typeck_results, block) - { // we intentionally only lint structs, see lint description - if let ItemKind::Struct(_, data, _) = &self_item.kind { - check_struct(cx, typeck_results, block, self_ty, item, data); - } + && let ItemKind::Struct(_, data, _) = &self_item.kind + { + check_struct(cx, typeck_results, block, self_ty, item, data); } } } diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index f49e03ea7652..1f613171b46e 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -160,12 +160,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { AssocItemContainer::Impl => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id), }; - if let Some(trait_def_id) = trait_def_id { - if trait_def_id.is_local() && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) { - // If a trait is being implemented for an item, and the - // trait is not exported, we don't need #[inline] - return; - } + if let Some(trait_def_id) = trait_def_id + && trait_def_id.is_local() + && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) + { + // If a trait is being implemented for an item, and the + // trait is not exported, we don't need #[inline] + return; } let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index fbd287f52854..0e0855859628 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -135,10 +135,10 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { } fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(self.cx, e) { - if self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { - return; - } + if let Some(macro_call) = root_macro_call_first_node(self.cx, e) + && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" + { + return; } span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } @@ -328,22 +328,22 @@ impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> { return; } - if path_to_local_id(expr, self.var) { + if path_to_local_id(expr, self.var) // Check that this is a read, not a write. - if !is_in_assignment_position(self.cx, expr) { - span_lint_and_then( - self.cx, - MIXED_READ_WRITE_IN_EXPRESSION, - expr.span, - format!("unsequenced read of `{}`", self.cx.tcx.hir_name(self.var)), - |diag| { - diag.span_note( - self.write_expr.span, - "whether read occurs before this write depends on evaluation order", - ); - }, - ); - } + && !is_in_assignment_position(self.cx, expr) + { + span_lint_and_then( + self.cx, + MIXED_READ_WRITE_IN_EXPRESSION, + expr.span, + format!("unsequenced read of `{}`", self.cx.tcx.hir_name(self.var)), + |diag| { + diag.span_note( + self.write_expr.span, + "whether read occurs before this write depends on evaluation order", + ); + }, + ); } match expr.kind { // We're about to descend a closure. Since we don't know when (or @@ -373,10 +373,10 @@ impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> { /// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`. fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(parent) = get_parent_expr(cx, expr) { - if let ExprKind::Assign(lhs, ..) = parent.kind { - return lhs.hir_id == expr.hir_id; - } + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::Assign(lhs, ..) = parent.kind + { + return lhs.hir_id == expr.hir_id; } false } diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 7287193326f7..98614baffcea 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -119,22 +119,22 @@ impl EarlyLintPass for ModStyle { } for folder in &folder_segments { - if !mod_folders.contains(folder) { - if let Some((file, path)) = file_map.get(folder) { - span_lint_and_then( - cx, - SELF_NAMED_MODULE_FILES, - Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - format!("`mod.rs` files are required, found `{}`", path.display()), - |diag| { - let mut correct = path.to_path_buf(); - correct.pop(); - correct.push(folder); - correct.push("mod.rs"); - diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),)); - }, - ); - } + if !mod_folders.contains(folder) + && let Some((file, path)) = file_map.get(folder) + { + span_lint_and_then( + cx, + SELF_NAMED_MODULE_FILES, + Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), + format!("`mod.rs` files are required, found `{}`", path.display()), + |diag| { + let mut correct = path.to_path_buf(); + correct.pop(); + correct.push(folder); + correct.push("mod.rs"); + diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),)); + }, + ); } } } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2adc27c0b709..c6c27e22b90e 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -142,10 +142,9 @@ fn collect_unsafe_exprs<'tcx>( .typeck_results() .type_dependent_def_id(expr.hir_id) .map(|def_id| cx.tcx.fn_sig(def_id)) + && sig.skip_binder().safety().is_unsafe() { - if sig.skip_binder().safety().is_unsafe() { - unsafe_ops.push(("unsafe method call occurs here", expr.span)); - } + unsafe_ops.push(("unsafe method call occurs here", expr.span)); } }, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 7abc5870d00e..a45031ce22b9 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -82,10 +82,10 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) { - if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind { - if trait_ref_of_method(cx, item.owner_id.def_id).is_none() { - self.check_sig(cx, item.owner_id.def_id, sig.decl); - } + if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind + && trait_ref_of_method(cx, item.owner_id.def_id).is_none() + { + self.check_sig(cx, item.owner_id.def_id, sig.decl); } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 3c4ba5141dd9..d98c70e7f5a8 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -77,16 +77,16 @@ impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { expr.span, "generally you want to avoid `&mut &mut _` if possible", ); - } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { - if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) { - span_lint_hir( - self.cx, - MUT_MUT, - expr.hir_id, - expr.span, - "this expression mutably borrows a mutable reference. Consider reborrowing", - ); - } + } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() + && ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) + { + span_lint_hir( + self.cx, + MUT_MUT, + expr.hir_id, + expr.span, + "this expression mutably borrows a mutable reference. Consider reborrowing", + ); } } } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 13a23a13b9c2..270eebe07580 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -101,14 +101,13 @@ impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> { return; }, ExprKind::Path(_) => { - if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { - if adj + if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) + && adj .iter() .any(|a| matches!(a.target.kind(), ty::Ref(_, _, Mutability::Mut))) - { - self.found = true; - return; - } + { + self.found = true; + return; } }, // Don't check await desugars diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 49fd29d1dd6d..fe2157ca533a 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -91,19 +91,19 @@ declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); impl<'tcx> LateLintPass<'tcx> for Mutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(_, subst) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym::Mutex) { - let mutex_param = subst.type_at(0); - if let Some(atomic_name) = get_atomic_name(mutex_param) { - let msg = format!( - "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \ + if let ty::Adt(_, subst) = ty.kind() + && is_type_diagnostic_item(cx, ty, sym::Mutex) + { + let mutex_param = subst.type_at(0); + if let Some(atomic_name) = get_atomic_name(mutex_param) { + let msg = format!( + "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \ behavior and not the internal type, consider using `Mutex<()>`" - ); - match *mutex_param.kind() { - ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), - ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), - } + ); + match *mutex_param.kind() { + ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), } } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 2eacd6875d6b..f768e11a4a2b 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { || is_receiver_of_method_call(cx, e) || is_as_argument(cx, e) { - snip = snip.maybe_par(); + snip = snip.maybe_paren(); } span_lint_and_sugg( @@ -426,10 +426,10 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option { } fn fetch_bool_expr(expr: &Expr<'_>) -> Option { - if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind { - if let LitKind::Bool(value) = lit_ptr.node { - return Some(value); - } + if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind + && let LitKind::Bool(value) = lit_ptr.node + { + return Some(value); } None } diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index b61061d076b7..7052e1d0fbe5 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -86,11 +86,11 @@ fn should_skip<'tcx>( return false; } - if let PatKind::Binding(.., name, _) = arg.pat.kind { + if let PatKind::Binding(.., name, _) = arg.pat.kind // If it's a potentially unused variable, we don't check it. - if name.name == kw::Underscore || name.as_str().starts_with('_') { - return true; - } + && (name.name == kw::Underscore || name.as_str().starts_with('_')) + { + return true; } // All spans generated from a proc-macro invocation are the same... @@ -164,13 +164,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { }; // Exclude non-inherent impls - if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) { - if matches!( + if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) + && matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) - ) { - return; - } + ) + { + return; } let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity(); @@ -353,10 +353,10 @@ impl MutablyUsedVariablesCtxt<'_> { for (parent, node) in self.tcx.hir_parent_iter(item) { if let Some(fn_sig) = self.tcx.hir_fn_sig_by_hir_id(parent) { return fn_sig.header.is_unsafe(); - } else if let Node::Block(block) = node { - if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) { - return true; - } + } else if let Node::Block(block) = node + && matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) + { + return true; } } false @@ -426,10 +426,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { // upon! self.add_mutably_used_var(*vid); } - } else if borrow == ty::BorrowKind::Immutable { + } else if borrow == ty::BorrowKind::Immutable // If there is an `async block`, it'll contain a call to a closure which we need to // go into to ensure all "mutate" checks are found. - if let Node::Expr(Expr { + && let Node::Expr(Expr { kind: ExprKind::Call( _, @@ -442,9 +442,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { ), .. }) = self.tcx.hir_node(cmt.hir_id) - { - self.async_closures.insert(*def_id); - } + { + self.async_closures.insert(*def_id); } } @@ -460,10 +459,9 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { }), .. } = &cmt.place + && !projections.is_empty() { - if !projections.is_empty() { - self.add_mutably_used_var(*vid); - } + self.add_mutably_used_var(*vid); } } @@ -477,10 +475,9 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { }), .. } = &cmt.place + && self.is_in_unsafe_block(id) { - if self.is_in_unsafe_block(id) { - self.add_mutably_used_var(*vid); - } + self.add_mutably_used_var(*vid); } self.prev_bind = None; } @@ -499,15 +496,14 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { }), .. } = &cmt.place + && let FakeReadCause::ForLet(Some(inner)) = cause { - if let FakeReadCause::ForLet(Some(inner)) = cause { - // Seems like we are inside an async function. We need to store the closure `DefId` - // to go through it afterwards. - self.async_closures.insert(inner); - self.add_alias(cmt.hir_id, *vid); - self.prev_move_to_closure.insert(*vid); - self.prev_bind = None; - } + // Seems like we are inside an async function. We need to store the closure `DefId` + // to go through it afterwards. + self.async_closures.insert(inner); + self.add_alias(cmt.hir_id, *vid); + self.prev_move_to_closure.insert(*vid); + self.prev_bind = None; } } @@ -522,10 +518,9 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { }), .. } = &cmt.place + && self.is_in_unsafe_block(id) { - if self.is_in_unsafe_block(id) { - self.add_mutably_used_var(*vid); - } + self.add_mutably_used_var(*vid); } } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 978fde33d517..275d710c76a9 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -98,13 +98,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Exclude non-inherent impls - if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) { - if matches!( + if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) + && matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) - ) { - return; - } + ) + { + return; } // Allow `Borrow` or functions to be taken by value @@ -197,20 +197,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { { // Dereference suggestion let sugg = |diag: &mut Diag<'_, ()>| { - if let ty::Adt(def, ..) = ty.kind() { - if let Some(span) = cx.tcx.hir_span_if_local(def.did()) { - if type_allowed_to_implement_copy( - cx.tcx, - cx.param_env, - ty, - traits::ObligationCause::dummy_with_span(span), - rustc_hir::Safety::Safe, - ) - .is_ok() - { - diag.span_help(span, "or consider marking this type as `Copy`"); - } - } + if let ty::Adt(def, ..) = ty.kind() + && let Some(span) = cx.tcx.hir_span_if_local(def.did()) + && type_allowed_to_implement_copy( + cx.tcx, + cx.param_env, + ty, + traits::ObligationCause::dummy_with_span(span), + rustc_hir::Safety::Safe, + ) + .is_ok() + { + diag.span_help(span, "or consider marking this type as `Copy`"); } if is_type_diagnostic_item(cx, ty, sym::Vec) @@ -254,29 +252,28 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { return; } - if is_type_lang_item(cx, ty, LangItem::String) { - if let Some(clone_spans) = + if is_type_lang_item(cx, ty, LangItem::String) + && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) - { + { + diag.span_suggestion( + input.span, + "consider changing the type to", + "&str", + Applicability::Unspecified, + ); + + for (span, suggestion) in clone_spans { diag.span_suggestion( - input.span, - "consider changing the type to", - "&str", + span, + span.get_source_text(cx) + .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), + suggestion, Applicability::Unspecified, ); - - for (span, suggestion) in clone_spans { - diag.span_suggestion( - span, - span.get_source_text(cx) - .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), - suggestion, - Applicability::Unspecified, - ); - } - - return; } + + return; } diag.span_suggestion_verbose( diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index cce0617ba392..4a86c3720ca2 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -53,18 +53,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Struct(_, fields, StructTailExpr::Base(base)) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, _) = ty.kind() { - let variant = def.non_enum_variant(); - if fields.len() == variant.fields.len() - && !variant.is_field_list_non_exhaustive() - { - span_lint( - cx, - NEEDLESS_UPDATE, - base.span, - "struct update has no effect, all the fields in the struct have already been specified", - ); - } + if let ty::Adt(def, _) = ty.kind() + && fields.len() == def.non_enum_variant().fields.len() + && !def.variant(0_usize.into()).is_field_list_non_exhaustive() + { + span_lint( + cx, + NEEDLESS_UPDATE, + base.span, + "struct update has no effect, all the fields in the struct have already been specified", + ); } } } diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 429afff9b664..74c8142787eb 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -16,9 +16,6 @@ declare_clippy_lint! { /// ### Why is this bad? /// It's more readable to just negate. /// - /// ### Known problems - /// This only catches integers (for now). - /// /// ### Example /// ```rust,ignore /// let a = x * -1; @@ -38,23 +35,32 @@ declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]); impl<'tcx> LateLintPass<'tcx> for NegMultiply { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref op, left, right) = e.kind { - if BinOpKind::Mul == op.node { - match (&left.kind, &right.kind) { - (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {}, - (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right), - (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left), - _ => {}, - } + if let ExprKind::Binary(ref op, left, right) = e.kind + && BinOpKind::Mul == op.node + { + match (&left.kind, &right.kind) { + (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {}, + (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right), + (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left), + _ => {}, } } } } fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { + const F16_ONE: u16 = 1.0_f16.to_bits(); + const F128_ONE: u128 = 1.0_f128.to_bits(); if let ExprKind::Lit(l) = lit.kind - && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1) - && cx.typeck_results().expr_ty(exp).is_integral() + && matches!( + consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)), + Constant::Int(1) + | Constant::F16(F16_ONE) + | Constant::F32(1.0) + | Constant::F64(1.0) + | Constant::F128(F128_ONE) + ) + && cx.typeck_results().expr_ty(exp).is_numeric() { let mut applicability = Applicability::MachineApplicable; let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 1e469c3b63a4..4b73a4455f55 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -99,10 +99,10 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let mut impls = HirIdSet::default(); for &d in cx.tcx.local_trait_impls(default_trait_id) { let ty = cx.tcx.type_of(d).instantiate_identity(); - if let Some(ty_def) = ty.ty_adt_def() { - if let Some(local_def_id) = ty_def.did().as_local() { - impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id)); - } + if let Some(ty_def) = ty.ty_adt_def() + && let Some(local_def_id) = ty_def.did().as_local() + { + impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id)); } } self.impling_types = Some(impls); diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 7187a8f2c11a..7ab7976d5697 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -182,23 +182,22 @@ impl NoEffect { ); return true; } - } else if let StmtKind::Let(local) = stmt.kind { - if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) - && !matches!(local.source, LocalSource::AsyncFn) - && let Some(init) = local.init - && local.els.is_none() - && !local.pat.span.from_expansion() - && has_no_effect(cx, init) - && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind - && ident.name.to_ident_string().starts_with('_') - && !in_automatically_derived(cx.tcx, local.hir_id) - { - if let Some(l) = self.local_bindings.last_mut() { - l.push(hir_id); - self.underscore_bindings.insert(hir_id, ident.span); - } - return true; + } else if let StmtKind::Let(local) = stmt.kind + && !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) + && !matches!(local.source, LocalSource::AsyncFn) + && let Some(init) = local.init + && local.els.is_none() + && !local.pat.span.from_expansion() + && has_no_effect(cx, init) + && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind + && ident.name.to_ident_string().starts_with('_') + && !in_automatically_derived(cx.tcx, local.hir_id) + { + if let Some(l) = self.local_bindings.last_mut() { + l.push(hir_id); + self.underscore_bindings.insert(hir_id, ident.span); } + return true; } false } diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 448bb603cf2c..93865197ec96 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -1,6 +1,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; +use clippy_utils::{ + is_diag_trait_item, is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core, +}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; @@ -98,7 +100,7 @@ declare_clippy_lint! { /// /// impl PartialOrd for A { /// fn partial_cmp(&self, other: &Self) -> Option { - /// Some(self.cmp(other)) + /// Some(self.cmp(other)) // or self.cmp(other).into() /// } /// } /// ``` @@ -185,65 +187,66 @@ impl LateLintPass<'_> for NonCanonicalImpls { if block.stmts.is_empty() && let Some(expr) = block.expr - && expr_is_cmp(cx, &expr.kind, impl_item, &mut needs_fully_qualified) + && expr_is_cmp(cx, expr, impl_item, &mut needs_fully_qualified) { + return; } // Fix #12683, allow [`needless_return`] here else if block.expr.is_none() && let Some(stmt) = block.stmts.first() && let rustc_hir::StmtKind::Semi(Expr { - kind: ExprKind::Ret(Some(Expr { kind: ret_kind, .. })), + kind: ExprKind::Ret(Some(ret)), .. }) = stmt.kind - && expr_is_cmp(cx, ret_kind, impl_item, &mut needs_fully_qualified) + && expr_is_cmp(cx, ret, impl_item, &mut needs_fully_qualified) { - } else { - // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid - // suggestion tons more complex. - if let [lhs, rhs, ..] = trait_impl.args.as_slice() - && lhs != rhs - { - return; - } - - span_lint_and_then( - cx, - NON_CANONICAL_PARTIAL_ORD_IMPL, - item.span, - "non-canonical implementation of `partial_cmp` on an `Ord` type", - |diag| { - let [_, other] = body.params else { - return; - }; - let Some(std_or_core) = std_or_core(cx) else { - return; - }; - - let suggs = match (other.pat.simple_ident(), needs_fully_qualified) { - (Some(other_ident), true) => vec![( - block.span, - format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name), - )], - (Some(other_ident), false) => { - vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))] - }, - (None, true) => vec![ - ( - block.span, - format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"), - ), - (other.pat.span, "other".to_owned()), - ], - (None, false) => vec![ - (block.span, "{ Some(self.cmp(other)) }".to_owned()), - (other.pat.span, "other".to_owned()), - ], - }; - - diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified); - }, - ); + return; } + // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid + // suggestion tons more complex. + else if let [lhs, rhs, ..] = trait_impl.args.as_slice() + && lhs != rhs + { + return; + } + + span_lint_and_then( + cx, + NON_CANONICAL_PARTIAL_ORD_IMPL, + item.span, + "non-canonical implementation of `partial_cmp` on an `Ord` type", + |diag| { + let [_, other] = body.params else { + return; + }; + let Some(std_or_core) = std_or_core(cx) else { + return; + }; + + let suggs = match (other.pat.simple_ident(), needs_fully_qualified) { + (Some(other_ident), true) => vec![( + block.span, + format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name), + )], + (Some(other_ident), false) => { + vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))] + }, + (None, true) => vec![ + ( + block.span, + format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"), + ), + (other.pat.span, "other".to_owned()), + ], + (None, false) => vec![ + (block.span, "{ Some(self.cmp(other)) }".to_owned()), + (other.pat.span, "other".to_owned()), + ], + }; + + diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified); + }, + ); } } } @@ -251,10 +254,11 @@ impl LateLintPass<'_> for NonCanonicalImpls { /// Return true if `expr_kind` is a `cmp` call. fn expr_is_cmp<'tcx>( cx: &LateContext<'tcx>, - expr_kind: &'tcx ExprKind<'tcx>, + expr: &'tcx Expr<'tcx>, impl_item: &ImplItem<'_>, needs_fully_qualified: &mut bool, ) -> bool { + let impl_item_did = impl_item.owner_id.def_id; if let ExprKind::Call( Expr { kind: ExprKind::Path(some_path), @@ -262,11 +266,17 @@ fn expr_is_cmp<'tcx>( .. }, [cmp_expr], - ) = expr_kind + ) = expr.kind { is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) // Fix #11178, allow `Self::cmp(self, ..)` too - && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, needs_fully_qualified) + && self_cmp_call(cx, cmp_expr, impl_item_did, needs_fully_qualified) + } else if let ExprKind::MethodCall(_, recv, [], _) = expr.kind { + cx.tcx + .typeck(impl_item_did) + .type_dependent_def_id(expr.hir_id) + .is_some_and(|def_id| is_diag_trait_item(cx, def_id, sym::Into)) + && self_cmp_call(cx, recv, impl_item_did, needs_fully_qualified) } else { false } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 9b53608ae7f3..63859c0396e4 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -449,7 +449,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { dereferenced_expr = parent_expr; }, - ExprKind::Index(e, _, _) if ptr::eq(&**e, cur_expr) => { + ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => { // `e[i]` => desugared to `*Index::index(&e, i)`, // meaning `e` must be referenced. // no need to go further up since a method call is involved now. diff --git a/clippy_lints/src/non_std_lazy_statics.rs b/clippy_lints/src/non_std_lazy_statics.rs index 8305bf345ef1..f6bc9428d65f 100644 --- a/clippy_lints/src/non_std_lazy_statics.rs +++ b/clippy_lints/src/non_std_lazy_statics.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// static FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "FOO".to_lowercase()); /// static BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "BAR".to_lowercase()); /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.86.0"] pub NON_STD_LAZY_STATICS, pedantic, "lazy static that could be replaced by `std::sync::LazyLock`" @@ -121,7 +121,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { cx, NON_STD_LAZY_STATICS, macro_call.span, - "this macro has been superceded by `std::sync::LazyLock`", + "this macro has been superseded by `std::sync::LazyLock`", ); return; } @@ -240,7 +240,7 @@ impl LazyInfo { cx, NON_STD_LAZY_STATICS, self.ty_span_no_args, - "this type has been superceded by `LazyLock` in the standard library", + "this type has been superseded by `LazyLock` in the standard library", |diag| { diag.multipart_suggestion("use `std::sync::LazyLock` instead", suggs, appl); }, diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index 16c4391c0fbe..635f5678e2a6 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -82,11 +82,10 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit if let ty::Adt(adt_def, _) = receiver_ty.kind() && adt_def.is_struct() && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + && let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { - if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { - let arg_snippet = get_arg_snippet(cx, arg, rcv_path); - suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability); - } + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability); } } } diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index cf6b8992973a..9b2cfd91b853 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -98,7 +98,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let arg_snip = snippet(cx, arg_span, ".."); let expr_snip; let eq_impl; - if with_deref.is_implemented() { + if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { expr_snip = format!("*{arg_snip}"); eq_impl = with_deref; } else { diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index 74e0a6333db0..047a5a0159cb 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -50,7 +50,7 @@ pub(crate) fn check<'tcx>( // format the suggestion let suggestion = format!( "{}.abs()", - sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_par() + sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_paren() ); // spans the lint span_lint_and_then( diff --git a/clippy_lints/src/operators/identity_op.rs b/clippy_lints/src/operators/identity_op.rs index 035823228278..e1fd09549a4b 100644 --- a/clippy_lints/src/operators/identity_op.rs +++ b/clippy_lints/src/operators/identity_op.rs @@ -103,7 +103,7 @@ enum Parens { /// /// e.g. `-(x + y + 0)` cannot be reduced to `-x + y`, as the behavior changes silently. /// e.g. `1u64 + ((x + y + 0i32) as u64)` cannot be reduced to `1u64 + x + y as u64`, since -/// the the cast expression will not apply to the same expression. +/// the cast expression will not apply to the same expression. /// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced /// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be /// interpreted as a statement. The same behavior happens for `match`, `loop`, diff --git a/clippy_lints/src/operators/modulo_one.rs b/clippy_lints/src/operators/modulo_one.rs index fc5565e821ed..2e6a071eb184 100644 --- a/clippy_lints/src/operators/modulo_one.rs +++ b/clippy_lints/src/operators/modulo_one.rs @@ -12,15 +12,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right: span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } - if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { - if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { - span_lint( - cx, - MODULO_ONE, - expr.span, - "any number modulo -1 will panic/overflow or result in 0", - ); - } + if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() + && is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) + { + span_lint( + cx, + MODULO_ONE, + expr.span, + "any number modulo -1 will panic/overflow or result in 0", + ); } } } diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index 96c9775e292e..e6be536ca0f4 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -75,10 +75,10 @@ impl Context { hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => { let body_span = cx.tcx.hir_span_with_body(body_owner); - if let Some(span) = self.const_span { - if span.contains(body_span) { - return; - } + if let Some(span) = self.const_span + && span.contains(body_span) + { + return; } self.const_span = Some(body_span); }, @@ -90,10 +90,10 @@ impl Context { let body_owner = cx.tcx.hir_body_owner(body.id()); let body_span = cx.tcx.hir_span_with_body(body_owner); - if let Some(span) = self.const_span { - if span.contains(body_span) { - return; - } + if let Some(span) = self.const_span + && span.contains(body_span) + { + return; } self.const_span = None; } diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index 378fed481f4f..0faa7b9e6466 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -47,12 +47,11 @@ pub(crate) fn check<'tcx>( let rty = cx.typeck_results().expr_ty(r); let lcpy = is_copy(cx, lty); let rcpy = is_copy(cx, rty); - if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { - if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) - || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) - { - return; // Don't lint - } + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) + && ((are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))) + { + return; // Don't lint } // either operator autorefs or both args are copyable if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) { @@ -86,7 +85,7 @@ pub(crate) fn check<'tcx>( left.span, "use the left value directly", lsnip, - Applicability::MaybeIncorrect, // FIXME #2597 + Applicability::MachineApplicable, ); }, ); @@ -105,7 +104,7 @@ pub(crate) fn check<'tcx>( right.span, "use the right value directly", rsnip, - Applicability::MaybeIncorrect, // FIXME #2597 + Applicability::MachineApplicable, ); }, ); @@ -137,7 +136,7 @@ pub(crate) fn check<'tcx>( left.span, "use the left value directly", lsnip, - Applicability::MaybeIncorrect, // FIXME #2597 + Applicability::MachineApplicable, ); }, ); @@ -164,7 +163,7 @@ pub(crate) fn check<'tcx>( right.span, "use the right value directly", rsnip, - Applicability::MaybeIncorrect, // FIXME #2597 + Applicability::MachineApplicable, ); }); } diff --git a/clippy_lints/src/operators/verbose_bit_mask.rs b/clippy_lints/src/operators/verbose_bit_mask.rs index a6aba33e431a..147737891412 100644 --- a/clippy_lints/src/operators/verbose_bit_mask.rs +++ b/clippy_lints/src/operators/verbose_bit_mask.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( e.span, "bit mask could be simplified with a call to `trailing_zeros`", |diag| { - let sugg = Sugg::hir(cx, left1, "...").maybe_par(); + let sugg = Sugg::hir(cx, left1, "...").maybe_paren(); diag.span_suggestion( e.span, "try", diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 6f302ea19621..9487cec87efb 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -4,8 +4,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_copy; use clippy_utils::{ - CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, - is_res_lang_ctor, peel_blocks, peel_hir_expr_while, + CaptureKind, can_move_expr_to_closure, eager_or_lazy, expr_requires_coercion, higher, is_else_clause, + is_in_const_context, is_res_lang_ctor, peel_blocks, peel_hir_expr_while, }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -106,7 +106,7 @@ struct OptionOccurrence { fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", - cond_sugg.maybe_par(), + cond_sugg.maybe_paren(), if as_mut { ".as_mut()" } else if as_ref { @@ -212,6 +212,15 @@ fn try_get_option_occurrence<'tcx>( } } + let some_body_ty = cx.typeck_results().expr_ty(some_body); + let none_body_ty = cx.typeck_results().expr_ty(none_body); + // Check if coercion is needed for the `None` arm. If so, we cannot suggest because it will + // introduce a type mismatch. A special case is when both arms have the same type, then + // coercion is fine. + if some_body_ty != none_body_ty && expr_requires_coercion(cx, none_body) { + return None; + } + let mut app = Applicability::Unspecified; let (none_body, is_argless_call) = match none_body.kind { diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 65671b478ba7..8eaf65e63065 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { items: impl_items, .. }) = item.kind - && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) + && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) && let Some(eq_trait) = cx.tcx.lang_items().eq_trait() && trait_ref.path.res.def_id() == eq_trait { diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 6d4216970cc4..9b9024c81057 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { let sugg = format!( "{}.{}", sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability) - .maybe_par(), + .maybe_paren(), if is_eq { "is_none()" } else { "is_some()" } ); diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0a8e28856487..5d30b66def2c 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -178,19 +178,18 @@ impl PassByRefOrValue { && size <= self.ref_min_size && let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind { - if let Some(typeck) = cx.maybe_typeck_results() { + if let Some(typeck) = cx.maybe_typeck_results() // Don't lint if a raw pointer is created. // TODO: Limit the check only to raw pointers to the argument (or part of the argument) // which escape the current function. - if typeck.node_types().items().any(|(_, &ty)| ty.is_raw_ptr()) + && (typeck.node_types().items().any(|(_, &ty)| ty.is_raw_ptr()) || typeck .adjustments() .items() .flat_map(|(_, a)| a) - .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer))) - { - continue; - } + .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer)))) + { + continue; } let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) { "self".into() @@ -282,12 +281,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } let attrs = cx.tcx.hir_attrs(hir_id); for a in attrs { - if let Some(meta_items) = a.meta_item_list() { - if a.has_name(sym::proc_macro_derive) - || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)) - { - return; - } + if let Some(meta_items) = a.meta_item_list() + && (a.has_name(sym::proc_macro_derive) + || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))) + { + return; } } }, @@ -296,13 +294,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } // Exclude non-inherent impls - if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) { - if matches!( + if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) + && matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) - ) { - return; - } + ) + { + return; } self.check_poly_fn(cx, def_id, decl, Some(span)); diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index b653b459b04c..35caac855cf6 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -173,16 +173,15 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let Some(mut searcher) = self.searcher.take() { - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind - && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "push" - { - searcher.err_span = searcher.err_span.to(stmt.span); - searcher.arg = Some(*arg_expr); - searcher.display_err(cx); - } + if let Some(mut searcher) = self.searcher.take() + && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind + && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind + && path_to_local_id(self_arg, searcher.local_id) + && name.ident.as_str() == "push" + { + searcher.err_span = searcher.err_span.to(stmt.span); + searcher.arg = Some(*arg_expr); + searcher.display_err(cx); } } diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 96d3f7196c0c..19d9acfc9305 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -177,17 +177,16 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut PatKind::Or([p, ..]) => p, _ => p, }; - if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) { - if let [first, ..] = **adjustments { - if let ty::Ref(.., mutability) = *first.source.kind() { - let level = if p.hir_id == pat.hir_id { - Level::Top - } else { - Level::Lower - }; - result = Some((p.span, mutability, level)); - } - } + if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) + && let [first, ..] = **adjustments + && let ty::Ref(.., mutability) = *first.source.kind() + { + let level = if p.hir_id == pat.hir_id { + Level::Top + } else { + Level::Lower + }; + result = Some((p.span, mutability, level)); } result.is_none() }); diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 901a1634ddc8..491961408adb 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -264,8 +264,8 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { is_null_path(cx, l), is_null_path(cx, r), ) { - (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_par(), - (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_par(), + (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_paren(), + (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(), _ => return check_ptr_eq(cx, expr, op.node, l, r), }; @@ -498,29 +498,33 @@ fn check_fn_args<'cx, 'tcx: 'cx>( } fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&Body<'tcx>>) { - if let FnRetTy::Return(ty) = sig.decl.output - && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty) - { + let FnRetTy::Return(ty) = sig.decl.output else { return }; + for (out, mutability, out_span) in get_lifetimes(ty) { + if mutability != Some(Mutability::Mut) { + continue; + } let out_region = cx.tcx.named_bound_var(out.hir_id); - let args: Option> = sig + // `None` if one of the types contains `&'a mut T` or `T<'a>`. + // Else, contains all the locations of `&'a T` types. + let args_immut_refs: Option> = sig .decl .inputs .iter() - .filter_map(get_ref_lm) + .flat_map(get_lifetimes) .filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region) - .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span)) + .map(|(_, mutability, span)| (mutability == Some(Mutability::Not)).then_some(span)) .collect(); - if let Some(args) = args - && !args.is_empty() + if let Some(args_immut_refs) = args_immut_refs + && !args_immut_refs.is_empty() && body.is_none_or(|body| sig.header.is_unsafe() || contains_unsafe_block(cx, body.value)) { span_lint_and_then( cx, MUT_FROM_REF, - ty.span, + out_span, "mutable borrow from immutable input(s)", |diag| { - let ms = MultiSpan::from_spans(args); + let ms = MultiSpan::from_spans(args_immut_refs); diag.span_note(ms, "immutable borrow here"); }, ); @@ -686,12 +690,36 @@ fn matches_preds<'tcx>( }) } -fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { - if let TyKind::Ref(lt, ref m) = ty.kind { - Some((lt, m.mutbl, ty.span)) - } else { - None +struct LifetimeVisitor<'tcx> { + result: Vec<(&'tcx Lifetime, Option, Span)>, +} + +impl<'tcx> Visitor<'tcx> for LifetimeVisitor<'tcx> { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { + if let TyKind::Ref(lt, ref m) = ty.kind { + self.result.push((lt, Some(m.mutbl), ty.span)); + } + hir::intravisit::walk_ty(self, ty); } + + fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) { + if let GenericArg::Lifetime(lt) = generic_arg { + self.result.push((lt, None, generic_arg.span())); + } + hir::intravisit::walk_generic_arg(self, generic_arg); + } +} + +/// Visit `ty` and collect the all the lifetimes appearing in it, implicit or not. +/// +/// The second field of the vector's elements indicate if the lifetime is attached to a +/// shared reference, a mutable reference, or neither. +fn get_lifetimes<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Vec<(&'tcx Lifetime, Option, Span)> { + use hir::intravisit::VisitorExt as _; + + let mut visitor = LifetimeVisitor { result: Vec::new() }; + visitor.visit_ty_unambig(ty); + visitor.result } fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { @@ -728,8 +756,9 @@ fn check_ptr_eq<'tcx>( let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); - if let Some(left_snip) = left_var.span.get_source_text(cx) - && let Some(right_snip) = right_var.span.get_source_text(cx) + let mut app = Applicability::MachineApplicable; + let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app); + let right_snip = Sugg::hir_with_context(cx, right_var, expr.span.ctxt(), "_", &mut app); { let Some(top_crate) = std_or_core(cx) else { return }; let invert = if op == BinOpKind::Eq { "" } else { "!" }; @@ -740,7 +769,7 @@ fn check_ptr_eq<'tcx>( format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", format!("{invert}{top_crate}::ptr::eq({left_snip}, {right_snip})"), - Applicability::MachineApplicable, + app, ); } } @@ -748,7 +777,8 @@ fn check_ptr_eq<'tcx>( // If the given expression is a cast to a usize, return the lhs of the cast // E.g., `foo as *const _ as usize` returns `foo as *const _`. fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize + if !cast_expr.span.from_expansion() + && cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize && let ExprKind::Cast(expr, _) = cast_expr.kind { Some(expr) @@ -759,7 +789,8 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_> // Peel raw casts if the remaining expression can be coerced to it fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> { - if let ExprKind::Cast(inner, _) = expr.kind + if !expr.span.from_expansion() + && let ExprKind::Cast(inner, _) = expr.kind && let ty::RawPtr(target_ty, _) = expr_ty.kind() && let inner_ty = cx.typeck_results().expr_ty(inner) && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind() diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 68ae575c9063..7f74a2fff9f2 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -77,10 +77,10 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { // If the given expression is a cast from a usize, return the lhs of the cast fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind { - if is_expr_ty_usize(cx, cast_lhs_expr) { - return Some(cast_lhs_expr); - } + if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind + && is_expr_ty_usize(cx, cast_lhs_expr) + { + return Some(cast_lhs_expr); } None } @@ -91,14 +91,14 @@ fn expr_as_ptr_offset_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind { - if is_expr_ty_raw_ptr(cx, arg_0) { - if path_segment.ident.name == sym::offset { - return Some((arg_0, arg_1, Method::Offset)); - } - if path_segment.ident.name.as_str() == "wrapping_offset" { - return Some((arg_0, arg_1, Method::WrappingOffset)); - } + if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind + && is_expr_ty_raw_ptr(cx, arg_0) + { + if path_segment.ident.name == sym::offset { + return Some((arg_0, arg_1, Method::Offset)); + } + if path_segment.ident.name.as_str() == "wrapping_offset" { + return Some((arg_0, arg_1, Method::WrappingOffset)); } } None diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index a80e1f79bbc7..d318897443da 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -5,6 +5,7 @@ use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, @@ -144,7 +145,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && !span_contains_comment(cx.tcx.sess.source_map(), els.span) { let mut applicability = Applicability::MaybeIncorrect; - let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability); + let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); // Take care when binding is `ref` let sugg = if let PatKind::Binding( BindingMode(ByRef::Yes(ref_mutability), binding_mutability), diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index cc423eca74fb..d292ed86ea4c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -179,10 +179,10 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref op, l, r) = expr.kind { - if self.msrv.meets(cx, msrvs::RANGE_CONTAINS) { - check_possible_range_contains(cx, op.node, l, r, expr, expr.span); - } + if let ExprKind::Binary(ref op, l, r) = expr.kind + && self.msrv.meets(cx, msrvs::RANGE_CONTAINS) + { + check_possible_range_contains(cx, op.node, l, r, expr, expr.span); } check_exclusive_range_plus_one(cx, expr); @@ -327,18 +327,18 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> inc: inclusive, }); } - } else if let Some(id) = path_to_local(r) { - if let Some(c) = ConstEvalCtxt::new(cx).eval(l) { - return Some(RangeBounds { - val: c, - expr: l, - id, - name_span: r.span, - val_span: l.span, - ord: ordering.reverse(), - inc: inclusive, - }); - } + } else if let Some(id) = path_to_local(r) + && let Some(c) = ConstEvalCtxt::new(cx).eval(l) + { + return Some(RangeBounds { + val: c, + expr: l, + id, + name_span: r.span, + val_span: l.span, + ord: ordering.reverse(), + inc: inclusive, + }); } } None @@ -361,8 +361,8 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { span, "an inclusive range would be more readable", |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_par(); + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_paren(); match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { Some(true) => { diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect); @@ -398,8 +398,8 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "an exclusive range would be more readable", |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_par(); + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_paren(); diag.span_suggestion( expr.span, "use", diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 6bb7650a7e1c..689a2ac4c6ae 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -1,14 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::last_path_segment; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::{last_path_segment, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -135,7 +135,7 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) { - return Some((Symbol::intern("Weak"), func.span)); + return Some((sym::Weak, func.span)); } } diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 8289ec47bc7e..d2442ad0f373 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,14 +1,9 @@ -use std::ops::ControlFlow; - use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr_without_closures; +use clippy_utils::{desugar_await, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{ - Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource, -}; +use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; @@ -99,20 +94,3 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op None } } - -/// If `expr` is a desugared `.await`, return the original expression if it does not come from a -/// macro expansion. -fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind - && let ExprKind::Call(_, [into_future_arg]) = match_value.kind - && let ctxt = expr.span.ctxt() - && for_each_expr_without_closures(into_future_arg, |e| { - walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) - }) - .is_none() - { - Some(into_future_arg) - } else { - None - } -} diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index cfa622aea582..e57b8cc2d84e 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -109,10 +109,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { continue; } - if let ty::Adt(def, _) = arg_ty.kind() { - if def.is_manually_drop() { - continue; - } + if let ty::Adt(def, _) = arg_ty.kind() + && def.is_manually_drop() + { + continue; } // `{ arg = &cloned; clone(move arg); }` or `{ arg = &cloned; to_path_buf(arg); }` @@ -182,20 +182,25 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let clone_usage = if local == ret_local { CloneUsage { - cloned_used: false, + cloned_use_loc: None.into(), cloned_consume_or_mutate_loc: None, clone_consumed_or_mutated: true, } } else { let clone_usage = visit_clone_usage(local, ret_local, mir, bb); - if clone_usage.cloned_used && clone_usage.clone_consumed_or_mutated { + if clone_usage.cloned_use_loc.maybe_used() && clone_usage.clone_consumed_or_mutated { // cloned value is used, and the clone is modified or moved continue; - } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc { + } else if let MirLocalUsage::Used(loc) = clone_usage.cloned_use_loc + && possible_borrower.local_is_alive_at(ret_local, loc) + { + // cloned value is used, and the clone is alive. + continue; + } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc // cloned value is mutated, and the clone is alive. - if possible_borrower.local_is_alive_at(ret_local, loc) { - continue; - } + && possible_borrower.local_is_alive_at(ret_local, loc) + { + continue; } clone_usage }; @@ -216,19 +221,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let call_snip = &snip[dot + 1..]; // Machine applicable when `call_snip` looks like `foobar()` - if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) { - if call_snip + if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) + && call_snip .as_bytes() .iter() .all(|b| b.is_ascii_alphabetic() || *b == b'_') - { - app = Applicability::MachineApplicable; - } + { + app = Applicability::MachineApplicable; } span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| { diag.span_suggestion(sugg_span, "remove this", "", app); - if clone_usage.cloned_used { + if clone_usage.cloned_use_loc.maybe_used() { diag.span_note(span, "cloned value is neither consumed nor mutated"); } else { diag.span_note( @@ -329,10 +333,33 @@ fn base_local_and_movability<'tcx>( (place.local, deref || field || slice) } -#[derive(Default)] +#[derive(Debug, Default)] +enum MirLocalUsage { + /// The local maybe used, but we are not sure how. + Unknown, + /// The local is not used. + #[default] + Unused, + /// The local is used at a specific location. + Used(mir::Location), +} + +impl MirLocalUsage { + fn maybe_used(&self) -> bool { + matches!(self, MirLocalUsage::Unknown | MirLocalUsage::Used(_)) + } +} + +impl From> for MirLocalUsage { + fn from(loc: Option) -> Self { + loc.map_or(MirLocalUsage::Unused, MirLocalUsage::Used) + } +} + +#[derive(Debug, Default)] struct CloneUsage { - /// Whether the cloned value is used after the clone. - cloned_used: bool, + /// The first location where the cloned value is used, if any. + cloned_use_loc: MirLocalUsage, /// The first location where the cloned value is consumed or mutated, if any. cloned_consume_or_mutate_loc: Option, /// Whether the clone value is mutated. @@ -360,7 +387,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, .map(|mut vec| (vec.remove(0), vec.remove(0))) { CloneUsage { - cloned_used: !cloned_use_locs.is_empty(), + cloned_use_loc: cloned_use_locs.first().copied().into(), cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(), // Consider non-temporary clones consumed. // TODO: Actually check for mutation of non-temporaries. @@ -369,7 +396,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, } } else { CloneUsage { - cloned_used: true, + cloned_use_loc: MirLocalUsage::Unknown, cloned_consume_or_mutate_loc: None, clone_consumed_or_mutated: true, } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 1498a49a7a4a..84597269a58f 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // avoid clippy::double_parens if !is_in_fn_call_arg { - hint = hint.maybe_par(); + hint = hint.maybe_paren(); } diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability); diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index f2fdac5a8afa..7b381fac5f11 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -52,13 +52,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && is_not_macro_export(item) && !item.span.in_external_macro(cx.sess().source_map()) { - // FIXME: `DUMMY_SP` isn't right here, because it causes the - // resulting span to begin at the start of the file. - let span = item.span.with_hi( - item.kind - .ident() - .map_or(rustc_span::DUMMY_SP.hi(), |ident| ident.span.hi()), - ); + let span = item + .kind + .ident() + .map_or(item.span, |ident| item.span.with_hi(ident.span.hi())); let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id()); span_lint_and_then( cx, diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 7038b19d2759..1117dea703c2 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -135,25 +135,24 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { }; diag.span_suggestion(expr.span, help_msg, sugg, app); }); - } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { - if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( + } else if let Some(target_id) = cx.tcx.lang_items().deref_target() + && let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.typing_env(), Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), - ) { - if deref_ty == expr_ty { - let (lint, msg) = DEREF_BY_SLICING_LINT; - span_lint_and_then(cx, lint, expr.span, msg, |diag| { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; - let sugg = if needs_parens_for_prefix { - format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) - } else { - format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) - }; - diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app); - }); - } - } + ) + && deref_ty == expr_ty + { + let (lint, msg) = DEREF_BY_SLICING_LINT; + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; + let sugg = if needs_parens_for_prefix { + format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) + } else { + format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) + }; + diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app); + }); } } } diff --git a/clippy_lints/src/redundant_test_prefix.rs b/clippy_lints/src/redundant_test_prefix.rs new file mode 100644 index 000000000000..84276e321657 --- /dev/null +++ b/clippy_lints/src/redundant_test_prefix.rs @@ -0,0 +1,161 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_test_function; +use clippy_utils::visitors::for_each_expr; +use rustc_errors::Applicability; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{self as hir, Body, ExprKind, FnDecl}; +use rustc_lexer::is_ident; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, Symbol, edition}; +use std::borrow::Cow; +use std::ops::ControlFlow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for test functions (functions annotated with `#[test]`) that are prefixed + /// with `test_` which is redundant. + /// + /// ### Why is this bad? + /// This is redundant because test functions are already annotated with `#[test]`. + /// Moreover, it clutters the output of `cargo test` since test functions are expanded as + /// `module::tests::test_use_case` in the output. Without the redundant prefix, the output + /// becomes `module::tests::use_case`, which is more readable. + /// + /// ### Example + /// ```no_run + /// #[cfg(test)] + /// mod tests { + /// use super::*; + /// + /// #[test] + /// fn test_use_case() { + /// // test code + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #[cfg(test)] + /// mod tests { + /// use super::*; + /// + /// #[test] + /// fn use_case() { + /// // test code + /// } + /// } + /// ``` + #[clippy::version = "1.88.0"] + pub REDUNDANT_TEST_PREFIX, + restriction, + "redundant `test_` prefix in test function name" +} + +declare_lint_pass!(RedundantTestPrefix => [REDUNDANT_TEST_PREFIX]); + +impl<'tcx> LateLintPass<'tcx> for RedundantTestPrefix { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'_>, + _decl: &FnDecl<'_>, + body: &'tcx Body<'_>, + _span: Span, + fn_def_id: LocalDefId, + ) { + // Ignore methods and closures. + let FnKind::ItemFn(ref ident, ..) = kind else { + return; + }; + + // Skip the lint if the function is within a macro expansion. + if ident.span.from_expansion() { + return; + } + + // Skip if the function name does not start with `test_`. + if !ident.as_str().starts_with("test_") { + return; + } + + // If the function is not a test function, skip the lint. + if !is_test_function(cx.tcx, fn_def_id) { + return; + } + + span_lint_and_then( + cx, + REDUNDANT_TEST_PREFIX, + ident.span, + "redundant `test_` prefix in test function name", + |diag| { + let non_prefixed = Symbol::intern(ident.as_str().trim_start_matches("test_")); + if is_invalid_ident(non_prefixed) { + // If the prefix-trimmed name is not a valid function name, do not provide an + // automatic fix, just suggest renaming the function. + diag.help( + "consider function renaming (just removing `test_` prefix will produce invalid function name)", + ); + } else { + let (sugg, msg): (Cow<'_, str>, _) = if name_conflicts(cx, body, non_prefixed) { + // If `non_prefixed` conflicts with another function in the same module/scope, + // do not provide an automatic fix, but still emit a fix suggestion. + ( + format!("{non_prefixed}_works").into(), + "consider function renaming (just removing `test_` prefix will cause a name conflict)", + ) + } else { + // If `non_prefixed` is a valid identifier and does not conflict with another function, + // so we can suggest an auto-fix. + (non_prefixed.as_str().into(), "consider removing the `test_` prefix") + }; + diag.span_suggestion(ident.span, msg, sugg, Applicability::MaybeIncorrect); + } + }, + ); + } +} + +/// Checks whether removal of the `_test` prefix from the function name will cause a name conflict. +/// +/// There should be no other function with the same name in the same module/scope. Also, there +/// should not be any function call with the same name within the body of the function, to avoid +/// recursion. +fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: Symbol) -> bool { + let tcx = cx.tcx; + let id = body.id().hir_id; + + // Iterate over items in the same module/scope + let (module, _module_span, _module_hir) = tcx.hir_get_module(tcx.parent_module(id)); + if module + .item_ids + .iter() + .any(|item| matches!(tcx.hir_item(*item).kind, hir::ItemKind::Fn { ident, .. } if ident.name == fn_name)) + { + // Name conflict found + return true; + } + + // Also check that within the body of the function there is also no function call + // with the same name (since it will result in recursion) + for_each_expr(cx, body, |expr| { + if let ExprKind::Path(qpath) = &expr.kind + && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() + && let Some(name) = tcx.opt_item_name(def_id) + && name == fn_name + { + // Function call with the same name found + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} + +fn is_invalid_ident(ident: Symbol) -> bool { + // The identifier is either a reserved keyword, or starts with an invalid sequence. + ident.is_reserved(|| edition::LATEST_STABLE_EDITION) || !is_ident(ident.as_str()) +} diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 9443dca154e3..834ff2af0e88 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths}; +use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths, sym}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; @@ -76,7 +76,7 @@ declare_clippy_lint! { /// This is documented as an antipattern [on the regex documentation](https://docs.rs/regex/latest/regex/#avoid-re-compiling-regexes-especially-in-a-loop) /// /// ### Example - /// ```no_run + /// ```rust,ignore /// # let haystacks = [""]; /// # const MY_REGEX: &str = "a.b"; /// for haystack in haystacks { @@ -87,7 +87,7 @@ declare_clippy_lint! { /// } /// ``` /// can be replaced with - /// ```no_run + /// ```rust,ignore /// # let haystacks = [""]; /// # const MY_REGEX: &str = "a.b"; /// let regex = regex::Regex::new(MY_REGEX).unwrap(); @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Regex { // // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only // perform the operation once and store the results - let regex_crates = find_crates(cx.tcx, sym!(regex)); + let regex_crates = find_crates(cx.tcx, sym::regex); let mut resolve = |path: &[&str], kind: RegexKind| { for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { if let Some(id) = res.opt_def_id() { diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 33815cc3bac1..226e8ff6adbf 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::AssocItem; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -85,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { .associated_items(did) .in_definition_order() .filter(|assoc_item| assoc_item.is_fn()) - .map(|assoc_item| assoc_item.name()) + .map(AssocItem::name) .collect() } else { BTreeSet::new() diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 6a0dfde2d9c9..a8c6518b592b 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -32,28 +32,28 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi { }) = item.kind { let did = trait_ref.path.res.def_id(); - if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR) { - if did == visit_did { - let mut seen_str = None; - let mut seen_string = None; - for item in *items { - match item.ident.as_str() { - "visit_str" => seen_str = Some(item.span), - "visit_string" => seen_string = Some(item.span), - _ => {}, - } - } - if let Some(span) = seen_string { - if seen_str.is_none() { - span_lint( - cx, - SERDE_API_MISUSE, - span, - "you should not implement `visit_string` without also implementing `visit_str`", - ); - } + if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR) + && did == visit_did + { + let mut seen_str = None; + let mut seen_string = None; + for item in *items { + match item.ident.as_str() { + "visit_str" => seen_str = Some(item.span), + "visit_string" => seen_string = Some(item.span), + _ => {}, } } + if let Some(span) = seen_string + && seen_str.is_none() + { + span_lint( + cx, + SERDE_API_MISUSE, + span, + "you should not implement `visit_string` without also implementing `visit_str`", + ); + } } } } diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index 1185d67b1258..ff6e6ef214b5 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while}; +use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while, sym}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for SetContainsOrInsert { then: then_expr, .. }) = higher::If::hir(expr) - && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr) + && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym::contains)//try_parse_contains(cx, cond_expr) && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr) { span_lint( @@ -118,7 +118,7 @@ fn find_insert_calls<'tcx>( expr: &'tcx Expr<'_>, ) -> Option> { for_each_expr(cx, expr, |e| { - if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym!(insert)) + if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert) && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index b82ddedd56c0..14399867f318 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -8,7 +8,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; -use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, Node, Pat, PatKind, QPath, UnOp}; +use rustc_hir::{ + Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, LocalSource, Node, Pat, PatKind, QPath, UnOp, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; @@ -65,7 +67,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub SHADOW_REUSE, restriction, - "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`" + "rebinding a name to an expression that reuses the original value, e.g., `let x = x + 1`" } declare_clippy_lint! { @@ -125,6 +127,17 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { return; } + // Desugaring of a destructuring assignment may reuse the same identifier internally. + // Peel `Pat` and `PatField` nodes and check if we reach a desugared `Let` assignment. + if let Some((_, Node::LetStmt(let_stmt))) = cx + .tcx + .hir_parent_iter(pat.hir_id) + .find(|(_, node)| !matches!(node, Node::Pat(_) | Node::PatField(_))) + && let LocalSource::AssignDesugar(_) = let_stmt.source + { + return; + } + let HirId { owner, local_id } = id; // get (or insert) the list of items for this owner and symbol let (ref mut data, scope_owner) = *self.bindings.last_mut().unwrap(); @@ -167,10 +180,10 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool { let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id()); - if let Some(first_scope) = scope_tree.var_scope(first) { - if let Some(second_scope) = scope_tree.var_scope(second) { - return scope_tree.is_subscope_of(second_scope, first_scope); - } + if let Some(first_scope) = scope_tree.var_scope(first) + && let Some(second_scope) = scope_tree.var_scope(second) + { + return scope_tree.is_subscope_of(second_scope, first_scope); } false diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 76874cc34206..ccb1209c6fcb 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -124,8 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { diag.span_label( apa.first_block_span, format!( - "temporary `{}` is currently being dropped at the end of its contained scope", - first_bind_ident + "temporary `{first_bind_ident}` is currently being dropped at the end of its contained scope" ), ); }, @@ -145,7 +144,10 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { Self { cx, type_cache } } - fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>, depth: usize) -> bool { + if !self.cx.tcx.recursion_limit().value_within_limit(depth) { + return false; + } let ty = self .cx .tcx @@ -157,12 +159,12 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { e.insert(false); }, } - let value = self.has_sig_drop_attr_uncached(ty); + let value = self.has_sig_drop_attr_uncached(ty, depth + 1); self.type_cache.insert(ty, value); value } - fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { + fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>, depth: usize) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -177,15 +179,15 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { rustc_middle::ty::Adt(a, b) => { for f in a.all_fields() { let ty = f.ty(self.cx.tcx, b); - if self.has_sig_drop_attr(ty) { + if self.has_sig_drop_attr(ty, depth) { return true; } } for generic_arg in *b { - if let GenericArgKind::Type(ty) = generic_arg.unpack() { - if self.has_sig_drop_attr(ty) { - return true; - } + if let GenericArgKind::Type(ty) = generic_arg.unpack() + && self.has_sig_drop_attr(ty, depth) + { + return true; } } false @@ -193,7 +195,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { rustc_middle::ty::Array(ty, _) | rustc_middle::ty::RawPtr(ty, _) | rustc_middle::ty::Ref(_, ty, _) - | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty), + | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty, depth), _ => false, } } @@ -269,7 +271,7 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { apa.has_expensive_expr_after_last_attr = false; }; let mut ac = AttrChecker::new(self.cx, self.type_cache); - if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) { + if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr), 0) { if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && !self.ap.apas.contains_key(&hir_id) @@ -317,7 +319,7 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { } }, hir::StmtKind::Semi(semi_expr) => { - if has_drop(semi_expr, &apa.first_bind_ident, self.cx) { + if has_drop(semi_expr, apa.first_bind_ident, self.cx) { apa.has_expensive_expr_after_last_attr = false; apa.last_stmt_span = DUMMY_SP; return; @@ -414,7 +416,7 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> { } } -fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Option, lcx: &LateContext<'_>) -> bool { +fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: Option, lcx: &LateContext<'_>) -> bool { if let hir::ExprKind::Call(fun, [first_arg]) = expr.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind && let Res::Def(DefKind::Fn, did) = fun_path.res @@ -424,7 +426,7 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Option, lcx: &LateCo if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind && let [first_arg_ps, ..] = arg_path.segments && let Some(first_bind_ident) = first_bind_ident - && &first_arg_ps.ident == first_bind_ident + && first_arg_ps.ident == first_bind_ident { true } else { diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 50a6ee316c8a..8c34da0d14a4 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -45,19 +45,20 @@ impl EarlyLintPass for SingleCharLifetimeNames { return; } - if let GenericParamKind::Lifetime = param.kind { - if !param.is_placeholder && param.ident.as_str().len() <= 2 { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - ctx, - SINGLE_CHAR_LIFETIME_NAMES, - param.ident.span, - "single-character lifetime names are likely uninformative", - |diag| { - diag.help("use a more informative name"); - }, - ); - } + if let GenericParamKind::Lifetime = param.kind + && !param.is_placeholder + && param.ident.as_str().len() <= 2 + { + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + ctx, + SINGLE_CHAR_LIFETIME_NAMES, + param.ident.span, + "single-character lifetime names are likely uninformative", + |diag| { + diag.help("use a more informative name"); + }, + ); } } } diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 35f80b2acda6..62939912304b 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -204,17 +204,17 @@ impl SingleComponentPathImports { if let UseTreeKind::Nested { items, .. } = &use_tree.kind { for tree in items { let segments = &tree.0.prefix.segments; - if segments.len() == 1 { - if let UseTreeKind::Simple(None) = tree.0.kind { - let name = segments[0].ident.name; - if !macros.contains(&name) { - single_use_usages.push(SingleUse { - name, - span: tree.0.span, - item_id: item.id, - can_suggest: false, - }); - } + if segments.len() == 1 + && let UseTreeKind::Simple(None) = tree.0.kind + { + let name = segments[0].ident.name; + if !macros.contains(&name) { + single_use_usages.push(SingleUse { + name, + span: tree.0.span, + item_id: item.id, + can_suggest: false, + }); } } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 27c548bed9f6..43a3e6961051 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, path_def_id, - peel_blocks, + peel_blocks, sym, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -12,7 +12,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::sym; use std::ops::ControlFlow; @@ -162,13 +161,12 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { if is_string(cx, left) { if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { let parent = get_parent_expr(cx, e); - if let Some(p) = parent { - if let ExprKind::Assign(target, _, _) = p.kind { + if let Some(p) = parent + && let ExprKind::Assign(target, _, _) = p.kind // avoid duplicate matches - if SpanlessEq::new(cx).eq_expr(target, left) { - return; - } - } + && SpanlessEq::new(cx).eq_expr(target, left) + { + return; } } span_lint( @@ -263,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind && let ExprKind::Index(left, right, _) = args.kind && let (method_names, expressions, _) = method_calls(left, 1) - && method_names == [sym!(as_bytes)] + && method_names == [sym::as_bytes] && expressions.len() == 1 && expressions[0].1.is_empty() diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 56bd8fefdb45..83241f97a99a 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -59,25 +59,18 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { match expr.kind { hir::ExprKind::Binary(op, _, _) => { - self.check_expr_inner(cx, expr, op.node, op.span); - } + check_expr_inner(cx, expr, op.node, op.span); + }, hir::ExprKind::AssignOp(op, _, _) => { - self.check_expr_inner(cx, expr, op.node.into(), op.span); - } - _ => {} + check_expr_inner(cx, expr, op.node.into(), op.span); + }, + _ => {}, } } } -impl<'tcx> SuspiciousImpl { - fn check_expr_inner( - &mut self, - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - binop: hir::BinOpKind, - span: Span, - ) { - if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop) +fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, binop: hir::BinOpKind, span: Span) { + if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop) && let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang) && let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang) @@ -98,18 +91,17 @@ impl<'tcx> SuspiciousImpl { .iter() .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t))) && count_binops(body.value) == 1 - { - span_lint( - cx, - lint, - span, - format!( - "suspicious use of `{}` in `{}` impl", - binop.as_str(), - cx.tcx.item_name(trait_id) - ), - ); - } + { + span_lint( + cx, + lint, + span, + format!( + "suspicious use of `{}` in `{}` impl", + binop.as_str(), + cx.tcx.item_name(trait_id) + ), + ); } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 0337b74b4b12..e3ecd6508bf9 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -133,7 +133,7 @@ fn generate_swap_warning<'tcx>( applicability: &mut applicability, } .snippet_index_bindings(&[idx1, idx2, rhs1, rhs2]), - slice.maybe_par(), + slice.maybe_paren(), snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0, snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0, ), @@ -269,12 +269,11 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< if let ExprKind::Assign(lhs, rhs, _) = expr.kind { return Some((ExprOrIdent::Expr(lhs), rhs)); } - } else if let StmtKind::Let(expr) = stmt.kind { - if let Some(rhs) = expr.init { - if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind { - return Some((ExprOrIdent::Ident(ident_l), rhs)); - } - } + } else if let StmtKind::Let(expr) = stmt.kind + && let Some(rhs) = expr.init + && let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind + { + return Some((ExprOrIdent::Ident(ident_l), rhs)); } None } diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index fa36c9a21f65..8aac3a591029 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -151,20 +151,19 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { .iter() .filter_map(get_trait_info_from_bound) .for_each(|(trait_item_res, trait_item_segments, span)| { - if let Some(self_segments) = self_bounds_map.get(&trait_item_res) { - if SpanlessEq::new(cx) + if let Some(self_segments) = self_bounds_map.get(&trait_item_res) + && SpanlessEq::new(cx) .paths_by_resolution() .eq_path_segments(self_segments, trait_item_segments) - { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - span, - "this trait bound is already specified in trait declaration", - None, - "consider removing this trait bound", - ); - } + { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + span, + "this trait bound is already specified in trait declaration", + None, + "consider removing this trait bound", + ); } }); } diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index f2c757952af3..df2f681a1629 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( } } - sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_par()).into()); + sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_paren()).into()); // cast the result of `to_bits` if `to_ty` is signed sugg = if let ty::Int(int_ty) = to_ty.kind() { diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index fcc763763bd2..933e25fe98c6 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_par()), + format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else if from_pointee_ty == to_pointee_ty @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg.maybe_par()), + format!("{}.{method}()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else { diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 45ee83c78ab6..e58212fae15c 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( let sugg = if let Some(ty) = get_explicit_type(path) { let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); if msrv.meets(cx, msrvs::POINTER_CAST) { - format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) + format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren()) } else if from_ptr_ty.has_erased_regions() { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() } else { @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( } else if *from_ptr_ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { if msrv.meets(cx, msrvs::POINTER_CAST) { - format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) + format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren()) } else { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) .to_string() diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index b6f4c4d7f0a4..3147058b4cda 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -591,26 +591,26 @@ impl Types { TyKind::Path(ref qpath) if !context.in_body => { let hir_id = hir_ty.hir_id; let res = cx.qpath_res(qpath, hir_id); - if let Some(def_id) = res.opt_def_id() { - if self.is_type_change_allowed(context) { - // All lints that are being checked in this block are guarded by - // the `avoid_breaking_exported_api` configuration. When adding a - // new lint, please also add the name to the configuration documentation - // in `clippy_config::conf` + if let Some(def_id) = res.opt_def_id() + && self.is_type_change_allowed(context) + { + // All lints that are being checked in this block are guarded by + // the `avoid_breaking_exported_api` configuration. When adding a + // new lint, please also add the name to the configuration documentation + // in `clippy_config::conf` - let mut triggered = false; - triggered |= box_collection::check(cx, hir_ty, qpath, def_id); - triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id); - triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id); - triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold); - triggered |= option_option::check(cx, hir_ty, qpath, def_id); - triggered |= linked_list::check(cx, hir_ty, def_id); - triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id); - triggered |= owned_cow::check(cx, qpath, def_id); + let mut triggered = false; + triggered |= box_collection::check(cx, hir_ty, qpath, def_id); + triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id); + triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id); + triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold); + triggered |= option_option::check(cx, hir_ty, qpath, def_id); + triggered |= linked_list::check(cx, hir_ty, def_id); + triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id); + triggered |= owned_cow::check(cx, qpath, def_id); - if triggered { - return; - } + if triggered { + return; } } match *qpath { diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 0c17cc5d8f66..d321c48f6aff 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -23,8 +23,8 @@ declare_clippy_lint! { /// implementations. /// /// ### Why is this bad? - /// This is a hard to find infinite recursion that will crash any code - /// using it. + /// Infinite recursion in trait implementation will either cause crashes + /// or result in an infinite loop, and it is hard to detect. /// /// ### Example /// ```no_run @@ -39,9 +39,31 @@ declare_clippy_lint! { /// } /// } /// ``` + /// /// Use instead: /// - /// In such cases, either use `#[derive(PartialEq)]` or don't implement it. + /// ```no_run + /// #[derive(PartialEq)] + /// enum Foo { + /// A, + /// B, + /// } + /// ``` + /// + /// As an alternative, rewrite the logic without recursion: + /// + /// ```no_run + /// enum Foo { + /// A, + /// B, + /// } + /// + /// impl PartialEq for Foo { + /// fn eq(&self, other: &Self) -> bool { + /// matches!((self, other), (Foo::A, Foo::A) | (Foo::B, Foo::B)) + /// } + /// } + /// ``` #[clippy::version = "1.77.0"] pub UNCONDITIONAL_RECURSION, suspicious, @@ -113,7 +135,7 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt }), )) = cx.tcx.hir_parent_iter(hir_id).next() // We exclude `impl` blocks generated from rustc's proc macros. - && !cx.tcx.has_attr(*owner_id, sym::automatically_derived) + && !cx.tcx.is_automatically_derived(owner_id.to_def_id()) // It is a implementation of a trait. && let Some(trait_) = impl_.of_trait { @@ -218,7 +240,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local }), )) = cx.tcx.hir_parent_iter(hir_id).next() // We exclude `impl` blocks generated from rustc's proc macros. - && !cx.tcx.has_attr(*owner_id, sym::automatically_derived) + && !cx.tcx.is_automatically_derived(owner_id.to_def_id()) // It is a implementation of a trait. && let Some(trait_) = impl_.of_trait && let Some(trait_def_id) = trait_.trait_def_id() @@ -315,7 +337,7 @@ impl UnconditionalRecursion { for (ty, impl_def_ids) in impls.non_blanket_impls() { let Some(self_def_id) = ty.def() else { continue }; for impl_def_id in impl_def_ids { - if !cx.tcx.has_attr(*impl_def_id, sym::automatically_derived) && + if !cx.tcx.is_automatically_derived(*impl_def_id) && let Some(assoc_item) = cx .tcx .associated_items(impl_def_id) diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index e1fc644e4cee..79571b0409d2 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -76,10 +76,10 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_ impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Lit(lit) = expr.kind { - if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node { - check_str(cx, lit.span, expr.hir_id); - } + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Str(_, _) | LitKind::Char(_) = lit.node + { + check_str(cx, lit.span, expr.hir_id); } } } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 937e35dea96d..bcd05cceca9c 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -93,13 +93,13 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Abort if the method is implementing a trait or of it a trait method. let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); - if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) { - if matches!( + if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) + && matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) - ) { - return; - } + ) + { + return; } // Get the wrapper and inner types, if can't, abort. diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 8966e6851ac2..9ad184450de4 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -69,10 +69,10 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if self.msrv.meets(msrvs::OR_PATTERNS) { - if let ast::ExprKind::Let(pat, _, _, _) = &e.kind { - lint_unnested_or_patterns(cx, pat); - } + if self.msrv.meets(msrvs::OR_PATTERNS) + && let ast::ExprKind::Let(pat, _, _, _) = &e.kind + { + lint_unnested_or_patterns(cx, pat); } } @@ -120,18 +120,25 @@ fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { /// Remove all `(p)` patterns in `pat`. fn remove_all_parens(pat: &mut P) { - struct Visitor; + #[derive(Default)] + struct Visitor { + /// If is not in the outer most pattern. This is needed to avoid removing the outermost + /// parens because top-level or-patterns are not allowed in let statements. + is_inner: bool, + } + impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { + let is_inner = mem::replace(&mut self.is_inner, true); walk_pat(self, pat); let inner = match &mut pat.kind { - Paren(i) => mem::replace(&mut i.kind, Wild), + Paren(i) if is_inner => mem::replace(&mut i.kind, Wild), _ => return, }; pat.kind = inner; } } - Visitor.visit_pat(pat); + Visitor::default().visit_pat(pat); } /// Insert parens where necessary according to Rust's precedence rules for patterns. diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 0687fc319af6..2d88c490b1ab 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -265,15 +265,14 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { - if let ExprKind::Call(func, [arg_0]) = expr.kind { - if matches!( - func.kind, - ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) - ) { - return arg_0; - } - } + if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(func, [arg_0]) = expr.kind + && matches!( + func.kind, + ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) + ) + { + return arg_0; } expr } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index b466a8e127a9..ce82b56eb946 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; -use clippy_utils::{higher, path_to_local}; +use clippy_utils::{higher, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; @@ -11,8 +11,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -307,8 +307,8 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg) && let Some(id) = path_to_local(self_arg) - && [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name) - && let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name) + && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err) + && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect) && let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.local_id == id) // Span contexts should not differ with the conditional branch diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 57bb2fc27f14..3a9c997a579d 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -92,36 +92,36 @@ fn into_iter_bound<'tcx>( let mut into_iter_span = None; for (pred, span) in cx.tcx.explicit_predicates_of(fn_did).predicates { - if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() { - if tr.self_ty().is_param(param_index) { - if tr.def_id() == into_iter_did { - into_iter_span = Some(*span); - } else { - let tr = cx.tcx.erase_regions(tr); - if tr.has_escaping_bound_vars() { - return None; - } + if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() + && tr.self_ty().is_param(param_index) + { + if tr.def_id() == into_iter_did { + into_iter_span = Some(*span); + } else { + let tr = cx.tcx.erase_regions(tr); + if tr.has_escaping_bound_vars() { + return None; + } - // Substitute generics in the predicate and replace the IntoIterator type parameter with the - // `.into_iter()` receiver to see if the bound also holds for that type. - let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| { - if i == param_index as usize { - GenericArg::from(into_iter_receiver) - } else { - arg - } - })); - - let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args); - let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - if !cx - .tcx - .infer_ctxt() - .build(cx.typing_mode()) - .predicate_must_hold_modulo_regions(&obligation) - { - return None; + // Substitute generics in the predicate and replace the IntoIterator type parameter with the + // `.into_iter()` receiver to see if the bound also holds for that type. + let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| { + if i == param_index as usize { + GenericArg::from(into_iter_receiver) + } else { + arg } + })); + + let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args); + let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); + if !cx + .tcx + .infer_ctxt() + .build(cx.typing_mode()) + .predicate_must_hold_modulo_regions(&obligation) + { + return None; } } } @@ -356,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) { let mut app = Applicability::MachineApplicable; - let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_paren(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs deleted file mode 100644 index deb983b6971d..000000000000 --- a/clippy_lints/src/utils/internal_lints.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod almost_standard_lint_formulation; -pub mod collapsible_calls; -pub mod interning_defined_symbol; -pub mod invalid_paths; -pub mod lint_without_lint_pass; -pub mod msrv_attr_impl; -pub mod outer_expn_data_pass; -pub mod produce_ice; -pub mod slow_symbol_comparisons; -pub mod unnecessary_def_path; -pub mod unsorted_clippy_utils_paths; diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs deleted file mode 100644 index e454427adde1..000000000000 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ /dev/null @@ -1,241 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::ConstValue; -use rustc_middle::ty; -use rustc_session::impl_lint_pass; -use rustc_span::sym; -use rustc_span::symbol::Symbol; - -use std::borrow::Cow; - -declare_clippy_lint! { - /// ### What it does - /// Checks for interning symbols that have already been pre-interned and defined as constants. - /// - /// ### Why is this bad? - /// It's faster and easier to use the symbol constant. - /// - /// ### Example - /// ```rust,ignore - /// let _ = sym!(f32); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// let _ = sym::f32; - /// ``` - pub INTERNING_DEFINED_SYMBOL, - internal, - "interning a symbol that is pre-interned and defined as a constant" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for unnecessary conversion from Symbol to a string. - /// - /// ### Why is this bad? - /// It's faster use symbols directly instead of strings. - /// - /// ### Example - /// ```rust,ignore - /// symbol.as_str() == "clippy"; - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// symbol == sym::clippy; - /// ``` - pub UNNECESSARY_SYMBOL_STR, - internal, - "unnecessary conversion between Symbol and string" -} - -#[derive(Default)] -pub struct InterningDefinedSymbol { - // Maps the symbol value to the constant DefId. - symbol_map: FxHashMap, -} - -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); - -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if !self.symbol_map.is_empty() { - return; - } - - for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - for def_id in def_path_def_ids(cx.tcx, module) { - for item in cx.tcx.module_children(def_id) { - if let Res::Def(DefKind::Const, item_def_id) = item.res - && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() - && match_type(cx, ty, &paths::SYMBOL) - && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) - && let Some(value) = value.to_u32().discard_err() - { - self.symbol_map.insert(value, item_def_id); - } - } - } - } - } - - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Call(func, [arg]) = &expr.kind - && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() - && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) - && let value = Symbol::intern(&arg).as_u32() - && let Some(&def_id) = self.symbol_map.get(&value) - { - span_lint_and_sugg( - cx, - INTERNING_DEFINED_SYMBOL, - is_expn_of(expr.span, "sym").unwrap_or(expr.span), - "interning a defined symbol", - "try", - cx.tcx.def_path_str(def_id), - Applicability::MachineApplicable, - ); - } - if let ExprKind::Binary(op, left, right) = expr.kind { - if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) { - let data = [ - (left, self.symbol_str_expr(left, cx)), - (right, self.symbol_str_expr(right, cx)), - ]; - match data { - // both operands are a symbol string - [(_, Some(left)), (_, Some(right))] => { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary `Symbol` to string conversion", - "try", - format!( - "{} {} {}", - left.as_symbol_snippet(cx), - op.node.as_str(), - right.as_symbol_snippet(cx), - ), - Applicability::MachineApplicable, - ); - }, - // one of the operands is a symbol string - [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => { - // creating an owned string for comparison - if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary string allocation", - "try", - format!("{}.as_str()", symbol.as_symbol_snippet(cx)), - Applicability::MachineApplicable, - ); - } - }, - // nothing found - [(_, None), (_, None)] => {}, - } - } - } - } -} - -impl InterningDefinedSymbol { - fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option> { - static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; - static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; - let call = if let ExprKind::AddrOf(_, _, e) = expr.kind - && let ExprKind::Unary(UnOp::Deref, e) = e.kind - { - e - } else { - expr - }; - if let ExprKind::MethodCall(_, item, [], _) = call.kind - // is a method call - && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) - && let ty = cx.typeck_results().expr_ty(item) - // ...on either an Ident or a Symbol - && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { - Some(false) - } else if match_type(cx, ty, &paths::IDENT) { - Some(true) - } else { - None - } - // ...which converts it to a string - && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS } - && let Some(is_to_owned) = paths - .iter() - .find_map(|path| if match_def_path(cx, did, path) { - Some(path == &paths::SYMBOL_TO_IDENT_STRING) - } else { - None - }) - .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) { - Some(true) - } else { - None - }) - { - return Some(SymbolStrExpr::Expr { - item, - is_ident, - is_to_owned, - }); - } - // is a string constant - if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) { - let value = Symbol::intern(&s).as_u32(); - // ...which matches a symbol constant - if let Some(&def_id) = self.symbol_map.get(&value) { - return Some(SymbolStrExpr::Const(def_id)); - } - } - None - } -} - -enum SymbolStrExpr<'tcx> { - /// a string constant with a corresponding symbol constant - Const(DefId), - /// a "symbol to string" expression like `symbol.as_str()` - Expr { - /// part that evaluates to `Symbol` or `Ident` - item: &'tcx Expr<'tcx>, - is_ident: bool, - /// whether an owned `String` is created like `to_ident_string()` - is_to_owned: bool, - }, -} - -impl<'tcx> SymbolStrExpr<'tcx> { - /// Returns a snippet that evaluates to a `Symbol` and is const if possible - fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> { - match *self { - Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(), - Self::Expr { item, is_ident, .. } => { - let mut snip = snippet(cx, item.span.source_callsite(), ".."); - if is_ident { - // get `Ident.name` - snip.to_mut().push_str(".name"); - } - snip - }, - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs deleted file mode 100644 index b8bcb9b37560..000000000000 --- a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; - -declare_clippy_lint! { - /// ### What it does - /// - /// Detects symbol comparison using `Symbol::intern`. - /// - /// ### Why is this bad? - /// - /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused. - /// - /// ### Example - /// - /// None, see suggestion. - pub SLOW_SYMBOL_COMPARISONS, - internal, - "detects slow comparisons of symbol" -} - -declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); - -fn check_slow_comparison<'tcx>( - cx: &LateContext<'tcx>, - op1: &'tcx Expr<'tcx>, - op2: &'tcx Expr<'tcx>, -) -> Option<(Span, String)> { - if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) - && let ExprKind::Call(fun, args) = op2.kind - && let ExprKind::Path(ref qpath) = fun.kind - && cx - .tcx - .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?) - && let [symbol_name_expr] = args - && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) - { - Some((op1.span, symbol_name)) - } else { - None - } -} - -impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if let ExprKind::Binary(op, left, right) = expr.kind - && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) - && let Some((symbol_span, symbol_name)) = - check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left)) - { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - SLOW_SYMBOL_COMPARISONS, - expr.span, - "comparing `Symbol` via `Symbol::intern`", - "use `Symbol::as_str` and check the string instead", - format!( - "{}.as_str() {} \"{symbol_name}\"", - snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability), - op.node.as_str() - ), - applicability, - ); - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs deleted file mode 100644 index a5c4bf474f7a..000000000000 --- a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs +++ /dev/null @@ -1,49 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast::{Crate, ItemKind, ModKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks that [`clippy_utils::paths`] is sorted lexically - /// - /// ### Why is this bad? - /// We like to pretend we're an example of tidy code. - /// - /// ### Example - /// Wrong ordering of the util::paths constants. - pub UNSORTED_CLIPPY_UTILS_PATHS, - internal, - "various things that will negatively affect your clippy experience" -} - -declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); - -impl EarlyLintPass for UnsortedClippyUtilsPaths { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { - if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") { - if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { - if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") { - if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind { - let mut last_name: Option<&str> = None; - for item in items { - let name = item.ident.as_str(); - if let Some(last_name) = last_name { - if *last_name > *name { - span_lint( - cx, - UNSORTED_CLIPPY_UTILS_PATHS, - item.span, - "this constant should be before the previous constant due to lexical \ - ordering", - ); - } - } - last_name = Some(name); - } - } - } - } - } - } -} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4476cd1005e7..16066dd96c0a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -2,6 +2,3 @@ pub mod attr_collector; pub mod author; pub mod dump_hir; pub mod format_args_collector; - -#[cfg(feature = "internal")] -pub mod internal_lints; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 405310512dff..5b3f60ad6ab0 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -68,6 +68,8 @@ declare_clippy_lint! { /// (including the standard library) provide modules named "prelude" specifically designed /// for wildcard import. /// + /// Wildcard imports reexported through `pub use` are also allowed. + /// /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name. /// /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag. @@ -121,7 +123,9 @@ impl LateLintPass<'_> for WildcardImports { } let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id); - if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) { + if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) + && !self.warn_on_all + { return; } if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index f6948be7f67a..a97643e0eaca 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -74,10 +74,10 @@ impl LateLintPass<'_> for ZeroSizedMapValues { fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { let parent_id = cx.tcx.hir_get_parent_item(hir_id); let second_parent_id = cx.tcx.hir_get_parent_item(parent_id.into()).def_id; - if let Node::Item(item) = cx.tcx.hir_node_by_def_id(second_parent_id) { - if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind { - return true; - } + if let Node::Item(item) = cx.tcx.hir_node_by_def_id(second_parent_id) + && let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind + { + return true; } false } diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 7667db469689..39c1aab8967a 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -131,7 +131,7 @@ struct WaitFinder<'a, 'tcx> { local_id: HirId, state: VisitorState, early_return: Option, - // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targetted help + // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help // messages missing_wait_branch: Option, } diff --git a/clippy_lints_internal/Cargo.toml b/clippy_lints_internal/Cargo.toml new file mode 100644 index 000000000000..2a0ceac27a32 --- /dev/null +++ b/clippy_lints_internal/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "clippy_lints_internal" +version = "0.0.1" +edition = "2021" + +[dependencies] +clippy_config = { path = "../clippy_config" } +clippy_utils = { path = "../clippy_utils" } +regex = { version = "1.5" } +rustc-semver = "1.1" + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs similarity index 92% rename from clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs rename to clippy_lints_internal/src/almost_standard_lint_formulation.rs index 0a01a364a75b..4fd5ea459a55 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -1,11 +1,12 @@ -use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type; +use crate::lint_without_lint_pass::is_lint_ref_type; use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_session::impl_lint_pass; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks if lint formulations have a standardized format. /// @@ -14,9 +15,10 @@ declare_clippy_lint! { /// /// ### Example /// `Checks for use...` can be written as `Checks for usage...` . - pub ALMOST_STANDARD_LINT_FORMULATION, - internal, - "lint formulations must have a standardized format." + pub clippy::ALMOST_STANDARD_LINT_FORMULATION, + Warn, + "lint formulations must have a standardized format.", + report_in_external_macro: true } impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]); diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_calls.rs similarity index 97% rename from clippy_lints/src/utils/internal_lints/collapsible_calls.rs rename to clippy_lints_internal/src/collapsible_calls.rs index 2e6fb7c4ce4d..d7967a0cc022 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints_internal/src/collapsible_calls.rs @@ -4,12 +4,13 @@ use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_bloc use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_session::declare_lint_pass; use rustc_span::Span; use std::borrow::{Borrow, Cow}; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Lints `span_lint_and_then` function calls, where the /// closure argument has only one statement and that statement is a method @@ -64,9 +65,10 @@ declare_clippy_lint! { /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg); /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg); /// ``` - pub COLLAPSIBLE_SPAN_LINT_CALLS, - internal, - "found collapsible `span_lint_and_then` calls" + pub clippy::COLLAPSIBLE_SPAN_LINT_CALLS, + Warn, + "found collapsible `span_lint_and_then` calls", + report_in_external_macro: true } declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); diff --git a/clippy_lints_internal/src/interning_literals.rs b/clippy_lints_internal/src/interning_literals.rs new file mode 100644 index 000000000000..6cee37442349 --- /dev/null +++ b/clippy_lints_internal/src/interning_literals.rs @@ -0,0 +1,102 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::match_type; +use clippy_utils::{def_path_def_ids, paths}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::mir::ConstValue; +use rustc_middle::ty; +use rustc_session::impl_lint_pass; +use rustc_span::sym; +use rustc_span::symbol::Symbol; + +declare_tool_lint! { + /// ### What it does + /// Checks for interning string literals as symbols + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs` + /// + /// ### Example + /// ```rust,ignore + /// let _ = Symbol::intern("f32"); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// let _ = sym::f32; + /// ``` + pub clippy::INTERNING_LITERALS, + Warn, + "interning a symbol that is a literal", + report_in_external_macro: true +} + +#[derive(Default)] +pub struct InterningDefinedSymbol { + // Maps the symbol to the import path + symbol_map: FxHashMap, +} + +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]); + +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { + fn check_crate(&mut self, cx: &LateContext<'_>) { + let modules = [ + ("kw", &paths::KW_MODULE[..]), + ("sym", &paths::SYM_MODULE), + ("sym", &paths::CLIPPY_SYM_MODULE), + ]; + for (prefix, module) in modules { + for def_id in def_path_def_ids(cx.tcx, module) { + // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will + // still lint but the suggestion will say to add it to `sym.rs` even if it's already there + if def_id.is_local() { + continue; + } + + for item in cx.tcx.module_children(def_id) { + if let Res::Def(DefKind::Const, item_def_id) = item.res + && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() + && match_type(cx, ty, &paths::SYMBOL) + && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) + && let Some(value) = value.to_u32().discard_err() + { + self.symbol_map.insert(value, (prefix, item.ident.name)); + } + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(func, [arg]) = &expr.kind + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() + && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) + && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + { + span_lint_and_then( + cx, + INTERNING_LITERALS, + expr.span, + "interning a string literal", + |diag| { + let value = Symbol::intern(&arg).as_u32(); + let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) { + ("use the preinterned symbol", format!("{prefix}::{name}")) + } else { + ( + "add the symbol to `clippy_utils/src/sym.rs` and use it", + format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")), + ) + }; + diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); + }, + ); + } + } +} diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints_internal/src/invalid_paths.rs similarity index 79% rename from clippy_lints/src/utils/internal_lints/invalid_paths.rs rename to clippy_lints_internal/src/invalid_paths.rs index 252ac5e67682..bee87efa3fcd 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints_internal/src/invalid_paths.rs @@ -5,12 +5,13 @@ use rustc_hir as hir; use rustc_hir::Item; use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, FloatTy}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks the paths module for invalid paths. /// @@ -19,9 +20,10 @@ declare_clippy_lint! { /// /// ### Example /// None. - pub INVALID_PATHS, - internal, - "invalid path" + pub clippy::INVALID_PATHS, + Warn, + "invalid path", + report_in_external_macro: true } declare_lint_pass!(InvalidPaths => [INVALID_PATHS]); @@ -80,22 +82,22 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { .copied(); for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { let lang_item_path = cx.get_def_path(item_def_id); - if path_syms.starts_with(&lang_item_path) { - if let [item] = &path_syms[lang_item_path.len()..] { - if matches!( - cx.tcx.def_kind(item_def_id), - DefKind::Mod | DefKind::Enum | DefKind::Trait - ) { - for child in cx.tcx.module_children(item_def_id) { - if child.ident.name == *item { - return true; - } + if path_syms.starts_with(&lang_item_path) + && let [item] = &path_syms[lang_item_path.len()..] + { + if matches!( + cx.tcx.def_kind(item_def_id), + DefKind::Mod | DefKind::Enum | DefKind::Trait + ) { + for child in cx.tcx.module_children(item_def_id) { + if child.ident.name == *item { + return true; } - } else { - for child in cx.tcx.associated_item_def_ids(item_def_id) { - if cx.tcx.item_name(*child) == *item { - return true; - } + } + } else { + for child in cx.tcx.associated_item_def_ids(item_def_id) { + if cx.tcx.item_name(*child) == *item { + return true; } } } diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs new file mode 100644 index 000000000000..1c42f4112f9a --- /dev/null +++ b/clippy_lints_internal/src/lib.rs @@ -0,0 +1,74 @@ +#![feature(let_chains, rustc_private)] +#![allow( + clippy::missing_docs_in_private_items, + clippy::must_use_candidate, + rustc::diagnostic_outside_of_impl, + rustc::untranslatable_diagnostic +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications, + rustc::internal +)] +// Disable this rustc lint for now, as it was also done in rustc +#![allow(rustc::potential_query_instability)] +// None of these lints need a version. +#![allow(clippy::missing_clippy_version_attribute)] + +extern crate rustc_ast; +extern crate rustc_attr_parsing; +extern crate rustc_data_structures; +extern crate rustc_errors; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_lint_defs; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; + +mod almost_standard_lint_formulation; +mod collapsible_calls; +mod interning_literals; +mod invalid_paths; +mod lint_without_lint_pass; +mod msrv_attr_impl; +mod outer_expn_data_pass; +mod produce_ice; +mod unnecessary_def_path; +mod unsorted_clippy_utils_paths; + +use rustc_lint::{Lint, LintStore}; + +static LINTS: &[&Lint] = &[ + almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, + collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, + interning_literals::INTERNING_LITERALS, + invalid_paths::INVALID_PATHS, + lint_without_lint_pass::DEFAULT_LINT, + lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, + lint_without_lint_pass::LINT_WITHOUT_LINT_PASS, + lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE, + msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, + outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, + produce_ice::PRODUCE_ICE, + unnecessary_def_path::UNNECESSARY_DEF_PATH, + unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, +]; + +pub fn register_lints(store: &mut LintStore) { + store.register_lints(LINTS); + + store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); + store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); + store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); + store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); + store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); +} diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs similarity index 90% rename from clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs rename to clippy_lints_internal/src/lint_without_lint_pass.rs index 94a2e598522b..6a75defcce34 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -9,13 +9,14 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Ensures every lint is associated to a `LintPass`. /// @@ -37,12 +38,14 @@ declare_clippy_lint! { /// declare_lint_pass!(Pass => [LINT_1, LINT_2]); /// // missing FORGOTTEN_LINT /// ``` - pub LINT_WITHOUT_LINT_PASS, - internal, - "declaring a lint without associating it in a LintPass" + pub clippy::LINT_WITHOUT_LINT_PASS, + Warn, + "declaring a lint without associating it in a LintPass", + report_in_external_macro: true + } -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks for cases of an auto-generated lint without an updated description, /// i.e. `default lint description`. @@ -59,30 +62,32 @@ declare_clippy_lint! { /// ```rust,ignore /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" } /// ``` - pub DEFAULT_LINT, - internal, - "found 'default lint description' in a lint declaration" + pub clippy::DEFAULT_LINT, + Warn, + "found 'default lint description' in a lint declaration", + report_in_external_macro: true } -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks for invalid `clippy::version` attributes. /// /// Valid values are: /// * "pre 1.29.0" /// * any valid semantic version - pub INVALID_CLIPPY_VERSION_ATTRIBUTE, - internal, - "found an invalid `clippy::version` attribute" + pub clippy::INVALID_CLIPPY_VERSION_ATTRIBUTE, + Warn, + "found an invalid `clippy::version` attribute", + report_in_external_macro: true } -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks for declared clippy lints without the `clippy::version` attribute. - /// - pub MISSING_CLIPPY_VERSION_ATTRIBUTE, - internal, - "found clippy lint without `clippy::version` attribute" + pub clippy::MISSING_CLIPPY_VERSION_ATTRIBUTE, + Warn, + "found clippy lint without `clippy::version` attribute", + report_in_external_macro: true } #[derive(Clone, Debug, Default)] @@ -100,10 +105,6 @@ impl_lint_pass!(LintWithoutLintPass => [ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) { - return; - } - if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind { if is_lint_ref_type(cx, ty) { check_invalid_clippy_version_attribute(cx, item); @@ -205,12 +206,10 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { mutbl: Mutability::Not, }, ) = ty.kind + && let TyKind::Path(ref path) = inner.kind + && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) { - if let TyKind::Path(ref path) = inner.kind { - if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) { - return match_def_path(cx, def_id, &paths::LINT); - } - } + return match_def_path(cx, def_id, &paths::LINT); } false diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints_internal/src/msrv_attr_impl.rs similarity index 93% rename from clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs rename to clippy_lints_internal/src/msrv_attr_impl.rs index 558acacb9724..dda054546e26 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints_internal/src/msrv_attr_impl.rs @@ -5,16 +5,17 @@ use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; use rustc_session::declare_lint_pass; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV. - /// - pub MISSING_MSRV_ATTR_IMPL, - internal, - "checking if all necessary steps were taken when adding a MSRV to a lint" + pub clippy::MISSING_MSRV_ATTR_IMPL, + Warn, + "checking if all necessary steps were taken when adding a MSRV to a lint", + report_in_external_macro: true } declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]); diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs similarity index 92% rename from clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs rename to clippy_lints_internal/src/outer_expn_data_pass.rs index 326e17214613..e94419647978 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -4,10 +4,11 @@ use clippy_utils::{is_lint_allowed, method_calls, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks for calls to `cx.outer().expn_data()` and suggests to use /// the `cx.outer_expn_data()` @@ -24,9 +25,10 @@ declare_clippy_lint! { /// ```rust,ignore /// expr.span.ctxt().outer_expn_data() /// ``` - pub OUTER_EXPN_EXPN_DATA, - internal, - "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`" + pub clippy::OUTER_EXPN_EXPN_DATA, + Warn, + "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`", + report_in_external_macro: true } declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]); diff --git a/clippy_lints/src/utils/internal_lints/produce_ice.rs b/clippy_lints_internal/src/produce_ice.rs similarity index 79% rename from clippy_lints/src/utils/internal_lints/produce_ice.rs rename to clippy_lints_internal/src/produce_ice.rs index 0a07919d659f..14e93dc6d5f1 100644 --- a/clippy_lints/src/utils/internal_lints/produce_ice.rs +++ b/clippy_lints_internal/src/produce_ice.rs @@ -1,10 +1,11 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint_defs::declare_tool_lint; use rustc_session::declare_lint_pass; use rustc_span::Span; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Not an actual lint. This lint is only meant for testing our customized internal compiler /// error message by calling `panic`. @@ -16,9 +17,10 @@ declare_clippy_lint! { /// ```rust,ignore /// 🍦🍦🍦🍦🍦 /// ``` - pub PRODUCE_ICE, - internal, - "this message should not appear anywhere as we ICE before and don't emit the lint" + pub clippy::PRODUCE_ICE, + Warn, + "this message should not appear anywhere as we ICE before and don't emit the lint", + report_in_external_macro: true } declare_lint_pass!(ProduceIce => [PRODUCE_ICE]); @@ -35,7 +37,7 @@ impl EarlyLintPass for ProduceIce { fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { match fn_kind { - FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy", + FnKind::Fn(_, _, func) => func.ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy", FnKind::Closure(..) => false, } } diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints_internal/src/unnecessary_def_path.rs similarity index 97% rename from clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs rename to clippy_lints_internal/src/unnecessary_def_path.rs index 76b0a52621be..6bdfbed55b06 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints_internal/src/unnecessary_def_path.rs @@ -8,6 +8,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::ty::{self, Ty}; @@ -17,7 +18,7 @@ use rustc_span::symbol::Symbol; use std::str; -declare_clippy_lint! { +declare_tool_lint! { /// ### What it does /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. /// @@ -34,9 +35,10 @@ declare_clippy_lint! { /// ```rust,ignore /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` - pub UNNECESSARY_DEF_PATH, - internal, - "using a def path when a diagnostic item or a `LangItem` is available" + pub clippy::UNNECESSARY_DEF_PATH, + Warn, + "using a def path when a diagnostic item or a `LangItem` is available", + report_in_external_macro: true } impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); @@ -281,10 +283,10 @@ fn path_from_array(exprs: &[Expr<'_>]) -> Option> { exprs .iter() .map(|expr| { - if let ExprKind::Lit(lit) = &expr.kind { - if let LitKind::Str(sym, _) = lit.node { - return Some((*sym.as_str()).to_owned()); - } + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(sym, _) = lit.node + { + return Some((*sym.as_str()).to_owned()); } None diff --git a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs new file mode 100644 index 000000000000..8e281ecb2ee4 --- /dev/null +++ b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs @@ -0,0 +1,54 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::ast::{Crate, ItemKind, ModKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; + +declare_tool_lint! { + /// ### What it does + /// Checks that [`clippy_utils::paths`] is sorted lexically + /// + /// ### Why is this bad? + /// We like to pretend we're an example of tidy code. + /// + /// ### Example + /// Wrong ordering of the util::paths constants. + pub clippy::UNSORTED_CLIPPY_UTILS_PATHS, + Warn, + "various things that will negatively affect your clippy experience", + report_in_external_macro: true +} + +declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); + +impl EarlyLintPass for UnsortedClippyUtilsPaths { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { + if let Some(utils) = krate + .items + .iter() + .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) + && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind + && let Some(paths) = items + .iter() + .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) + && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind + { + let mut last_name: Option = None; + for item in items { + let name = item.kind.ident().expect("const items have idents").to_string(); + if let Some(last_name) = last_name + && *last_name > *name + { + span_lint( + cx, + UNSORTED_CLIPPY_UTILS_PATHS, + item.span, + "this constant should be before the previous constant due to lexical \ + ordering", + ); + } + last_name = Some(name); + } + } + } +} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index ba4bb1d177c5..b98e99017503 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.87" +version = "0.1.88" # end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 7c665b424977..aceff14a1599 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-03-20 +nightly-2025-04-22 ``` diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index c5dce26143be..8996b694ed8f 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -348,11 +348,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => eq_id(*li, *ri) - && lm == rm - && ls == rs - && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( Const(box ConstItem { defaultness: ld, @@ -370,11 +366,13 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { expr: re, define_opaque: _, }), - ) => eq_defaultness(*ld, *rd) + ) => { + eq_defaultness(*ld, *rd) && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()), + && eq_expr_opt(le.as_ref(), re.as_ref()) + }, ( Fn(box ast::Fn { defaultness: ld, @@ -440,7 +438,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, (Enum(li, le, lg), Enum(ri, re, rg)) => { eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg) - } + }, (Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => { eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg) }, @@ -471,7 +469,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, (TraitAlias(li, lg, lb), TraitAlias(ri, rg, rb)) => { eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) - } + }, ( Impl(box ast::Impl { safety: lu, @@ -506,7 +504,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacroDef(li, ld), MacroDef(ri, rd)) => { eq_id(*li, *ri) && ld.macro_rules == rd.macro_rules && eq_delim_args(&ld.body, &rd.body) - } + }, _ => false, } } @@ -531,13 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => { - eq_id(*li, *ri) - && eq_ty(lt, rt) - && lm == rm - && eq_expr_opt(le.as_ref(), re.as_ref()) - && ls == rs - } + ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, @@ -620,7 +612,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) - } + }, ( Fn(box ast::Fn { defaultness: ld, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 17751e824c02..b9928b8eed49 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -43,14 +43,16 @@ pub enum Constant<'tcx> { Char(char), /// An integer's bit representation. Int(u128), - /// An `f16`. - F16(f16), + /// An `f16` bitcast to a `u16`. + // FIXME(f16_f128): use `f16` once builtins are available on all host tools platforms. + F16(u16), /// An `f32`. F32(f32), /// An `f64`. F64(f64), - /// An `f128`. - F128(f128), + /// An `f128` bitcast to a `u128`. + // FIXME(f16_f128): use `f128` once builtins are available on all host tools platforms. + F128(u128), /// `true` or `false`. Bool(bool), /// An array of constants. @@ -177,7 +179,7 @@ impl Hash for Constant<'_> { }, Self::F16(f) => { // FIXME(f16_f128): once conversions to/from `f128` are available on all platforms, - f.to_bits().hash(state); + f.hash(state); }, Self::F32(f) => { f64::from(f).to_bits().hash(state); @@ -186,7 +188,7 @@ impl Hash for Constant<'_> { f.to_bits().hash(state); }, Self::F128(f) => { - f.to_bits().hash(state); + f.hash(state); }, Self::Bool(b) => { b.hash(state); @@ -292,12 +294,12 @@ impl Constant<'_> { fn parse_f16(s: &str) -> Self { let f: Half = s.parse().unwrap(); - Self::F16(f16::from_bits(f.to_bits().try_into().unwrap())) + Self::F16(f.to_bits().try_into().unwrap()) } fn parse_f128(s: &str) -> Self { let f: Quad = s.parse().unwrap(); - Self::F128(f128::from_bits(f.to_bits())) + Self::F128(f.to_bits()) } } @@ -868,10 +870,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))), - ty::Float(FloatTy::F16) => Some(Constant::F16(f16::from_bits(int.into()))), + ty::Float(FloatTy::F16) => Some(Constant::F16(int.into())), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))), ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))), - ty::Float(FloatTy::F128) => Some(Constant::F128(f128::from_bits(int.into()))), + ty::Float(FloatTy::F128) => Some(Constant::F128(int.into())), ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))), _ => None, }, @@ -892,10 +894,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option let range = alloc_range(offset + size * idx, size); let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?; res.push(match flt { - FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().discard_err()?)), + FloatTy::F16 => Constant::F16(val.to_u16().discard_err()?), FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().discard_err()?)), FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().discard_err()?)), - FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().discard_err()?)), + FloatTy::F128 => Constant::F128(val.to_u128().discard_err()?), }); } Some(Constant::Vec(res)) diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 292792408c64..cd2098a89891 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -17,16 +17,16 @@ use rustc_span::Span; use std::env; fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { - if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { - if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { - diag.help(format!( - "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", - &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { - // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplit_once('.').unwrap().1) - }) - )); - } + if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() + && let Some(lint) = lint.name_lower().strip_prefix("clippy::") + { + diag.help(format!( + "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", + &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { + // extract just major + minor version and ignore patch versions + format!("rust-{}", n.rsplit_once('.').unwrap().1) + }) + )); } } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index c4d00002292c..d4e66ebd8e1f 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -118,18 +118,17 @@ impl<'hir> IfLet<'hir> { ) = expr.kind { let mut iter = cx.tcx.hir_parent_iter(expr.hir_id); - if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() { - if let Some(( + if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() + && let Some(( _, Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::While, _), .. }), )) = iter.next() - { - // while loop desugar - return None; - } + { + // while loop desugar + return None; } return Some(Self { let_pat, @@ -176,6 +175,12 @@ impl<'hir> IfLetOrMatch<'hir> { ), } } + + pub fn scrutinee(&self) -> &'hir Expr<'hir> { + match self { + Self::Match(scrutinee, _, _) | Self::IfLet(scrutinee, _, _, _, _) => scrutinee, + } + } } /// An `if` or `if let` expression diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index be295b59f609..fe1fd70a9fa7 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -148,7 +148,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Let(l), &StmtKind::Let(r)) => { + (StmtKind::Let(l), StmtKind::Let(r)) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { @@ -166,7 +166,7 @@ impl HirEqInterExpr<'_, '_, '_> { && both(l.els.as_ref(), r.els.as_ref(), |l, r| self.eq_block(l, r)) && self.eq_pat(l.pat, r.pat) }, - (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), + (StmtKind::Expr(l), StmtKind::Expr(r)) | (StmtKind::Semi(l), StmtKind::Semi(r)) => self.eq_expr(l, r), _ => false, } } @@ -260,7 +260,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).last().is_some_and(|macro_call| { matches!( - &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), + self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::todo_macro | sym::unimplemented_macro) ) }) @@ -301,58 +301,58 @@ impl HirEqInterExpr<'_, '_, '_> { reduce_exprkind(self.inner.cx, &left.kind), reduce_exprkind(self.inner.cx, &right.kind), ) { - (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => { + (ExprKind::AddrOf(lb, l_mut, le), ExprKind::AddrOf(rb, r_mut, re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) }, - (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r), - (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => { + (ExprKind::Array(l), ExprKind::Array(r)) => self.eq_exprs(l, r), + (ExprKind::Assign(ll, lr, _), ExprKind::Assign(rl, rr, _)) => { self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, - (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => { + (ExprKind::AssignOp(lo, ll, lr), ExprKind::AssignOp(ro, rl, rr)) => { self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, - (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r), - (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => { + (ExprKind::Block(l, _), ExprKind::Block(r, _)) => self.eq_block(l, r), + (ExprKind::Binary(l_op, ll, lr), ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) || swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, - (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => { + (ExprKind::Break(li, le), ExprKind::Break(ri, re)) => { both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name) && both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { + (ExprKind::Call(l_fun, l_args), ExprKind::Call(r_fun, r_args)) => { self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) => { + (ExprKind::Cast(lx, lt), ExprKind::Cast(rx, rt)) => { self.eq_expr(lx, rx) && self.eq_ty(lt, rt) }, - (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false, - (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body), - (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { + (ExprKind::Closure(_l), ExprKind::Closure(_r)) => false, + (ExprKind::ConstBlock(lb), ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body), + (ExprKind::Continue(li), ExprKind::Continue(ri)) => { both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name) }, - (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), - (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => { + (ExprKind::DropTemps(le), ExprKind::DropTemps(re)) => self.eq_expr(le, re), + (ExprKind::Field(l_f_exp, l_f_ident), ExprKind::Field(r_f_exp, r_f_ident)) => { l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp) }, - (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), - (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => { + (ExprKind::Index(la, li, _), ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), + (ExprKind::If(lc, lt, le), ExprKind::If(rc, rt, re)) => { self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Let(l), &ExprKind::Let(r)) => { + (ExprKind::Let(l), ExprKind::Let(r)) => { self.eq_pat(l.pat, r.pat) && both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init) }, (ExprKind::Lit(l), ExprKind::Lit(r)) => l.node == r.node, - (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => { + (ExprKind::Loop(lb, ll, lls, _), ExprKind::Loop(rb, rl, rls, _)) => { lls == rls && self.eq_block(lb, rb) && both(ll.as_ref(), rl.as_ref(), |l, r| l.ident.name == r.ident.name) }, - (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => { + (ExprKind::Match(le, la, ls), ExprKind::Match(re, ra, rs)) => { (ls == rs || (matches!((ls, rs), (TryDesugar(_), TryDesugar(_))))) && self.eq_expr(le, re) && over(la, ra, |l, r| { @@ -362,27 +362,27 @@ impl HirEqInterExpr<'_, '_, '_> { }) }, ( - &ExprKind::MethodCall(l_path, l_receiver, l_args, _), - &ExprKind::MethodCall(r_path, r_receiver, r_args, _), + ExprKind::MethodCall(l_path, l_receiver, l_args, _), + ExprKind::MethodCall(r_path, r_receiver, r_args, _), ) => { self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_expr(l_receiver, r_receiver) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) => + (ExprKind::UnsafeBinderCast(lkind, le, None), ExprKind::UnsafeBinderCast(rkind, re, None)) => lkind == rkind && self.eq_expr(le, re), - (&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) => + (ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) => lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt), - (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => { + (ExprKind::OffsetOf(l_container, l_fields), ExprKind::OffsetOf(r_container, r_fields)) => { self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name) }, (ExprKind::Path(l), ExprKind::Path(r)) => self.eq_qpath(l, r), - (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => { + (ExprKind::Repeat(le, ll), ExprKind::Repeat(re, rl)) => { self.eq_expr(le, re) && self.eq_const_arg(ll, rl) }, (ExprKind::Ret(l), ExprKind::Ret(r)) => both(l.as_ref(), r.as_ref(), |l, r| self.eq_expr(l, r)), - (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => { + (ExprKind::Struct(l_path, lf, lo), ExprKind::Struct(r_path, rf, ro)) => { self.eq_qpath(l_path, r_path) && match (lo, ro) { (StructTailExpr::Base(l),StructTailExpr::Base(r)) => self.eq_expr(l, r), @@ -392,58 +392,58 @@ impl HirEqInterExpr<'_, '_, '_> { } && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, - (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), - (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), - (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), - (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), - (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), + (ExprKind::Tup(l_tup), ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), + (ExprKind::Use(l_expr, _), ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), + (ExprKind::Type(le, lt), ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), + (ExprKind::Unary(l_op, le), ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), + (ExprKind::Yield(le, _), ExprKind::Yield(re, _)) => return self.eq_expr(le, re), ( // Else branches for branches above, grouped as per `match_same_arms`. - | &ExprKind::AddrOf(..) - | &ExprKind::Array(..) - | &ExprKind::Assign(..) - | &ExprKind::AssignOp(..) - | &ExprKind::Binary(..) - | &ExprKind::Become(..) - | &ExprKind::Block(..) - | &ExprKind::Break(..) - | &ExprKind::Call(..) - | &ExprKind::Cast(..) - | &ExprKind::ConstBlock(..) - | &ExprKind::Continue(..) - | &ExprKind::DropTemps(..) - | &ExprKind::Field(..) - | &ExprKind::Index(..) - | &ExprKind::If(..) - | &ExprKind::Let(..) - | &ExprKind::Lit(..) - | &ExprKind::Loop(..) - | &ExprKind::Match(..) - | &ExprKind::MethodCall(..) - | &ExprKind::OffsetOf(..) - | &ExprKind::Path(..) - | &ExprKind::Repeat(..) - | &ExprKind::Ret(..) - | &ExprKind::Struct(..) - | &ExprKind::Tup(..) - | &ExprKind::Use(..) - | &ExprKind::Type(..) - | &ExprKind::Unary(..) - | &ExprKind::Yield(..) - | &ExprKind::UnsafeBinderCast(..) + | ExprKind::AddrOf(..) + | ExprKind::Array(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Binary(..) + | ExprKind::Become(..) + | ExprKind::Block(..) + | ExprKind::Break(..) + | ExprKind::Call(..) + | ExprKind::Cast(..) + | ExprKind::ConstBlock(..) + | ExprKind::Continue(..) + | ExprKind::DropTemps(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::If(..) + | ExprKind::Let(..) + | ExprKind::Lit(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::MethodCall(..) + | ExprKind::OffsetOf(..) + | ExprKind::Path(..) + | ExprKind::Repeat(..) + | ExprKind::Ret(..) + | ExprKind::Struct(..) + | ExprKind::Tup(..) + | ExprKind::Use(..) + | ExprKind::Type(..) + | ExprKind::Unary(..) + | ExprKind::Yield(..) + | ExprKind::UnsafeBinderCast(..) // --- Special cases that do not have a positive branch. // `Err` represents an invalid expression, so let's never assume that // an invalid expressions is equal to anything. - | &ExprKind::Err(..) + | ExprKind::Err(..) // For the time being, we always consider that two closures are unequal. // This behavior may change in the future. - | &ExprKind::Closure(..) + | ExprKind::Closure(..) // For the time being, we always consider that two instances of InlineAsm are different. // This behavior may change in the future. - | &ExprKind::InlineAsm(_) + | ExprKind::InlineAsm(_) , _ ) => false, }; @@ -494,11 +494,11 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool { match (&left.kind, &right.kind) { ( - &PatExprKind::Lit { + PatExprKind::Lit { lit: left, negated: left_neg, }, - &PatExprKind::Lit { + PatExprKind::Lit { lit: right, negated: right_neg, }, @@ -512,47 +512,47 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two patterns are the same. fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool { match (&left.kind, &right.kind) { - (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r), - (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => { + (PatKind::Box(l), PatKind::Box(r)) => self.eq_pat(l, r), + (PatKind::Struct(lp, la, ..), PatKind::Struct(rp, ra, ..)) => { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r)) }, - (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => { + (PatKind::TupleStruct(lp, la, ls), PatKind::TupleStruct(rp, ra, rs)) => { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs }, - (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => { + (PatKind::Binding(lb, li, _, lp), PatKind::Binding(rb, ri, _, rp)) => { let eq = lb == rb && both(lp.as_ref(), rp.as_ref(), |l, r| self.eq_pat(l, r)); if eq { - self.locals.insert(li, ri); + self.locals.insert(*li, *ri); } eq }, - (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r), - (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), - (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => { + (PatKind::Expr(l), PatKind::Expr(r)) => self.eq_pat_expr(l, r), + (PatKind::Tuple(l, ls), PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), + (PatKind::Range(ls, le, li), PatKind::Range(rs, re, ri)) => { both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b)) && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b)) && (li == ri) }, - (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re), - (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => { + (PatKind::Ref(le, lm), PatKind::Ref(re, rm)) => lm == rm && self.eq_pat(le, re), + (PatKind::Slice(ls, li, le), PatKind::Slice(rs, ri, re)) => { over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) && both(li.as_ref(), ri.as_ref(), |l, r| self.eq_pat(l, r)) }, - (&PatKind::Wild, &PatKind::Wild) => true, + (PatKind::Wild, PatKind::Wild) => true, _ => false, } } fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool { match (left, right) { - (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => { + (QPath::Resolved(lty, lpath), QPath::Resolved(rty, rpath)) => { both(lty.as_ref(), rty.as_ref(), |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath) }, - (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => { + (QPath::TypeRelative(lty, lseg), QPath::TypeRelative(rty, rseg)) => { self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg) }, - (&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item, + (QPath::LangItem(llang_item, ..), QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item, _ => false, } } @@ -611,15 +611,15 @@ impl HirEqInterExpr<'_, '_, '_> { pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { match (&left.kind, &right.kind) { - (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_const_arg(ll, rl), + (TyKind::Slice(l_vec), TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), + (TyKind::Array(lt, ll), TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_const_arg(ll, rl), (TyKind::Ptr(l_mut), TyKind::Ptr(r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty), (TyKind::Ref(_, l_rmut), TyKind::Ref(_, r_rmut)) => { l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty) }, (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r), - (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), - (&TyKind::Infer(()), &TyKind::Infer(())) => true, + (TyKind::Tup(l), TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), + (TyKind::Infer(()), TyKind::Infer(())) => true, _ => false, } } @@ -853,9 +853,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&e.kind).hash(&mut self.s); - match e.kind { + match &e.kind { ExprKind::AddrOf(kind, m, e) => { - std::mem::discriminant(&kind).hash(&mut self.s); + std::mem::discriminant(kind).hash(&mut self.s); m.hash(&mut self.s); self.hash_expr(e); }, @@ -871,7 +871,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(l); self.hash_expr(r); }, - ExprKind::AssignOp(ref o, l, r) => { + ExprKind::AssignOp(o, l, r) => { std::mem::discriminant(&o.node).hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); @@ -887,11 +887,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(l); self.hash_expr(r); }, - ExprKind::Break(i, ref j) => { + ExprKind::Break(i, j) => { if let Some(i) = i.label { self.hash_name(i.ident.name); } - if let Some(j) = *j { + if let Some(j) = j { self.hash_expr(j); } }, @@ -903,20 +903,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(e); self.hash_ty(ty); }, - ExprKind::Closure(&Closure { + ExprKind::Closure(Closure { capture_clause, body, .. }) => { - std::mem::discriminant(&capture_clause).hash(&mut self.s); + std::mem::discriminant(capture_clause).hash(&mut self.s); // closures inherit TypeckResults - self.hash_expr(self.cx.tcx.hir_body(body).value); + self.hash_expr(self.cx.tcx.hir_body(*body).value); }, - ExprKind::ConstBlock(ref l_id) => { + ExprKind::ConstBlock(l_id) => { self.hash_body(l_id.body); }, ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); }, - ExprKind::Field(e, ref f) => { + ExprKind::Field(e, f) => { self.hash_expr(e); self.hash_name(f.name); }, @@ -991,23 +991,23 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Lit(l) => { l.node.hash(&mut self.s); }, - ExprKind::Loop(b, ref i, ..) => { + ExprKind::Loop(b, i, ..) => { self.hash_block(b); - if let Some(i) = *i { + if let Some(i) = i { self.hash_name(i.ident.name); } }, - ExprKind::If(cond, then, ref else_opt) => { + ExprKind::If(cond, then, else_opt) => { self.hash_expr(cond); self.hash_expr(then); - if let Some(e) = *else_opt { + if let Some(e) = else_opt { self.hash_expr(e); } }, - ExprKind::Match(e, arms, ref s) => { + ExprKind::Match(e, arms, s) => { self.hash_expr(e); - for arm in arms { + for arm in *arms { self.hash_pat(arm.pat); if let Some(e) = arm.guard { self.hash_expr(e); @@ -1017,38 +1017,38 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { s.hash(&mut self.s); }, - ExprKind::MethodCall(path, receiver, args, ref _fn_span) => { + ExprKind::MethodCall(path, receiver, args, _fn_span) => { self.hash_name(path.ident.name); self.hash_expr(receiver); self.hash_exprs(args); }, ExprKind::OffsetOf(container, fields) => { self.hash_ty(container); - for field in fields { + for field in *fields { self.hash_name(field.name); } }, - ExprKind::Path(ref qpath) => { + ExprKind::Path(qpath) => { self.hash_qpath(qpath); }, ExprKind::Repeat(e, len) => { self.hash_expr(e); self.hash_const_arg(len); }, - ExprKind::Ret(ref e) => { - if let Some(e) = *e { + ExprKind::Ret(e) => { + if let Some(e) = e { self.hash_expr(e); } }, - ExprKind::Struct(path, fields, ref expr) => { + ExprKind::Struct(path, fields, expr) => { self.hash_qpath(path); - for f in fields { + for f in *fields { self.hash_name(f.ident.name); self.hash_expr(f.expr); } - if let StructTailExpr::Base(e) = *expr { + if let StructTailExpr::Base(e) = expr { self.hash_expr(e); } }, @@ -1059,11 +1059,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(expr); }, ExprKind::Unary(lop, le) => { - std::mem::discriminant(&lop).hash(&mut self.s); + std::mem::discriminant(lop).hash(&mut self.s); self.hash_expr(le); }, ExprKind::UnsafeBinderCast(kind, expr, ty) => { - std::mem::discriminant(&kind).hash(&mut self.s); + std::mem::discriminant(kind).hash(&mut self.s); self.hash_expr(expr); if let Some(ty) = ty { self.hash_ty(ty); @@ -1084,7 +1084,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } pub fn hash_qpath(&mut self, p: &QPath<'_>) { - match *p { + match p { QPath::Resolved(_, path) => { self.hash_path(path); }, @@ -1092,7 +1092,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(path.ident.name); }, QPath::LangItem(lang_item, ..) => { - std::mem::discriminant(&lang_item).hash(&mut self.s); + std::mem::discriminant(lang_item).hash(&mut self.s); }, } // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); @@ -1123,11 +1123,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); - match pat.kind { + match &pat.kind { PatKind::Missing => unreachable!(), PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => { - std::mem::discriminant(&by_ref).hash(&mut self.s); - std::mem::discriminant(&mutability).hash(&mut self.s); + std::mem::discriminant(by_ref).hash(&mut self.s); + std::mem::discriminant(mutability).hash(&mut self.s); if let Some(pat) = pat { self.hash_pat(pat); } @@ -1135,7 +1135,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Expr(expr) => self.hash_pat_expr(expr), PatKind::Or(pats) => { - for pat in pats { + for pat in *pats { self.hash_pat(pat); } }, @@ -1146,44 +1146,44 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { if let Some(e) = e { self.hash_pat_expr(e); } - std::mem::discriminant(&i).hash(&mut self.s); + std::mem::discriminant(i).hash(&mut self.s); }, PatKind::Ref(pat, mu) => { self.hash_pat(pat); - std::mem::discriminant(&mu).hash(&mut self.s); + std::mem::discriminant(mu).hash(&mut self.s); }, PatKind::Guard(pat, guard) => { self.hash_pat(pat); self.hash_expr(guard); }, PatKind::Slice(l, m, r) => { - for pat in l { + for pat in *l { self.hash_pat(pat); } if let Some(pat) = m { self.hash_pat(pat); } - for pat in r { + for pat in *r { self.hash_pat(pat); } }, - PatKind::Struct(ref qpath, fields, e) => { + PatKind::Struct(qpath, fields, e) => { self.hash_qpath(qpath); - for f in fields { + for f in *fields { self.hash_name(f.ident.name); self.hash_pat(f.pat); } e.hash(&mut self.s); }, PatKind::Tuple(pats, e) => { - for pat in pats { + for pat in *pats { self.hash_pat(pat); } e.hash(&mut self.s); }, - PatKind::TupleStruct(ref qpath, pats, e) => { + PatKind::TupleStruct(qpath, pats, e) => { self.hash_qpath(qpath); - for pat in pats { + for pat in *pats { self.hash_pat(pat); } e.hash(&mut self.s); @@ -1261,7 +1261,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::Slice(ty) => { self.hash_ty(ty); }, - &TyKind::Array(ty, len) => { + TyKind::Array(ty, len) => { self.hash_ty(ty); self.hash_const_arg(len); }, @@ -1334,11 +1334,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) { for arg in arg_list { - match *arg { + match arg { GenericArg::Lifetime(l) => self.hash_lifetime(l), GenericArg::Type(ty) => self.hash_ty(ty.as_unambig_ty()), GenericArg::Const(ca) => self.hash_const_arg(ca.as_unambig_ct()), - GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()), + GenericArg::Infer(inf) => self.hash_ty(&inf.to_ty()), } } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f715fc86e4e5..264b9b0406d0 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,10 +1,8 @@ #![feature(array_chunks)] #![feature(box_patterns)] -#![feature(f128)] -#![feature(f16)] #![feature(if_let_guard)] -#![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] +#![feature(macro_metavar_expr)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_private)] @@ -53,9 +51,6 @@ extern crate rustc_span; extern crate rustc_trait_selection; extern crate smallvec; -#[macro_use] -pub mod sym_helper; - pub mod ast_utils; pub mod attrs; mod check_proc_macro; @@ -108,10 +103,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, - Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItem, - ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, - Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem, - TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def, + CoroutineDesugaring, CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, + GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, + Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, + Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -129,6 +124,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span}; +use source::walk_span_to_context; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; @@ -370,10 +366,10 @@ pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks if a method is defined in an impl of a diagnostic item pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { - if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { - if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() { - return cx.tcx.is_diagnostic_item(diag_item, adt.did()); - } + if let Some(impl_did) = cx.tcx.impl_of_method(def_id) + && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() + { + return cx.tcx.is_diagnostic_item(diag_item, adt.did()); } false } @@ -460,10 +456,10 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { QPath::Resolved(_, path) => match_path(path, segments), QPath::TypeRelative(ty, segment) => match ty.kind { TyKind::Path(ref inner_path) => { - if let [prefix @ .., end] = segments { - if match_qpath(inner_path, prefix) { - return segment.ident.name.as_str() == *end; - } + if let [prefix @ .., end] = segments + && match_qpath(inner_path, prefix) + { + return segment.ident.name.as_str() == *end; } false }, @@ -526,10 +522,10 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { /// If the expression is a path to a local, returns the canonical `HirId` of the local. pub fn path_to_local(expr: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { - if let Res::Local(id) = path.res { - return Some(id); - } + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind + && let Res::Local(id) = path.res + { + return Some(id); } None } @@ -896,16 +892,14 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< sym::BinaryHeap, ]; - if let QPath::TypeRelative(_, method) = path { - if method.ident.name == sym::new { - if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { - if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() { - return std_types_symbols.iter().any(|&symbol| { - cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string() - }); - } - } - } + if let QPath::TypeRelative(_, method) = path + && method.ident.name == sym::new + && let Some(impl_did) = cx.tcx.impl_of_method(def_id) + && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() + { + return std_types_symbols.iter().any(|&symbol| { + cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string() + }); } false } @@ -1030,6 +1024,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg), ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), + ExprKind::Block(Block { stmts: [], expr, .. }, _) => expr.is_some_and(|e| is_default_equivalent(cx, e)), _ => false, } } @@ -1206,12 +1201,10 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { .adjustments() .get(child_id) .map_or(&[][..], |x| &**x) - { - if let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) = + && let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) = *adjust.last().map_or(target, |a| a.target).kind() - { - return CaptureKind::Ref(mutability); - } + { + return CaptureKind::Ref(mutability); } match parent { @@ -1739,10 +1732,10 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool /// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { // FIXME: use constant folding - if let ExprKind::Lit(spanned) = expr.kind { - if let LitKind::Int(v, _) = spanned.node { - return v == value; - } + if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Int(v, _) = spanned.node + { + return v == value; } false } @@ -1779,10 +1772,10 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind { - if mac_name.as_str() == name { - return Some(new_span); - } + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind + && mac_name.as_str() == name + { + return Some(new_span); } span = new_span; @@ -1808,10 +1801,10 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind { - if mac_name.as_str() == name { - return Some(new_span); - } + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind + && mac_name.as_str() == name + { + return Some(new_span); } } @@ -1832,15 +1825,15 @@ pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) -> /// Checks if an expression is constructing a tuple-like enum variant or struct pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ExprKind::Call(fun, _) = expr.kind { - if let ExprKind::Path(ref qp) = fun.kind { - let res = cx.qpath_res(qp, fun.hir_id); - return match res { - Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, - Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), - _ => false, - }; - } + if let ExprKind::Call(fun, _) = expr.kind + && let ExprKind::Path(ref qp) = fun.kind + { + let res = cx.qpath_res(qp, fun.hir_id); + return match res { + Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, + Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), + _ => false, + }; } false } @@ -1914,10 +1907,10 @@ pub fn is_self(slf: &Param<'_>) -> bool { } pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { - if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind { - if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res { - return true; - } + if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind + && let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res + { + return true; } false } @@ -2122,10 +2115,10 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, } // final `else {..}` - if !blocks.is_empty() { - if let ExprKind::Block(block, _) = expr.kind { - blocks.push(block); - } + if !blocks.is_empty() + && let ExprKind::Block(block, _) = expr.kind + { + blocks.push(block); } (conds, blocks) @@ -2140,26 +2133,34 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { } } -/// Peels away all the compiler generated code surrounding the body of an async function, -pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind { - if let ExprKind::Block( +/// Peels away all the compiler generated code surrounding the body of an async closure. +pub fn get_async_closure_expr<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Closure(&Closure { + body, + kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)), + .. + }) = expr.kind + && let ExprKind::Block( Block { - stmts: [], expr: Some(Expr { - kind: ExprKind::DropTemps(expr), + kind: ExprKind::DropTemps(inner_expr), .. }), .. }, _, ) = tcx.hir_body(body).value.kind - { - return Some(expr); - } + { + Some(inner_expr) + } else { + None } - None +} + +/// Peels away all the compiler generated code surrounding the body of an async function, +pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { + get_async_closure_expr(tcx, body.value) } // check if expr is calling method or function with #[must_use] attribute @@ -2631,17 +2632,19 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir> } pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { - if let Res::Def(_, def_id) = path.res { - return cx.tcx.has_attr(def_id, sym::cfg_trace) || cx.tcx.has_attr(def_id, sym::cfg_attr); - } + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let Res::Def(_, def_id) = path.res + { + return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr); } false } static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); -fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { +/// Apply `f()` to the set of test item names. +/// The names are sorted using the default `Symbol` ordering. +fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); let value = map.entry(module); @@ -2653,18 +2656,16 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym if matches!(tcx.def_kind(id.owner_id), DefKind::Const) && let item = tcx.hir_item(id) && let ItemKind::Const(ident, ty, _generics, _body) = item.kind - { - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind // We could also check for the type name `test::TestDescAndFn` - if let Res::Def(DefKind::Struct, _) = path.res { - let has_test_marker = tcx - .hir_attrs(item.hir_id()) - .iter() - .any(|a| a.has_name(sym::rustc_test_marker)); - if has_test_marker { - names.push(ident.name); - } - } + && let Res::Def(DefKind::Struct, _) = path.res + { + let has_test_marker = tcx + .hir_attrs(item.hir_id()) + .iter() + .any(|a| a.has_name(sym::rustc_test_marker)); + if has_test_marker { + names.push(ident.name); } } } @@ -2685,18 +2686,37 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { // Since you can nest functions we need to collect all until we leave // function scope .any(|(_id, node)| { - if let Node::Item(item) = node { - if let ItemKind::Fn { ident, .. } = item.kind { - // Note that we have sorted the item names in the visitor, - // so the binary_search gets the same as `contains`, but faster. - return names.binary_search(&ident.name).is_ok(); - } + if let Node::Item(item) = node + && let ItemKind::Fn { ident, .. } = item.kind + { + // Note that we have sorted the item names in the visitor, + // so the binary_search gets the same as `contains`, but faster. + return names.binary_search(&ident.name).is_ok(); } false }) }) } +/// Checks if `fn_def_id` has a `#[test]` attribute applied +/// +/// This only checks directly applied attributes. To see if a node has a parent function marked with +/// `#[test]` use [`is_in_test_function`]. +/// +/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function +pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { + let id = tcx.local_def_id_to_hir_id(fn_def_id); + if let Node::Item(item) = tcx.hir_node(id) + && let ItemKind::Fn { ident, .. } = item.kind + { + with_test_item_names(tcx, tcx.parent_module(id), |names| { + names.binary_search(&ident.name).is_ok() + }) + } else { + false + } +} + /// Checks if `id` has a `#[cfg(test)]` attribute applied /// /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent @@ -3728,3 +3748,20 @@ pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir:: } hir_ty } + +/// If `expr` is a desugared `.await`, return the original expression if it does not come from a +/// macro expansion. +pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(_, [into_future_arg]) = match_value.kind + && let ctxt = expr.span.ctxt() + && for_each_expr_without_closures(into_future_arg, |e| { + walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) + }) + .is_none() + { + Some(into_future_arg) + } else { + None + } +} diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index ffcfcd240ea5..9ba644fdd20e 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -76,7 +76,7 @@ impl<'tcx> Visitor<'tcx> for V<'_> { } if matches!( ctx, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move | NonMutatingUseContext::Inspect) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) ) { self.results[i].local_consume_or_mutate_locs.push(loc); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 86f4f190b950..19061b574ff8 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,10 +1,10 @@ +use crate::sym; use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; - use rustc_attr_parsing::{RustcVersion, parse_version}; use rustc_lint::LateContext; use rustc_session::Session; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use serde::Deserialize; use smallvec::SmallVec; use std::iter::once; @@ -24,10 +24,10 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT } 1,85,0 { UINT_FLOAT_MIDPOINT } - 1,84,0 { CONST_OPTION_AS_SLICE } + 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } - 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION } + 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION, DURATION_ABS_DIFF } 1,80,0 { BOX_INTO_ITER, LAZY_CELL } 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } @@ -40,6 +40,7 @@ msrv_aliases! { 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } + 1,60,0 { ABS_DIFF } 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,57,0 { MAP_WHILE } @@ -63,6 +64,7 @@ msrv_aliases! { 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,33,0 { UNDERSCORE_IMPORTS } + 1,32,0 { CONST_IS_POWER_OF_TWO } 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } @@ -182,8 +184,7 @@ impl MsrvStack { } fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option { - let sym_msrv = Symbol::intern("msrv"); - let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); + let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv])); if let Some(msrv_attr) = msrv_attrs.next() { if let Some(duplicate) = msrv_attrs.next_back() { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 51d06ad9b1aa..7f64ebd3b643 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -30,9 +30,11 @@ pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"] pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "", "is_ascii"]; pub const IO_ERROR_NEW: [&str; 5] = ["std", "io", "error", "Error", "new"]; pub const IO_ERRORKIND_OTHER: [&str; 5] = ["std", "io", "error", "ErrorKind", "Other"]; +pub const ALIGN_OF: [&str; 3] = ["core", "mem", "align_of"]; // Paths in clippy itself pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"]; +pub const CLIPPY_SYM_MODULE: [&str; 2] = ["clippy_utils", "sym"]; // Paths in external crates #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 80066e9702d3..3aa72cf5eaff 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -142,7 +142,19 @@ pub trait SpanRangeExt: SpanRange { map_range(cx.sess().source_map(), self.into_range(), f) } - /// Extends the range to include all preceding whitespace characters. + /// Extends the range to include all preceding whitespace characters, unless there + /// are non-whitespace characters left on the same line after `self`. + /// + /// This extra condition prevents a problem when removing the '}' in: + /// ```ignore + /// ( // There was an opening bracket after the parenthesis, which has been removed + /// // This is a comment + /// }) + /// ``` + /// Removing the whitespaces, including the linefeed, before the '}', would put the + /// closing parenthesis at the end of the `// This is a comment` line, which would + /// make it part of the comment as well. In this case, it is best to keep the span + /// on the '}' alone. fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { with_leading_whitespace(cx.sess().source_map(), self.into_range()) } @@ -263,10 +275,15 @@ fn map_range( } fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |src, range| { - Some(src.get(..range.start)?.trim_end().len()..range.end) + map_range(sm, sp, |src, range| { + let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len(); + if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) { + Some(src.get(..range.start)?.trim_end().len()..range.end) + } else { + Some(range) + } }) - .unwrap_or(sp) + .unwrap() } fn trim_start(sm: &SourceMap, sp: Range) -> Range { @@ -384,10 +401,10 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { - if let Some(snippet) = snippet_opt(sess, span) { - if snippet.is_empty() { - return false; - } + if let Some(snippet) = snippet_opt(sess, span) + && snippet.is_empty() + { + return false; } true } @@ -408,11 +425,11 @@ pub fn position_before_rarrow(s: &str) -> Option { let mut rpos = rpos; let chars: Vec = s.chars().collect(); while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } + if let Some(c) = chars.get(rpos - 1) + && c.is_whitespace() + { + rpos -= 1; + continue; } break; } diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index 421b25a77fe8..f0f82c8dddcf 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -1,4 +1,4 @@ -/// Dealing with sting indices can be hard, this struct ensures that both the +/// Dealing with string indices can be hard, this struct ensures that both the /// character and byte index are provided for correct indexing. #[derive(Debug, Default, PartialEq, Eq)] pub struct StrIndex { @@ -165,7 +165,7 @@ pub fn camel_case_split(s: &str) -> Vec<&str> { offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect() } -/// Dealing with sting comparison can be complicated, this struct ensures that both the +/// Dealing with string comparison can be complicated, this struct ensures that both the /// character and byte count are provided for correct indexing. #[derive(Debug, Default, PartialEq, Eq)] pub struct StrCount { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index e92c0c79b255..93dec113d31a 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -326,7 +326,7 @@ impl<'a> Sugg<'a> { /// `self` argument of a method call /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`). #[must_use] - pub fn maybe_par(self) -> Self { + pub fn maybe_paren(self) -> Self { match self { Sugg::NonParen(..) => self, // `(x)` and `(x).y()` both don't need additional parens. @@ -494,7 +494,7 @@ impl Display for ParenHelper { /// operators have the same /// precedence. pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { - Sugg::MaybeParen(format!("{op}{}", expr.maybe_par()).into()) + Sugg::MaybeParen(format!("{op}{}", expr.maybe_paren()).into()) } /// Builds the string for ` ` adding parenthesis when necessary. @@ -946,10 +946,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // some items do not need explicit deref, such as array accesses, // so we mark them as already processed // i.e.: don't suggest `*sub[1..4].len()` for `|sub| sub[1..4].len() == 3` - if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() { - if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) { - projections_handled = true; - } + if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() + && matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) { + projections_handled = true; } }, } @@ -1008,12 +1007,12 @@ mod test { } #[test] - fn binop_maybe_par() { + fn binop_maybe_paren() { let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "1".into(), "1".into()); - assert_eq!("(1 + 1)", sugg.maybe_par().to_string()); + assert_eq!("(1 + 1)", sugg.maybe_paren().to_string()); let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into()); - assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string()); + assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_paren().to_string()); } #[test] fn not_op() { diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 9cc72a5b3aaa..1a30b473d106 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -1,23 +1,69 @@ #![allow(non_upper_case_globals)] -use rustc_span::symbol::{Symbol, PREDEFINED_SYMBOLS_COUNT}; +use rustc_span::symbol::{PREDEFINED_SYMBOLS_COUNT, Symbol}; +#[doc(no_inline)] pub use rustc_span::sym::*; +macro_rules! val { + ($name:ident) => { + stringify!($name) + }; + ($name:ident $value:literal) => { + $value + }; +} + macro_rules! generate { - ($($sym:ident,)*) => { + ($($name:ident $(: $value:literal)? ,)*) => { /// To be supplied to `rustc_interface::Config` pub const EXTRA_SYMBOLS: &[&str] = &[ - $(stringify!($sym),)* + $( + val!($name $($value)?), + )* ]; $( - pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); + pub const $name: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); )* }; } generate! { + as_bytes, + as_deref_mut, + as_deref, + as_mut, + Binary, + Cargo_toml: "Cargo.toml", + CLIPPY_ARGS, + CLIPPY_CONF_DIR, + cloned, + contains, + copied, + Current, + get, + insert, + int_roundings, + IntoIter, + is_empty, + is_ok, + is_some, + LowerExp, + LowerHex, + msrv, + Octal, + or_default, + regex, rustfmt_skip, + Start, + to_owned, unused_extern_crates, + unwrap_err, + unwrap_or_default, + UpperExp, + UpperHex, + V4, + V6, + Weak, } diff --git a/clippy_utils/src/sym_helper.rs b/clippy_utils/src/sym_helper.rs deleted file mode 100644 index f47dc80ebade..000000000000 --- a/clippy_utils/src/sym_helper.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[macro_export] -/// Convenience wrapper around rustc's `Symbol::intern` -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index d33e59342a59..8db9cd593b33 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -19,9 +19,9 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, - GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, + self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, + GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -128,10 +128,10 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' // For `impl Trait`, it will register a predicate of `::Assoc = U`, // so we check the term for `U`. ty::ClauseKind::Projection(projection_predicate) => { - if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { - if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { - return true; - } + if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() + && contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) + { + return true; } }, _ => (), @@ -337,20 +337,20 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() { - if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { - if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { - return true; - } + if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) + { + return true; } } false }, ty::Dynamic(binder, _, _) => { for predicate in *binder { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { - return true; - } + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() + && cx.tcx.has_attr(trait_ref.def_id, sym::must_use) + { + return true; } } false @@ -1352,7 +1352,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n } } -/// Get's the type of a field by name. +/// Gets the type of a field by name. pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option> { match *ty.kind() { ty::Adt(def, args) if def.is_union() || def.is_struct() => def @@ -1376,3 +1376,49 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } } + +/// Check if a Ty<'_> of `Iterator` contains any mutable access to non-owning types by checking if +/// it contains fields of mutable references or pointers, or references/pointers to non-`Freeze` +/// types, or `PhantomData` types containing any of the previous. This can be used to check whether +/// skipping iterating over an iterator will change its behavior. +pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>) -> bool { + fn normalize_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty) + } + + /// Check if `ty` contains mutable references or equivalent, which includes: + /// - A mutable reference/pointer. + /// - A reference/pointer to a non-`Freeze` type. + /// - A `PhantomData` type containing any of the previous. + fn has_non_owning_mutable_access_inner<'tcx>( + cx: &LateContext<'tcx>, + phantoms: &mut FxHashSet>, + ty: Ty<'tcx>, + ) -> bool { + match ty.kind() { + ty::Adt(adt_def, args) if adt_def.is_phantom_data() => { + phantoms.insert(ty) + && args + .types() + .any(|arg_ty| has_non_owning_mutable_access_inner(cx, phantoms, arg_ty)) + }, + ty::Adt(adt_def, args) => adt_def.all_fields().any(|field| { + has_non_owning_mutable_access_inner(cx, phantoms, normalize_ty(cx, field.ty(cx.tcx, args))) + }), + ty::Array(elem_ty, _) | ty::Slice(elem_ty) => has_non_owning_mutable_access_inner(cx, phantoms, *elem_ty), + ty::RawPtr(pointee_ty, mutability) | ty::Ref(_, pointee_ty, mutability) => { + mutability.is_mut() || !pointee_ty.is_freeze(cx.tcx, cx.typing_env()) + }, + ty::Closure(_, closure_args) => { + matches!(closure_args.types().next_back(), Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures)) + }, + ty::Tuple(tuple_args) => tuple_args + .iter() + .any(|arg_ty| has_non_owning_mutable_access_inner(cx, phantoms, arg_ty)), + _ => false, + } + } + + let mut phantoms = FxHashSet::default(); + has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty) +} diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index a079fd940c00..1b049b6d12c4 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -126,10 +126,10 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) -> Self::Result { - if let Res::Local(id) = path.res { - if self.binding_ids.contains(&id) { - return ControlFlow::Break(()); - } + if let Res::Local(id) = path.res + && self.binding_ids.contains(&id) + { + return ControlFlow::Break(()); } ControlFlow::Continue(()) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 63dd00f2de0f..fc6e30a98047 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -297,10 +297,10 @@ where /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { for_each_expr(cx, cx.tcx.hir_body(body).value, |e| { - if let ExprKind::Path(p) = &e.kind { - if cx.qpath_res(p, e.hir_id) == res { - return ControlFlow::Break(()); - } + if let ExprKind::Path(p) = &e.kind + && cx.qpath_res(p, e.hir_id) == res + { + return ControlFlow::Break(()); } ControlFlow::Continue(()) }) diff --git a/lintcheck/ci-config/clippy.toml b/lintcheck/ci-config/clippy.toml new file mode 100644 index 000000000000..9853465c83f0 --- /dev/null +++ b/lintcheck/ci-config/clippy.toml @@ -0,0 +1,7 @@ +# Configuration applied when running lintcheck from the CI +# +# The CI will set the `CLIPPY_CONF_DIR` environment variable +# to `$PWD/lintcheck/ci-config`. + +avoid-breaking-exported-api = false +lint-commented-code = false diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 8d0d41ab9450..fe488ef89da1 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -120,14 +120,17 @@ impl Crate { if config.perf { cmd = Command::new("perf"); + let perf_data_filename = get_perf_data_filename(&self.path); cmd.args(&[ "record", "-e", "instructions", // Only count instructions "-g", // Enable call-graph, useful for flamegraphs and produces richer reports "--quiet", // Do not tamper with lintcheck's normal output + "--compression-level=22", + "--freq=3000", // Slow down program to capture all events "-o", - "perf.data", + &perf_data_filename, "--", "cargo", ]); @@ -165,7 +168,7 @@ impl Crate { return Vec::new(); } - if !config.fix { + if !config.fix && !config.perf { cmd.arg("--message-format=json"); } @@ -203,6 +206,11 @@ impl Crate { return Vec::new(); } + // We don't want to keep target directories if benchmarking + if config.perf { + let _ = fs::remove_dir_all(&shared_target_dir); + } + // get all clippy warnings and ICEs let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { @@ -441,6 +449,35 @@ fn lintcheck(config: LintcheckConfig) { fs::write(&config.lintcheck_results_path, text).unwrap(); } +/// Traverse a directory looking for `perf.data.` files, and adds one +/// to the most recent of those files, returning the new most recent `perf.data` +/// file name. +fn get_perf_data_filename(source_path: &Path) -> String { + if source_path.join("perf.data").exists() { + let mut max_number = 0; + fs::read_dir(source_path) + .unwrap() + .filter_map(Result::ok) + .filter(|path| { + path.file_name() + .as_os_str() + .to_string_lossy() // We don't care about data loss, as we're checking for equality + .starts_with("perf.data") + }) + .for_each(|path| { + let file_name = path.file_name(); + let file_name = file_name.as_os_str().to_str().unwrap().split('.').next_back().unwrap(); + if let Ok(parsed_file_name) = file_name.parse::() + && parsed_file_name >= max_number + { + max_number = parsed_file_name + 1; + } + }); + return format!("perf.data.{max_number}"); + } + String::from("perf.data") +} + /// Returns the path to the Clippy project directory #[must_use] fn clippy_project_root() -> &'static Path { diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 57073f523648..6406b2dcb643 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -64,7 +64,7 @@ fn process_stream( // It's 99% likely that dependencies compiled with recursive mode are on crates.io // and therefore on docs.rs. This links to the sources directly, do avoid invalid - // links due to remaped paths. See rust-lang/docs.rs#2551 for more details. + // links due to remapped paths. See rust-lang/docs.rs#2551 for more details. let base_url = format!( "https://docs.rs/crate/{}/{}/source/src/{{file}}#{{line}}", driver_info.package_name, driver_info.version diff --git a/rust-toolchain b/rust-toolchain.toml similarity index 85% rename from rust-toolchain rename to rust-toolchain.toml index fcaeedc9a66b..d2f79da1a541 100644 --- a/rust-toolchain +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-03-20" +channel = "nightly-2025-04-22" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 423154a69fa0..b45edf234558 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -121,7 +121,7 @@ fn get_output(cmd: &str, args: &[&str]) -> Option { pub fn rerun_if_git_changes() -> Option<()> { // Make sure we get rerun when the git commit changes. // We want to watch two files: HEAD, which tracks which branch we are on, - // and the file for that branch that tracks which commit is is on. + // and the file for that branch that tracks which commit is checked out. // First, find the `HEAD` file. This should work even with worktrees. let git_head_file = PathBuf::from(get_output("git", &["rev-parse", "--git-path", "HEAD"])?); diff --git a/src/driver.rs b/src/driver.rs index df9c4e8e6ae9..87ca9c5beddf 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -14,6 +14,7 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::sym; use rustc_interface::interface; use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; @@ -78,7 +79,7 @@ fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) { psess .env_depinfo .get_mut() - .insert((Symbol::intern("CLIPPY_ARGS"), args_env_var.map(Symbol::intern))); + .insert((sym::CLIPPY_ARGS, args_env_var.map(Symbol::intern))); } /// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy @@ -89,7 +90,7 @@ fn track_files(psess: &mut ParseSess) { // Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver` // with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine if Path::new("Cargo.toml").exists() { - file_depinfo.insert(Symbol::intern("Cargo.toml")); + file_depinfo.insert(sym::Cargo_toml); } // `clippy.toml` will be automatically tracked as it's loaded with `sess.source_map().load_file()` @@ -145,7 +146,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so // changes between dirs that are invalid UTF-8 will not trigger rebuilds psess.env_depinfo.get_mut().insert(( - Symbol::intern("CLIPPY_CONF_DIR"), + sym::CLIPPY_CONF_DIR, env::var("CLIPPY_CONF_DIR").ok().map(|dir| Symbol::intern(&dir)), )); })); @@ -158,9 +159,10 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_config::Conf::read(sess, &conf_path); clippy_lints::register_lints(lint_store, conf); - clippy_lints::register_pre_expansion_lints(lint_store, conf); + #[cfg(feature = "internal")] + clippy_lints_internal::register_lints(lint_store); })); - config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into(); + config.extra_symbols = sym::EXTRA_SYMBOLS.into(); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be // run on the unoptimized MIR. On the other hand this results in some false negatives. If @@ -208,12 +210,12 @@ pub fn main() { // Beside checking for existence of `--sysroot` on the command line, we need to // check for the arg files that are prefixed with @ as well to be consistent with rustc for arg in args.iter() { - if let Some(arg_file_path) = arg.strip_prefix('@') { - if let Ok(arg_file) = read_to_string(arg_file_path) { - let split_arg_file: Vec = arg_file.lines().map(ToString::to_string).collect(); - if has_arg(&split_arg_file, "--sysroot") { - return true; - } + if let Some(arg_file_path) = arg.strip_prefix('@') + && let Ok(arg_file) = read_to_string(arg_file_path) + { + let split_arg_file: Vec = arg_file.lines().map(ToString::to_string).collect(); + if has_arg(&split_arg_file, "--sysroot") { + return true; } } } @@ -222,10 +224,10 @@ pub fn main() { let sys_root_env = std::env::var("SYSROOT").ok(); let pass_sysroot_env_if_given = |args: &mut Vec, sys_root_env| { - if let Some(sys_root) = sys_root_env { - if !has_sysroot_arg(args) { - args.extend(vec!["--sysroot".into(), sys_root]); - } + if let Some(sys_root) = sys_root_env + && !has_sysroot_arg(args) + { + args.extend(vec!["--sysroot".into(), sys_root]); } }; diff --git a/tests/clippy.toml b/tests/clippy.toml index 5eb7ac035419..91a2e55180b9 100644 --- a/tests/clippy.toml +++ b/tests/clippy.toml @@ -1 +1,2 @@ # default config for tests, overrides clippy.toml at the project root +lint-commented-code = false diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 956a05288f35..6d391bd622a8 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -2,6 +2,8 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] +use askama::Template; +use askama::filters::Safe; use cargo_metadata::Message; use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; @@ -9,11 +11,10 @@ use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; use pulldown_cmark::{Options, Parser, html}; -use rinja::Template; -use rinja::filters::Safe; use serde::Deserialize; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; +use ui_test::custom_flags::edition::Edition; use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; use ui_test::{Args, CommandBuilder, Config, Match, error_on_output_conflict, status_emitter}; @@ -86,13 +87,13 @@ fn extern_flags() -> Vec { let name = name.strip_prefix("lib").unwrap_or(name); Some((name, path_str)) }; - if let Some((name, path)) = parse_name_path() { - if TEST_DEPENDENCIES.contains(&name) { - // A dependency may be listed twice if it is available in sysroot, - // and the sysroot dependencies are listed first. As of the writing, - // this only seems to apply to if_chain. - crates.insert(name, path); - } + if let Some((name, path)) = parse_name_path() + && TEST_DEPENDENCIES.contains(&name) + { + // A dependency may be listed twice if it is available in sysroot, + // and the sysroot dependencies are listed first. As of the writing, + // this only seems to apply to if_chain. + crates.insert(name, path); } } let not_found: Vec<&str> = TEST_DEPENDENCIES @@ -147,11 +148,16 @@ impl TestContext { .map(|filters| filters.split(',').map(str::to_string).collect()) .unwrap_or_default(), target: None, - bless_command: Some("cargo uibless".into()), + bless_command: Some(if IS_RUSTC_TEST_SUITE { + "./x test src/tools/clippy --bless".into() + } else { + "cargo uibless".into() + }), out_dir: target_dir.join("ui_test"), ..Config::rustc(Path::new("tests").join(test_dir)) }; let defaults = config.comment_defaults.base(); + defaults.set_custom("edition", Edition("2024".into())); defaults.exit_status = None.into(); if mandatory_annotations { defaults.require_annotations = Some(Spanned::dummy(true)).into(); diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 858be389a9e6..16a1a415102c 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -36,6 +36,7 @@ fn dogfood() { for package in [ "./", "clippy_dev", + "clippy_lints_internal", "clippy_lints", "clippy_utils", "clippy_config", @@ -80,11 +81,9 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { command.arg("--").args(args); command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + command.args(["-D", "clippy::dbg_macro"]); - if cfg!(feature = "internal") { - // internal lints only exist if we build with the internal feature - command.args(["-D", "clippy::internal"]); - } else { + if !cfg!(feature = "internal") { // running a clippy built without internal lints on the clippy source // that contains e.g. `allow(clippy::invalid_paths)` command.args(["-A", "unknown_lints"]); diff --git a/tests/ui-internal/auxiliary/paths.rs b/tests/ui-internal/auxiliary/paths.rs index 52fcaec4df32..f730f564a09c 100644 --- a/tests/ui-internal/auxiliary/paths.rs +++ b/tests/ui-internal/auxiliary/paths.rs @@ -1,2 +1,4 @@ +#![allow(clippy::unnecessary_def_path)] + pub static OPTION: [&str; 3] = ["core", "option", "Option"]; pub const RESULT: &[&str] = &["core", "result", "Result"]; diff --git a/tests/ui-internal/check_clippy_version_attribute.rs b/tests/ui-internal/check_clippy_version_attribute.rs index e5f6001b74d0..897002949e67 100644 --- a/tests/ui-internal/check_clippy_version_attribute.rs +++ b/tests/ui-internal/check_clippy_version_attribute.rs @@ -1,5 +1,5 @@ -#![deny(clippy::internal)] #![feature(rustc_private)] +#![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] #[macro_use] extern crate rustc_middle; @@ -86,6 +86,15 @@ mod internal_clippy_lints { } use crate::internal_clippy_lints::ALLOW_MISSING_ATTRIBUTE_ONE; -declare_lint_pass!(Pass2 => [VALID_ONE, VALID_TWO, VALID_THREE, INVALID_ONE, INVALID_TWO, MISSING_ATTRIBUTE_ONE, MISSING_ATTRIBUTE_TWO, ALLOW_MISSING_ATTRIBUTE_ONE]); +declare_lint_pass!(Pass2 => [ + VALID_ONE, + VALID_TWO, + VALID_THREE, + INVALID_ONE, + INVALID_TWO, + MISSING_ATTRIBUTE_ONE, + MISSING_ATTRIBUTE_TWO, + ALLOW_MISSING_ATTRIBUTE_ONE, +]); fn main() {} diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 1129c35d1d01..952bc9440303 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -12,11 +12,10 @@ LL | | } | = help: please use a valid semantic version, see `doc/adding_lints.md` note: the lint level is defined here - --> tests/ui-internal/check_clippy_version_attribute.rs:1:9 + --> tests/ui-internal/check_clippy_version_attribute.rs:2:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute @@ -47,7 +46,11 @@ LL | | } | |_^ | = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` +note: the lint level is defined here + --> tests/ui-internal/check_clippy_version_attribute.rs:2:51 + | +LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value diff --git a/tests/ui-internal/check_formulation.rs b/tests/ui-internal/check_formulation.rs index 8265a78769d1..bcbb0d783198 100644 --- a/tests/ui-internal/check_formulation.rs +++ b/tests/ui-internal/check_formulation.rs @@ -1,4 +1,5 @@ -#![warn(clippy::almost_standard_lint_formulation)] +#![deny(clippy::almost_standard_lint_formulation)] +#![allow(clippy::lint_without_lint_pass)] #![feature(rustc_private)] #[macro_use] diff --git a/tests/ui-internal/check_formulation.stderr b/tests/ui-internal/check_formulation.stderr index b16e1bf86873..9aeb9e1f2d49 100644 --- a/tests/ui-internal/check_formulation.stderr +++ b/tests/ui-internal/check_formulation.stderr @@ -1,15 +1,18 @@ error: non-standard lint formulation - --> tests/ui-internal/check_formulation.rs:23:5 + --> tests/ui-internal/check_formulation.rs:24:5 | LL | /// Check for lint formulations that are correct | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using `Checks for` - = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]` +note: the lint level is defined here + --> tests/ui-internal/check_formulation.rs:1:9 + | +LL | #![deny(clippy::almost_standard_lint_formulation)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-standard lint formulation - --> tests/ui-internal/check_formulation.rs:34:5 + --> tests/ui-internal/check_formulation.rs:35:5 | LL | /// Detects uses of incorrect formulations | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index 918e33345a77..76f68686ee2a 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::collapsible_span_lint_calls)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index 2f289ae2b481..214c8783a669 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::collapsible_span_lint_calls)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr index a2be1f1cd367..9c83538947ca 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.stderr +++ b/tests/ui-internal/collapsible_span_lint_calls.stderr @@ -10,9 +10,8 @@ LL | | }); note: the lint level is defined here --> tests/ui-internal/collapsible_span_lint_calls.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::collapsible_span_lint_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call is collapsible --> tests/ui-internal/collapsible_span_lint_calls.rs:39:9 diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 71819fe37070..c7e92b1bf164 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -6,7 +6,7 @@ //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc running on " //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" -#![deny(clippy::internal)] +#![deny(clippy::produce_ice)] #![allow(clippy::missing_clippy_version_attribute)] fn it_looks_like_you_are_trying_to_kill_clippy() {} diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 589e1190a907..884d3d035a29 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -8,7 +8,7 @@ error: internal compiler error: Would you like some help with that? LL | fn it_looks_like_you_are_trying_to_kill_clippy() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: delayed at clippy_lints/src/utils/internal_lints/produce_ice.rs - disabled backtrace +note: delayed at clippy_lints_internal/src/produce_ice.rs - disabled backtrace --> tests/ui-internal/custom_ice_message.rs:12:1 | LL | fn it_looks_like_you_are_trying_to_kill_clippy() {} diff --git a/tests/ui-internal/default_lint.rs b/tests/ui-internal/default_lint.rs index 959bfd27e389..809f2c4d080d 100644 --- a/tests/ui-internal/default_lint.rs +++ b/tests/ui-internal/default_lint.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::default_lint)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/default_lint.stderr b/tests/ui-internal/default_lint.stderr index 9d4c2e15349f..2c700ec82dcd 100644 --- a/tests/ui-internal/default_lint.stderr +++ b/tests/ui-internal/default_lint.stderr @@ -13,9 +13,8 @@ LL | | } note: the lint level is defined here --> tests/ui-internal/default_lint.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::default_lint)] + | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-internal/disallow_span_lint.rs b/tests/ui-internal/disallow_span_lint.rs index 3fed38cab64d..36e4158f6e68 100644 --- a/tests/ui-internal/disallow_span_lint.rs +++ b/tests/ui-internal/disallow_span_lint.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![deny(clippy::disallowed_methods)] extern crate rustc_errors; extern crate rustc_hir; diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 9a7a7ecbbff9..f03a745963e0 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -1,15 +1,18 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> tests/ui-internal/disallow_span_lint.rs:14:8 + --> tests/ui-internal/disallow_span_lint.rs:15:8 | LL | cx.span_lint(lint, span, |lint| { | ^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` +note: the lint level is defined here + --> tests/ui-internal/disallow_span_lint.rs:2:9 + | +LL | #![deny(clippy::disallowed_methods)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:21:9 + --> tests/ui-internal/disallow_span_lint.rs:22:9 | LL | tcx.node_span_lint(lint, hir_id, span, |lint| { | ^^^^^^^^^^^^^^ diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed deleted file mode 100644 index 92d3b1537e0c..000000000000 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(clippy::internal)] -#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] -#![feature(rustc_private)] - -extern crate rustc_span; - -use rustc_span::symbol::Symbol; - -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} - -fn main() { - // Direct use of Symbol::intern - let _ = rustc_span::sym::f32; - //~^ interning_defined_symbol - - // Using a sym macro - let _ = rustc_span::sym::f32; - //~^ interning_defined_symbol - - // Correct suggestion when symbol isn't stringified constant name - let _ = rustc_span::sym::proc_dash_macro; - //~^ interning_defined_symbol - - // interning a keyword - let _ = rustc_span::kw::SelfLower; - //~^ interning_defined_symbol - - // Interning a symbol that is not defined - let _ = Symbol::intern("xyz123"); - let _ = sym!(xyz123); - - // Using a different `intern` function - let _ = intern("f32"); -} - -fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs deleted file mode 100644 index d1e6f9cb1c41..000000000000 --- a/tests/ui-internal/interning_defined_symbol.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(clippy::internal)] -#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] -#![feature(rustc_private)] - -extern crate rustc_span; - -use rustc_span::symbol::Symbol; - -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} - -fn main() { - // Direct use of Symbol::intern - let _ = Symbol::intern("f32"); - //~^ interning_defined_symbol - - // Using a sym macro - let _ = sym!(f32); - //~^ interning_defined_symbol - - // Correct suggestion when symbol isn't stringified constant name - let _ = Symbol::intern("proc-macro"); - //~^ interning_defined_symbol - - // interning a keyword - let _ = Symbol::intern("self"); - //~^ interning_defined_symbol - - // Interning a symbol that is not defined - let _ = Symbol::intern("xyz123"); - let _ = sym!(xyz123); - - // Using a different `intern` function - let _ = intern("f32"); -} - -fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.stderr b/tests/ui-internal/interning_defined_symbol.stderr deleted file mode 100644 index c84a566436a8..000000000000 --- a/tests/ui-internal/interning_defined_symbol.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:17:13 - | -LL | let _ = Symbol::intern("f32"); - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32` - | -note: the lint level is defined here - --> tests/ui-internal/interning_defined_symbol.rs:1:9 - | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]` - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:21:13 - | -LL | let _ = sym!(f32); - | ^^^^^^^^^ help: try: `rustc_span::sym::f32` - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:25:13 - | -LL | let _ = Symbol::intern("proc-macro"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro` - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:29:13 - | -LL | let _ = Symbol::intern("self"); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::kw::SelfLower` - -error: aborting due to 4 previous errors - diff --git a/tests/ui-internal/interning_literals.fixed b/tests/ui-internal/interning_literals.fixed new file mode 100644 index 000000000000..03e97768b996 --- /dev/null +++ b/tests/ui-internal/interning_literals.fixed @@ -0,0 +1,31 @@ +#![allow(clippy::let_unit_value)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn main() { + let _ = sym::f32; + //~^ interning_literals + + // Correct suggestion when symbol isn't stringified constant name + let _ = sym::proc_dash_macro; + //~^ interning_literals + + // Interning a keyword + let _ = kw::SelfLower; + //~^ interning_literals + + // Defined in clippy_utils + let _ = sym::msrv; + //~^ interning_literals + let _ = sym::Cargo_toml; + //~^ interning_literals + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_literals.rs b/tests/ui-internal/interning_literals.rs new file mode 100644 index 000000000000..561fd5702a59 --- /dev/null +++ b/tests/ui-internal/interning_literals.rs @@ -0,0 +1,31 @@ +#![allow(clippy::let_unit_value)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn main() { + let _ = Symbol::intern("f32"); + //~^ interning_literals + + // Correct suggestion when symbol isn't stringified constant name + let _ = Symbol::intern("proc-macro"); + //~^ interning_literals + + // Interning a keyword + let _ = Symbol::intern("self"); + //~^ interning_literals + + // Defined in clippy_utils + let _ = Symbol::intern("msrv"); + //~^ interning_literals + let _ = Symbol::intern("Cargo.toml"); + //~^ interning_literals + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_literals.stderr b/tests/ui-internal/interning_literals.stderr new file mode 100644 index 000000000000..628b97eff84d --- /dev/null +++ b/tests/ui-internal/interning_literals.stderr @@ -0,0 +1,64 @@ +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:10:13 + | +LL | let _ = Symbol::intern("f32"); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::interning-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("f32"); +LL + let _ = sym::f32; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:14:13 + | +LL | let _ = Symbol::intern("proc-macro"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("proc-macro"); +LL + let _ = sym::proc_dash_macro; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:18:13 + | +LL | let _ = Symbol::intern("self"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("self"); +LL + let _ = kw::SelfLower; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:22:13 + | +LL | let _ = Symbol::intern("msrv"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("msrv"); +LL + let _ = sym::msrv; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:24:13 + | +LL | let _ = Symbol::intern("Cargo.toml"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("Cargo.toml"); +LL + let _ = sym::Cargo_toml; + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui-internal/interning_literals_unfixable.rs b/tests/ui-internal/interning_literals_unfixable.rs new file mode 100644 index 000000000000..43872e95a585 --- /dev/null +++ b/tests/ui-internal/interning_literals_unfixable.rs @@ -0,0 +1,16 @@ +//@no-rustfix: paths that don't exist yet +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::Symbol; + +fn main() { + // Not yet defined + let _ = Symbol::intern("xyz123"); + //~^ interning_literals + let _ = Symbol::intern("with-dash"); + //~^ interning_literals + let _ = Symbol::intern("with.dot"); + //~^ interning_literals +} diff --git a/tests/ui-internal/interning_literals_unfixable.stderr b/tests/ui-internal/interning_literals_unfixable.stderr new file mode 100644 index 000000000000..8294453a8f94 --- /dev/null +++ b/tests/ui-internal/interning_literals_unfixable.stderr @@ -0,0 +1,40 @@ +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:10:13 + | +LL | let _ = Symbol::intern("xyz123"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::interning-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("xyz123"); +LL + let _ = sym::xyz123; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:12:13 + | +LL | let _ = Symbol::intern("with-dash"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("with-dash"); +LL + let _ = sym::with_dash; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:14:13 + | +LL | let _ = Symbol::intern("with.dot"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("with.dot"); +LL + let _ = sym::with_dot; + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 6804e2bbae83..238ef9ae6d0a 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::missing_msrv_attr_impl)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index c625a5d9a459..7753dcaad713 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::missing_msrv_attr_impl)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.stderr b/tests/ui-internal/invalid_msrv_attr_impl.stderr index 0a7636313eff..d5928d8c0c2d 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.stderr +++ b/tests/ui-internal/invalid_msrv_attr_impl.stderr @@ -7,9 +7,8 @@ LL | impl EarlyLintPass for Pass { note: the lint level is defined here --> tests/ui-internal/invalid_msrv_attr_impl.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::missing_msrv_attr_impl)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::missing_msrv_attr_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `extract_msrv_attr!()` to the `EarlyLintPass` implementation | LL ~ impl EarlyLintPass for Pass { diff --git a/tests/ui-internal/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs index abfb111f938e..7317abc2185a 100644 --- a/tests/ui-internal/invalid_paths.rs +++ b/tests/ui-internal/invalid_paths.rs @@ -1,4 +1,4 @@ -#![warn(clippy::internal)] +#![deny(clippy::invalid_paths)] #![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)] mod paths { diff --git a/tests/ui-internal/invalid_paths.stderr b/tests/ui-internal/invalid_paths.stderr index 7bde37667be4..7b7b25ce8d8d 100644 --- a/tests/ui-internal/invalid_paths.stderr +++ b/tests/ui-internal/invalid_paths.stderr @@ -4,8 +4,11 @@ error: invalid path LL | pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::invalid-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::invalid_paths)]` +note: the lint level is defined here + --> tests/ui-internal/invalid_paths.rs:1:9 + | +LL | #![deny(clippy::invalid_paths)] + | ^^^^^^^^^^^^^^^^^^^^^ error: invalid path --> tests/ui-internal/invalid_paths.rs:19:5 diff --git a/tests/ui-internal/lint_without_lint_pass.rs b/tests/ui-internal/lint_without_lint_pass.rs index 69591523432c..6b649132aca3 100644 --- a/tests/ui-internal/lint_without_lint_pass.rs +++ b/tests/ui-internal/lint_without_lint_pass.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::lint_without_lint_pass)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/lint_without_lint_pass.stderr b/tests/ui-internal/lint_without_lint_pass.stderr index 9cca96ca1602..3798293f4c11 100644 --- a/tests/ui-internal/lint_without_lint_pass.stderr +++ b/tests/ui-internal/lint_without_lint_pass.stderr @@ -13,9 +13,8 @@ LL | | } note: the lint level is defined here --> tests/ui-internal/lint_without_lint_pass.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::lint_without_lint_pass)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::lint_without_lint_pass)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-internal/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed index cb7680b8bb14..900ca5b2ab9d 100644 --- a/tests/ui-internal/outer_expn_data.fixed +++ b/tests/ui-internal/outer_expn_data.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::outer_expn_expn_data)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs index 41d735110b5a..bcfc42aa2ac7 100644 --- a/tests/ui-internal/outer_expn_data.rs +++ b/tests/ui-internal/outer_expn_data.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::outer_expn_expn_data)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/outer_expn_data.stderr b/tests/ui-internal/outer_expn_data.stderr index 33ac91e4fb0d..b86138a5d45d 100644 --- a/tests/ui-internal/outer_expn_data.stderr +++ b/tests/ui-internal/outer_expn_data.stderr @@ -7,9 +7,8 @@ LL | let _ = expr.span.ctxt().outer_expn().expn_data(); note: the lint level is defined here --> tests/ui-internal/outer_expn_data.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::outer_expn_expn_data)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::outer_expn_expn_data)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui-internal/slow_symbol_comparisons.fixed b/tests/ui-internal/slow_symbol_comparisons.fixed deleted file mode 100644 index 2cbd646a0fd5..000000000000 --- a/tests/ui-internal/slow_symbol_comparisons.fixed +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(rustc_private)] -#![warn(clippy::slow_symbol_comparisons)] - -extern crate rustc_span; - -use clippy_utils::sym; -use rustc_span::Symbol; - -fn main() { - let symbol = sym!(example); - let other_symbol = sym!(other_example); - - // Should lint - let slow_comparison = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_macro = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_backwards = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - - // Should not lint - let faster_comparison = symbol.as_str() == "other_example"; - let preinterned_comparison = symbol == other_symbol; -} diff --git a/tests/ui-internal/slow_symbol_comparisons.rs b/tests/ui-internal/slow_symbol_comparisons.rs deleted file mode 100644 index 0cea3c3fcff9..000000000000 --- a/tests/ui-internal/slow_symbol_comparisons.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(rustc_private)] -#![warn(clippy::slow_symbol_comparisons)] - -extern crate rustc_span; - -use clippy_utils::sym; -use rustc_span::Symbol; - -fn main() { - let symbol = sym!(example); - let other_symbol = sym!(other_example); - - // Should lint - let slow_comparison = symbol == Symbol::intern("example"); - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_macro = symbol == sym!(example); - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_backwards = sym!(example) == symbol; - //~^ error: comparing `Symbol` via `Symbol::intern` - - // Should not lint - let faster_comparison = symbol.as_str() == "other_example"; - let preinterned_comparison = symbol == other_symbol; -} diff --git a/tests/ui-internal/slow_symbol_comparisons.stderr b/tests/ui-internal/slow_symbol_comparisons.stderr deleted file mode 100644 index 72cb20a7fed9..000000000000 --- a/tests/ui-internal/slow_symbol_comparisons.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:14:27 - | -LL | let slow_comparison = symbol == Symbol::intern("example"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - | - = note: `-D clippy::slow-symbol-comparisons` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::slow_symbol_comparisons)]` - -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:16:33 - | -LL | let slow_comparison_macro = symbol == sym!(example); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:18:37 - | -LL | let slow_comparison_backwards = sym!(example) == symbol; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - -error: aborting due to 3 previous errors - diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index 577fad9341b6..89902ebe4e54 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -1,5 +1,5 @@ //@aux-build:paths.rs -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_def_path)] #![feature(rustc_private)] #![allow(clippy::unnecessary_map_or)] diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index d4deb3626d0b..cfca15267c19 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,5 +1,5 @@ //@aux-build:paths.rs -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_def_path)] #![feature(rustc_private)] #![allow(clippy::unnecessary_map_or)] diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr index 0053ba321bbe..d7fb4ea551e1 100644 --- a/tests/ui-internal/unnecessary_def_path.stderr +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -7,9 +7,8 @@ LL | let _ = match_type(cx, ty, &OPTION); note: the lint level is defined here --> tests/ui-internal/unnecessary_def_path.rs:2:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::unnecessary_def_path)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a def path to a diagnostic item --> tests/ui-internal/unnecessary_def_path.rs:39:13 diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs index 4801d76bd268..bd7a55114acb 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] #![allow(unused)] -#![warn(clippy::unnecessary_def_path)] +#![deny(clippy::unnecessary_def_path)] extern crate rustc_hir; diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index b93839519323..88fdf6f1c188 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -5,8 +5,11 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: convert all references to use `sym::Deref` - = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]` +note: the lint level is defined here + --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:3:9 + | +LL | #![deny(clippy::unnecessary_def_path)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: hardcoded path to a language item --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:40 diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed deleted file mode 100644 index dc564daef829..000000000000 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(rustc_private)] -#![deny(clippy::internal)] -#![allow( - clippy::slow_symbol_comparisons, - clippy::borrow_deref_ref, - clippy::unnecessary_operation, - unused_must_use, - clippy::missing_clippy_version_attribute -)] - -extern crate rustc_span; - -use rustc_span::symbol::{Ident, Symbol}; - -fn main() { - Symbol::intern("foo") == rustc_span::sym::clippy; - //~^ unnecessary_symbol_str - Symbol::intern("foo") == rustc_span::kw::SelfLower; - //~^ unnecessary_symbol_str - Symbol::intern("foo") != rustc_span::kw::SelfUpper; - //~^ unnecessary_symbol_str - Ident::empty().name == rustc_span::sym::clippy; - //~^ unnecessary_symbol_str - rustc_span::sym::clippy == Ident::empty().name; - //~^ unnecessary_symbol_str -} diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs deleted file mode 100644 index d74262d1294b..000000000000 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(rustc_private)] -#![deny(clippy::internal)] -#![allow( - clippy::slow_symbol_comparisons, - clippy::borrow_deref_ref, - clippy::unnecessary_operation, - unused_must_use, - clippy::missing_clippy_version_attribute -)] - -extern crate rustc_span; - -use rustc_span::symbol::{Ident, Symbol}; - -fn main() { - Symbol::intern("foo").as_str() == "clippy"; - //~^ unnecessary_symbol_str - Symbol::intern("foo").to_string() == "self"; - //~^ unnecessary_symbol_str - Symbol::intern("foo").to_ident_string() != "Self"; - //~^ unnecessary_symbol_str - &*Ident::empty().as_str() == "clippy"; - //~^ unnecessary_symbol_str - "clippy" == Ident::empty().to_string(); - //~^ unnecessary_symbol_str -} diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr deleted file mode 100644 index 517a395e93f2..000000000000 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:16:5 - | -LL | Symbol::intern("foo").as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy` - | -note: the lint level is defined here - --> tests/ui-internal/unnecessary_symbol_str.rs:2:9 - | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 - | -LL | Symbol::intern("foo").to_string() == "self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::kw::SelfLower` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:20:5 - | -LL | Symbol::intern("foo").to_ident_string() != "Self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::kw::SelfUpper` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:22:5 - | -LL | &*Ident::empty().as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:24:5 - | -LL | "clippy" == Ident::empty().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` - -error: aborting due to 5 previous errors - diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs b/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs index b43791521cb5..694ef45c75b0 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs @@ -16,6 +16,7 @@ //@[bad_conf_4] error-in-other-file: //@[bad_conf_5] error-in-other-file: //@[bad_conf_6] error-in-other-file: +//@compile-flags: --test #![allow(dead_code)] #![warn(clippy::arbitrary_source_item_ordering)] diff --git a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr index 7fc216b30d50..fcd7864c6677 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr @@ -1,16 +1,16 @@ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5 | LL | a: bool, | ^ | note: should be placed before `b` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 | LL | b: bool, | ^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8 | LL | #[deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr index 1f75f5099ecc..81c35ff778b7 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr @@ -1,33 +1,33 @@ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8 | LL | struct OrderedChecked { | ^^^^^^^^^^^^^^ | note: should be placed before `Unordered` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8 | LL | struct Unordered { | ^^^^^^^^^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9 | LL | #![deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5 | LL | a: bool, | ^ | note: should be placed before `b` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 | LL | b: bool, | ^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8 | LL | #[deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr index 8027f55add67..09ede57f295e 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr @@ -1,16 +1,16 @@ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8 | LL | struct OrderedChecked { | ^^^^^^^^^^^^^^ | note: should be placed before `Unordered` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8 | LL | struct Unordered { | ^^^^^^^^^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9 | LL | #![deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr index 333a601f6a95..7c515f050c12 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr @@ -1,48 +1,60 @@ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8 | LL | struct OrderedChecked { | ^^^^^^^^^^^^^^ | note: should be placed before `Unordered` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8 | LL | struct Unordered { | ^^^^^^^^^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9 | LL | #![deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:45:4 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:46:4 | LL | fn before_main() {} | ^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:41:4 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:42:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5 | LL | a: bool, | ^ | note: should be placed before `b` - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5 | LL | b: bool, | ^ note: the lint level is defined here - --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8 + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8 | LL | #[deny(clippy::arbitrary_source_item_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:52:11 + | +LL | const A: i8 = 0; + | ^ + | +note: should be placed before `B` + --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:51:11 + | +LL | const B: i8 = 1; + | ^ + +error: aborting due to 4 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs index e32b921dd965..cb6d0170b8f9 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs +++ b/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs @@ -4,6 +4,7 @@ //@[ord_within] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_within //@[ord_in_2] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_in_2 //@[ord_in_3] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_in_3 +//@compile-flags: --test #![allow(dead_code)] #![deny(clippy::arbitrary_source_item_ordering)] @@ -44,3 +45,10 @@ fn main() { fn before_main() {} //~[ord_within]^ arbitrary_source_item_ordering + +#[cfg(test)] +mod test { + const B: i8 = 1; + const A: i8 = 0; + //~[ord_within]^ arbitrary_source_item_ordering +} diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr index 86e30409af06..d0fce3614a14 100644 --- a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr +++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr @@ -1,11 +1,8 @@ error: error reading Clippy's configuration file: replacement not allowed for this configuration - --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:1:31 + --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:2:5 | -LL | await-holding-invalid-types = [ - | _______________________________^ -LL | | { path = "std::string::String", replacement = "std::net::Ipv4Addr" }, -LL | | ] - | |_^ +LL | { path = "std::string::String", replacement = "std::net::Ipv4Addr" }, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui-toml/collapsible_if/clippy.toml b/tests/ui-toml/collapsible_if/clippy.toml new file mode 100644 index 000000000000..592cea90cff5 --- /dev/null +++ b/tests/ui-toml/collapsible_if/clippy.toml @@ -0,0 +1 @@ +lint-commented-code = true diff --git a/tests/ui-toml/collapsible_if/collapsible_if.fixed b/tests/ui-toml/collapsible_if/collapsible_if.fixed new file mode 100644 index 000000000000..6f5cc47ba6c7 --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if.fixed @@ -0,0 +1,34 @@ +#![allow(clippy::eq_op, clippy::nonminimal_bool)] + +#[rustfmt::skip] +#[warn(clippy::collapsible_if)] +fn main() { + let (x, y) = ("hello", "world"); + + if x == "hello" + // Comment must be kept + && y == "world" { + println!("Hello world!"); + } + //~^^^^^^ collapsible_if + + // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798 + if x == "hello" // Inner comment + && y == "world" { + println!("Hello world!"); + } + //~^^^^^ collapsible_if + + if x == "hello" + /* Inner comment */ + && y == "world" { + println!("Hello world!"); + } + //~^^^^^^ collapsible_if + + if x == "hello" /* Inner comment */ + && y == "world" { + println!("Hello world!"); + } + //~^^^^^ collapsible_if +} diff --git a/tests/ui-toml/collapsible_if/collapsible_if.rs b/tests/ui-toml/collapsible_if/collapsible_if.rs new file mode 100644 index 000000000000..868b4adcde50 --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if.rs @@ -0,0 +1,38 @@ +#![allow(clippy::eq_op, clippy::nonminimal_bool)] + +#[rustfmt::skip] +#[warn(clippy::collapsible_if)] +fn main() { + let (x, y) = ("hello", "world"); + + if x == "hello" { + // Comment must be kept + if y == "world" { + println!("Hello world!"); + } + } + //~^^^^^^ collapsible_if + + // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798 + if x == "hello" { // Inner comment + if y == "world" { + println!("Hello world!"); + } + } + //~^^^^^ collapsible_if + + if x == "hello" { + /* Inner comment */ + if y == "world" { + println!("Hello world!"); + } + } + //~^^^^^^ collapsible_if + + if x == "hello" { /* Inner comment */ + if y == "world" { + println!("Hello world!"); + } + } + //~^^^^^ collapsible_if +} diff --git a/tests/ui-toml/collapsible_if/collapsible_if.stderr b/tests/ui-toml/collapsible_if/collapsible_if.stderr new file mode 100644 index 000000000000..357ce4ad32de --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if.stderr @@ -0,0 +1,80 @@ +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if.rs:8:5 + | +LL | / if x == "hello" { +LL | | // Comment must be kept +LL | | if y == "world" { +LL | | println!("Hello world!"); +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::collapsible-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` +help: collapse nested if block + | +LL ~ if x == "hello" +LL | // Comment must be kept +LL ~ && y == "world" { +LL | println!("Hello world!"); +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if.rs:17:5 + | +LL | / if x == "hello" { // Inner comment +LL | | if y == "world" { +LL | | println!("Hello world!"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if x == "hello" // Inner comment +LL ~ && y == "world" { +LL | println!("Hello world!"); +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if.rs:24:5 + | +LL | / if x == "hello" { +LL | | /* Inner comment */ +LL | | if y == "world" { +LL | | println!("Hello world!"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if x == "hello" +LL | /* Inner comment */ +LL ~ && y == "world" { +LL | println!("Hello world!"); +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if.rs:32:5 + | +LL | / if x == "hello" { /* Inner comment */ +LL | | if y == "world" { +LL | | println!("Hello world!"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if x == "hello" /* Inner comment */ +LL ~ && y == "world" { +LL | println!("Hello world!"); +LL ~ } + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed new file mode 100644 index 000000000000..f12273954c6d --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed @@ -0,0 +1,25 @@ +#![feature(let_chains)] +#![warn(clippy::collapsible_if)] + +fn main() { + if let Some(a) = Some(3) + // with comment + && let Some(b) = Some(4) { + let _ = a + b; + } + //~^^^^^^ collapsible_if + + if let Some(a) = Some(3) + // with comment + && a + 1 == 4 { + let _ = a; + } + //~^^^^^^ collapsible_if + + if Some(3) == Some(4).map(|x| x - 1) + // with comment + && let Some(b) = Some(4) { + let _ = b; + } + //~^^^^^^ collapsible_if +} diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs new file mode 100644 index 000000000000..5a984d7a3cbe --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs @@ -0,0 +1,28 @@ +#![feature(let_chains)] +#![warn(clippy::collapsible_if)] + +fn main() { + if let Some(a) = Some(3) { + // with comment + if let Some(b) = Some(4) { + let _ = a + b; + } + } + //~^^^^^^ collapsible_if + + if let Some(a) = Some(3) { + // with comment + if a + 1 == 4 { + let _ = a; + } + } + //~^^^^^^ collapsible_if + + if Some(3) == Some(4).map(|x| x - 1) { + // with comment + if let Some(b) = Some(4) { + let _ = b; + } + } + //~^^^^^^ collapsible_if +} diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr new file mode 100644 index 000000000000..c22a65a44730 --- /dev/null +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr @@ -0,0 +1,64 @@ +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:5:5 + | +LL | / if let Some(a) = Some(3) { +LL | | // with comment +LL | | if let Some(b) = Some(4) { +LL | | let _ = a + b; +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::collapsible-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL | // with comment +LL ~ && let Some(b) = Some(4) { +LL | let _ = a + b; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:13:5 + | +LL | / if let Some(a) = Some(3) { +LL | | // with comment +LL | | if a + 1 == 4 { +LL | | let _ = a; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL | // with comment +LL ~ && a + 1 == 4 { +LL | let _ = a; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:21:5 + | +LL | / if Some(3) == Some(4).map(|x| x - 1) { +LL | | // with comment +LL | | if let Some(b) = Some(4) { +LL | | let _ = b; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if Some(3) == Some(4).map(|x| x - 1) +LL | // with comment +LL ~ && let Some(b) = Some(4) { +LL | let _ = b; +LL ~ } + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs index 2465fe45645f..d3d5b0c103e7 100644 --- a/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs +++ b/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -251,6 +251,16 @@ pub mod issue13219 { } } +#[macro_export] +macro_rules! issue14488 { + ($e:expr) => { + #[expect(clippy::macro_metavars_in_unsafe)] + unsafe { + $e + } + }; +} + fn main() { allow_works!(1); simple!(1); @@ -271,4 +281,10 @@ fn main() { multiple_unsafe_blocks!(1, 1, 1); unsafe_from_root_ctxt!(unsafe { 1 }); nested_macros!(1, 1); + + // These two invocations lead to two expanded unsafe blocks, each with an `#[expect]` on it. + // Only of them gets a warning, which used to result in an unfulfilled expectation for the other + // expanded unsafe block. + issue14488!(1); + issue14488!(2); } diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed index 36540bf1dcf7..2877871d0bf4 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed @@ -1,3 +1,4 @@ +#![allow(clippy::uninlined_format_args)] #![deny(clippy::index_refutable_slice)] fn below_limit() { diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs index da76bb20fd96..f958b92a102a 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs @@ -1,3 +1,4 @@ +#![allow(clippy::uninlined_format_args)] #![deny(clippy::index_refutable_slice)] fn below_limit() { diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr index 022deb330e6e..e1a8941e102f 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr @@ -1,11 +1,11 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:5:17 + --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:6:17 | LL | if let Some(slice) = slice { | ^^^^^ | note: the lint level is defined here - --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:1:9 + --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:2:9 | LL | #![deny(clippy::index_refutable_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs index 08a8e1186d5c..13e19e9fe14b 100644 --- a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs +++ b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs @@ -29,7 +29,7 @@ unsafe impl Send for MyOption {} //~^ non_send_fields_in_send_ty // All fields are disallowed when raw pointer heuristic is off -extern "C" { +unsafe extern "C" { type NonSend; } diff --git a/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml b/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml index f43c9d97e825..3cb8523562a8 100644 --- a/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml +++ b/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml @@ -1 +1 @@ -lint-inconsistent-struct-field-initializers = true +check-inconsistent-struct-field-initializers = true diff --git a/tests/ui-toml/toml_invalid_path/clippy.toml b/tests/ui-toml/toml_invalid_path/clippy.toml new file mode 100644 index 000000000000..6d0d732a9223 --- /dev/null +++ b/tests/ui-toml/toml_invalid_path/clippy.toml @@ -0,0 +1,14 @@ +[[disallowed-types]] +path = "std::result::Result::Err" + +[[disallowed-macros]] +path = "bool" + +[[disallowed-methods]] +path = "std::process::current_exe" + +# negative test + +[[disallowed-methods]] +path = "std::current_exe" +allow-invalid = true diff --git a/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs b/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs new file mode 100644 index 000000000000..c15203827034 --- /dev/null +++ b/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs @@ -0,0 +1,5 @@ +//@error-in-other-file: expected a macro, found a primitive type +//@error-in-other-file: `std::process::current_exe` does not refer to an existing function +//@error-in-other-file: expected a type, found a tuple variant + +fn main() {} diff --git a/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr b/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr new file mode 100644 index 000000000000..82550108eba5 --- /dev/null +++ b/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr @@ -0,0 +1,23 @@ +warning: expected a macro, found a primitive type + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1 + | +LL | / [[disallowed-macros]] +LL | | path = "bool" + | |_____________^ + +warning: `std::process::current_exe` does not refer to an existing function + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1 + | +LL | / [[disallowed-methods]] +LL | | path = "std::process::current_exe" + | |__________________________________^ + +warning: expected a type, found a tuple variant + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1 + | +LL | / [[disallowed-types]] +LL | | path = "std::result::Result::Err" + | |_________________________________^ + +warning: 3 warnings emitted + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index fee5b01b6898..f2eaa66a4ae4 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -29,12 +29,11 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect array-size-threshold avoid-breaking-exported-api await-holding-invalid-types - blacklisted-names cargo-ignore-publish check-incompatible-msrv-in-tests + check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold - cyclomatic-complexity-threshold disallowed-macros disallowed-methods disallowed-names @@ -49,7 +48,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect future-size-threshold ignore-interior-mutability large-error-threshold - lint-inconsistent-struct-field-initializers + lint-commented-code literal-representation-threshold matches-for-let-else max-fn-params-bools @@ -122,12 +121,11 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect array-size-threshold avoid-breaking-exported-api await-holding-invalid-types - blacklisted-names cargo-ignore-publish check-incompatible-msrv-in-tests + check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold - cyclomatic-complexity-threshold disallowed-macros disallowed-methods disallowed-names @@ -142,7 +140,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect future-size-threshold ignore-interior-mutability large-error-threshold - lint-inconsistent-struct-field-initializers + lint-commented-code literal-representation-threshold matches-for-let-else max-fn-params-bools @@ -215,12 +213,11 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni array-size-threshold avoid-breaking-exported-api await-holding-invalid-types - blacklisted-names cargo-ignore-publish check-incompatible-msrv-in-tests + check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold - cyclomatic-complexity-threshold disallowed-macros disallowed-methods disallowed-names @@ -235,7 +232,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni future-size-threshold ignore-interior-mutability large-error-threshold - lint-inconsistent-struct-field-initializers + lint-commented-code literal-representation-threshold matches-for-let-else max-fn-params-bools diff --git a/tests/ui-toml/wildcard_imports/wildcard_imports.fixed b/tests/ui-toml/wildcard_imports/wildcard_imports.fixed index af72d6be0e09..20511cbed165 100644 --- a/tests/ui-toml/wildcard_imports/wildcard_imports.fixed +++ b/tests/ui-toml/wildcard_imports/wildcard_imports.fixed @@ -15,7 +15,7 @@ mod my_crate { } } -use utils::{BAR, print}; +pub use utils::{BAR, print}; //~^ ERROR: usage of wildcard import use my_crate::utils::my_util_fn; //~^ ERROR: usage of wildcard import diff --git a/tests/ui-toml/wildcard_imports/wildcard_imports.rs b/tests/ui-toml/wildcard_imports/wildcard_imports.rs index 91009dd8835f..8d05910f471b 100644 --- a/tests/ui-toml/wildcard_imports/wildcard_imports.rs +++ b/tests/ui-toml/wildcard_imports/wildcard_imports.rs @@ -15,7 +15,7 @@ mod my_crate { } } -use utils::*; +pub use utils::*; //~^ ERROR: usage of wildcard import use my_crate::utils::*; //~^ ERROR: usage of wildcard import diff --git a/tests/ui-toml/wildcard_imports/wildcard_imports.stderr b/tests/ui-toml/wildcard_imports/wildcard_imports.stderr index 3d3be965aa41..5e624dd6c3cd 100644 --- a/tests/ui-toml/wildcard_imports/wildcard_imports.stderr +++ b/tests/ui-toml/wildcard_imports/wildcard_imports.stderr @@ -1,8 +1,8 @@ error: usage of wildcard import - --> tests/ui-toml/wildcard_imports/wildcard_imports.rs:18:5 + --> tests/ui-toml/wildcard_imports/wildcard_imports.rs:18:9 | -LL | use utils::*; - | ^^^^^^^^ help: try: `utils::{BAR, print}` +LL | pub use utils::*; + | ^^^^^^^^ help: try: `utils::{BAR, print}` | = note: `-D clippy::wildcard-imports` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` diff --git a/tests/ui/asm_syntax_not_x86.rs b/tests/ui/asm_syntax_not_x86.rs index edcd5247f18c..361bc2033934 100644 --- a/tests/ui/asm_syntax_not_x86.rs +++ b/tests/ui/asm_syntax_not_x86.rs @@ -8,9 +8,11 @@ mod dont_warn { use std::arch::{asm, global_asm}; pub(super) unsafe fn use_asm() { - asm!(""); - asm!("", options()); - asm!("", options(nostack)); + unsafe { + asm!(""); + asm!("", options()); + asm!("", options(nostack)); + } } global_asm!(""); diff --git a/tests/ui/asm_syntax_x86.rs b/tests/ui/asm_syntax_x86.rs index 4e91f27cd318..30401c9a0448 100644 --- a/tests/ui/asm_syntax_x86.rs +++ b/tests/ui/asm_syntax_x86.rs @@ -5,17 +5,19 @@ mod warn_intel { use std::arch::{asm, global_asm}; pub(super) unsafe fn use_asm() { - asm!(""); - //~^ inline_asm_x86_intel_syntax + unsafe { + asm!(""); + //~^ inline_asm_x86_intel_syntax - asm!("", options()); - //~^ inline_asm_x86_intel_syntax + asm!("", options()); + //~^ inline_asm_x86_intel_syntax - asm!("", options(nostack)); - //~^ inline_asm_x86_intel_syntax + asm!("", options(nostack)); + //~^ inline_asm_x86_intel_syntax - asm!("", options(att_syntax)); - asm!("", options(nostack, att_syntax)); + asm!("", options(att_syntax)); + asm!("", options(nostack, att_syntax)); + } } global_asm!(""); @@ -32,14 +34,16 @@ mod warn_att { use std::arch::{asm, global_asm}; pub(super) unsafe fn use_asm() { - asm!(""); - asm!("", options()); - asm!("", options(nostack)); - asm!("", options(att_syntax)); - //~^ inline_asm_x86_att_syntax + unsafe { + asm!(""); + asm!("", options()); + asm!("", options(nostack)); + asm!("", options(att_syntax)); + //~^ inline_asm_x86_att_syntax - asm!("", options(nostack, att_syntax)); - //~^ inline_asm_x86_att_syntax + asm!("", options(nostack, att_syntax)); + //~^ inline_asm_x86_att_syntax + } } global_asm!(""); diff --git a/tests/ui/asm_syntax_x86.stderr b/tests/ui/asm_syntax_x86.stderr index 2dcd955f0347..8e068cf2349c 100644 --- a/tests/ui/asm_syntax_x86.stderr +++ b/tests/ui/asm_syntax_x86.stderr @@ -1,31 +1,31 @@ error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:8:9 + --> tests/ui/asm_syntax_x86.rs:9:13 | -LL | asm!(""); - | ^^^^^^^^ +LL | asm!(""); + | ^^^^^^^^ | = help: use AT&T x86 assembly syntax = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:11:9 + --> tests/ui/asm_syntax_x86.rs:12:13 | -LL | asm!("", options()); - | ^^^^^^^^^^^^^^^^^^^ +LL | asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:14:9 + --> tests/ui/asm_syntax_x86.rs:15:13 | -LL | asm!("", options(nostack)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | asm!("", options(nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:21:5 + --> tests/ui/asm_syntax_x86.rs:23:5 | LL | global_asm!(""); | ^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | global_asm!(""); = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:24:5 + --> tests/ui/asm_syntax_x86.rs:26:5 | LL | global_asm!("", options()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,25 +41,25 @@ LL | global_asm!("", options()); = help: use AT&T x86 assembly syntax error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:38:9 + --> tests/ui/asm_syntax_x86.rs:41:13 | -LL | asm!("", options(att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use Intel x86 assembly syntax = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:41:9 + --> tests/ui/asm_syntax_x86.rs:44:13 | -LL | asm!("", options(nostack, att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | asm!("", options(nostack, att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use Intel x86 assembly syntax error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:47:5 + --> tests/ui/asm_syntax_x86.rs:51:5 | LL | global_asm!("", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/author/if.rs b/tests/ui/author/if.rs index 59bc9f5bfa5c..abefc34cf6b3 100644 --- a/tests/ui/author/if.rs +++ b/tests/ui/author/if.rs @@ -1,6 +1,6 @@ //@ check-pass -#[allow(clippy::all)] +#![allow(clippy::all)] fn main() { #[clippy::author] diff --git a/tests/ui/author/macro_in_closure.rs b/tests/ui/author/macro_in_closure.rs index 8a02f38fad87..373f0148d475 100644 --- a/tests/ui/author/macro_in_closure.rs +++ b/tests/ui/author/macro_in_closure.rs @@ -1,5 +1,7 @@ //@ check-pass +#![allow(clippy::uninlined_format_args)] + fn main() { #[clippy::author] let print_text = |x| println!("{}", x); diff --git a/tests/ui/author/macro_in_loop.rs b/tests/ui/author/macro_in_loop.rs index 84ffe416e839..f68275fefaaa 100644 --- a/tests/ui/author/macro_in_loop.rs +++ b/tests/ui/author/macro_in_loop.rs @@ -1,6 +1,7 @@ //@ check-pass #![feature(stmt_expr_attributes)] +#![allow(clippy::uninlined_format_args)] fn main() { #[clippy::author] diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 1a2a4ec23114..7a4cc4fa9ee8 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -131,12 +131,12 @@ fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Resul pub fn make_it_big(input: TokenStream) -> TokenStream { let mut expr_repeat = syn::parse_macro_input!(input as syn::ExprRepeat); let len_span = expr_repeat.len.span(); - if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len { - if let syn::Lit::Int(lit_int) = &expr_lit.lit { - let orig_val = lit_int.base10_parse::().expect("not a valid length parameter"); - let new_val = orig_val.saturating_mul(10); - expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val); - } + if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len + && let syn::Lit::Int(lit_int) = &expr_lit.lit + { + let orig_val = lit_int.base10_parse::().expect("not a valid length parameter"); + let new_val = orig_val.saturating_mul(10); + expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val); } quote::quote!(#expr_repeat).into() } diff --git a/tests/ui/blocks_in_conditions.fixed b/tests/ui/blocks_in_conditions.fixed index cd307e803d0c..c82276b358e1 100644 --- a/tests/ui/blocks_in_conditions.fixed +++ b/tests/ui/blocks_in_conditions.fixed @@ -1,12 +1,7 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow( - unused, - clippy::let_and_return, - clippy::needless_if, - clippy::missing_transmute_annotations -)] +#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { @@ -71,28 +66,6 @@ fn block_in_assert() { ); } -// issue #11814 -fn block_in_match_expr(num: i32) -> i32 { - let res = { - //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - let opt = Some(2); - opt - }; match res { - Some(0) => 1, - Some(n) => num * 2, - None => 0, - }; - - match unsafe { - let hearty_hearty_hearty = vec![240, 159, 146, 150]; - String::from_utf8_unchecked(hearty_hearty_hearty).as_str() - } { - "💖" => 1, - "what" => 2, - _ => 3, - } -} - // issue #12162 macro_rules! timed { ($name:expr, $body:expr $(,)?) => {{ diff --git a/tests/ui/blocks_in_conditions.rs b/tests/ui/blocks_in_conditions.rs index 6a211c8edfd4..6a4a7c621068 100644 --- a/tests/ui/blocks_in_conditions.rs +++ b/tests/ui/blocks_in_conditions.rs @@ -1,12 +1,7 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow( - unused, - clippy::let_and_return, - clippy::needless_if, - clippy::missing_transmute_annotations -)] +#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { @@ -71,28 +66,6 @@ fn block_in_assert() { ); } -// issue #11814 -fn block_in_match_expr(num: i32) -> i32 { - match { - //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - let opt = Some(2); - opt - } { - Some(0) => 1, - Some(n) => num * 2, - None => 0, - }; - - match unsafe { - let hearty_hearty_hearty = vec![240, 159, 146, 150]; - String::from_utf8_unchecked(hearty_hearty_hearty).as_str() - } { - "💖" => 1, - "what" => 2, - _ => 3, - } -} - // issue #12162 macro_rules! timed { ($name:expr, $body:expr $(,)?) => {{ diff --git a/tests/ui/blocks_in_conditions.stderr b/tests/ui/blocks_in_conditions.stderr index da21344a8428..e57eca5dceef 100644 --- a/tests/ui/blocks_in_conditions.stderr +++ b/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:30:5 + --> tests/ui/blocks_in_conditions.rs:25:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:42:8 + --> tests/ui/blocks_in_conditions.rs:37:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:48:8 + --> tests/ui/blocks_in_conditions.rs:43:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` @@ -34,24 +34,5 @@ LL | if true && x == 3 { 6 } else { 10 } = note: `-D clippy::nonminimal-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` -error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:76:5 - | -LL | / match { -LL | | -LL | | let opt = Some(2); -LL | | opt -LL | | } { - | |_____^ - | -help: try - | -LL ~ let res = { -LL + -LL + let opt = Some(2); -LL + opt -LL ~ }; match res { - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/blocks_in_conditions_2021.fixed b/tests/ui/blocks_in_conditions_2021.fixed new file mode 100644 index 000000000000..c7cc643dba67 --- /dev/null +++ b/tests/ui/blocks_in_conditions_2021.fixed @@ -0,0 +1,25 @@ +//@edition: 2021 + +#![allow(clippy::let_and_return)] + +// issue #11814 +fn block_in_match_expr(num: i32) -> i32 { + let res = { + //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + let opt = Some(2); + opt + }; match res { + Some(0) => 1, + Some(n) => num * 2, + None => 0, + }; + + match unsafe { + let hearty_hearty_hearty = vec![240, 159, 146, 150]; + String::from_utf8_unchecked(hearty_hearty_hearty).as_str() + } { + "💖" => 1, + "what" => 2, + _ => 3, + } +} diff --git a/tests/ui/blocks_in_conditions_2021.rs b/tests/ui/blocks_in_conditions_2021.rs new file mode 100644 index 000000000000..a911237f5f79 --- /dev/null +++ b/tests/ui/blocks_in_conditions_2021.rs @@ -0,0 +1,25 @@ +//@edition: 2021 + +#![allow(clippy::let_and_return)] + +// issue #11814 +fn block_in_match_expr(num: i32) -> i32 { + match { + //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + let opt = Some(2); + opt + } { + Some(0) => 1, + Some(n) => num * 2, + None => 0, + }; + + match unsafe { + let hearty_hearty_hearty = vec![240, 159, 146, 150]; + String::from_utf8_unchecked(hearty_hearty_hearty).as_str() + } { + "💖" => 1, + "what" => 2, + _ => 3, + } +} diff --git a/tests/ui/blocks_in_conditions_2021.stderr b/tests/ui/blocks_in_conditions_2021.stderr new file mode 100644 index 000000000000..497ee9d679dd --- /dev/null +++ b/tests/ui/blocks_in_conditions_2021.stderr @@ -0,0 +1,23 @@ +error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + --> tests/ui/blocks_in_conditions_2021.rs:7:5 + | +LL | / match { +LL | | +LL | | let opt = Some(2); +LL | | opt +LL | | } { + | |_____^ + | + = note: `-D clippy::blocks-in-conditions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]` +help: try + | +LL ~ let res = { +LL + +LL + let opt = Some(2); +LL + opt +LL ~ }; match res { + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 0080801d46b7..ed6141244b40 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -117,3 +117,27 @@ fn if_let(a: Enum, b: Enum) { 0 }; } + +fn issue14628() { + macro_rules! mac { + (if $cond:expr, $then:expr, $else:expr) => { + if $cond { $then } else { $else } + }; + (zero) => { + 0 + }; + (one) => { + 1 + }; + } + + let _ = i32::from(dbg!(4 > 0)); + //~^ bool_to_int_with_if + + let _ = dbg!(i32::from(4 > 0)); + //~^ bool_to_int_with_if + + let _ = mac!(if 4 > 0, 1, 0); + let _ = if 4 > 0 { mac!(one) } else { 0 }; + let _ = if 4 > 0 { 1 } else { mac!(zero) }; +} diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index 72c7e2c71c56..3f1f1c766e46 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -157,3 +157,27 @@ fn if_let(a: Enum, b: Enum) { 0 }; } + +fn issue14628() { + macro_rules! mac { + (if $cond:expr, $then:expr, $else:expr) => { + if $cond { $then } else { $else } + }; + (zero) => { + 0 + }; + (one) => { + 1 + }; + } + + let _ = if dbg!(4 > 0) { 1 } else { 0 }; + //~^ bool_to_int_with_if + + let _ = dbg!(if 4 > 0 { 1 } else { 0 }); + //~^ bool_to_int_with_if + + let _ = mac!(if 4 > 0, 1, 0); + let _ = if 4 > 0 { mac!(one) } else { 0 }; + let _ = if 4 > 0 { 1 } else { mac!(zero) }; +} diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index 415e80f8d73d..94089bc6dc8e 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -114,5 +114,21 @@ LL | if a { 1 } else { 0 } | = note: `a as u8` or `a.into()` can also be valid options -error: aborting due to 9 previous errors +error: boolean to int conversion using if + --> tests/ui/bool_to_int_with_if.rs:174:13 + | +LL | let _ = if dbg!(4 > 0) { 1 } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))` + | + = note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options + +error: boolean to int conversion using if + --> tests/ui/bool_to_int_with_if.rs:177:18 + | +LL | let _ = dbg!(if 4 > 0 { 1 } else { 0 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)` + | + = note: `(4 > 0) as i32` or `(4 > 0).into()` can also be valid options + +error: aborting due to 11 previous errors diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index 3dca06fce4b8..3ba2eea59f0b 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -29,3 +29,21 @@ fn issue_13882() { let _raw = (&raw mut x[1]).wrapping_offset(-1); //~^ borrow_as_ptr } + +fn implicit_cast() { + let val = 1; + let p: *const i32 = &raw const val; + //~^ borrow_as_ptr + + let mut val = 1; + let p: *mut i32 = &raw mut val; + //~^ borrow_as_ptr + + let mut val = 1; + // Only lint the leftmost argument, the rightmost is ref to a temporary + core::ptr::eq(&raw const val, &1); + //~^ borrow_as_ptr + + // Do not lint references to temporaries + core::ptr::eq(&0i32, &1i32); +} diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index 3559dc23d018..8cdd0512da5f 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -29,3 +29,21 @@ fn issue_13882() { let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); //~^ borrow_as_ptr } + +fn implicit_cast() { + let val = 1; + let p: *const i32 = &val; + //~^ borrow_as_ptr + + let mut val = 1; + let p: *mut i32 = &mut val; + //~^ borrow_as_ptr + + let mut val = 1; + // Only lint the leftmost argument, the rightmost is ref to a temporary + core::ptr::eq(&val, &1); + //~^ borrow_as_ptr + + // Do not lint references to temporaries + core::ptr::eq(&0i32, &1i32); +} diff --git a/tests/ui/borrow_as_ptr.stderr b/tests/ui/borrow_as_ptr.stderr index 4a9f2ed4aa00..b1fcce49403c 100644 --- a/tests/ui/borrow_as_ptr.stderr +++ b/tests/ui/borrow_as_ptr.stderr @@ -25,5 +25,38 @@ error: borrow as raw pointer LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]` -error: aborting due to 4 previous errors +error: implicit borrow as raw pointer + --> tests/ui/borrow_as_ptr.rs:35:25 + | +LL | let p: *const i32 = &val; + | ^^^^ + | +help: use a raw pointer instead + | +LL | let p: *const i32 = &raw const val; + | +++++++++ + +error: implicit borrow as raw pointer + --> tests/ui/borrow_as_ptr.rs:39:23 + | +LL | let p: *mut i32 = &mut val; + | ^^^^^^^^ + | +help: use a raw pointer instead + | +LL | let p: *mut i32 = &raw mut val; + | +++ + +error: implicit borrow as raw pointer + --> tests/ui/borrow_as_ptr.rs:44:19 + | +LL | core::ptr::eq(&val, &1); + | ^^^^ + | +help: use a raw pointer instead + | +LL | core::ptr::eq(&raw const val, &1); + | +++++++++ + +error: aborting due to 7 previous errors diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed index 17c224f10bfe..765dd75fceb9 100644 --- a/tests/ui/borrow_deref_ref.fixed +++ b/tests/ui/borrow_deref_ref.fixed @@ -81,3 +81,46 @@ fn issue_13584() { let p = &raw const *s; let _ = p as *const i8; } + +mod issue_9905 { + use std::{fs, io}; + + pub enum File { + Stdio, + File(fs::File), + } + + impl io::Read for &'_ File { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + File::Stdio => io::stdin().read(buf), + File::File(file) => (&*file).read(buf), + } + } + } +} + +mod issue_11346 { + struct Struct; + + impl Struct { + fn foo(self: &mut &Self) {} + } + + trait Trait { + fn bar(&mut self) {} + } + + impl Trait for &Struct {} + + fn bar() { + let s = &Struct; + (&*s).foo(); + (&*s).bar(); + + let mut s = &Struct; + s.foo(); // To avoid a warning about `s` not needing to be mutable + s.foo(); + //~^ borrow_deref_ref + } +} diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs index 130ed2903dc6..8ee66bfa881a 100644 --- a/tests/ui/borrow_deref_ref.rs +++ b/tests/ui/borrow_deref_ref.rs @@ -81,3 +81,46 @@ fn issue_13584() { let p = &raw const *s; let _ = p as *const i8; } + +mod issue_9905 { + use std::{fs, io}; + + pub enum File { + Stdio, + File(fs::File), + } + + impl io::Read for &'_ File { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + File::Stdio => io::stdin().read(buf), + File::File(file) => (&*file).read(buf), + } + } + } +} + +mod issue_11346 { + struct Struct; + + impl Struct { + fn foo(self: &mut &Self) {} + } + + trait Trait { + fn bar(&mut self) {} + } + + impl Trait for &Struct {} + + fn bar() { + let s = &Struct; + (&*s).foo(); + (&*s).bar(); + + let mut s = &Struct; + s.foo(); // To avoid a warning about `s` not needing to be mutable + (&*s).foo(); + //~^ borrow_deref_ref + } +} diff --git a/tests/ui/borrow_deref_ref.stderr b/tests/ui/borrow_deref_ref.stderr index f5868aa87490..3d55da25b9b2 100644 --- a/tests/ui/borrow_deref_ref.stderr +++ b/tests/ui/borrow_deref_ref.stderr @@ -19,5 +19,11 @@ error: deref on an immutable reference LL | let addr_y = &&*x as *const _ as usize; // assert ok | ^^^ help: if you would like to reborrow, try removing `&*`: `x` -error: aborting due to 3 previous errors +error: deref on an immutable reference + --> tests/ui/borrow_deref_ref.rs:123:9 + | +LL | (&*s).foo(); + | ^^^^^ help: if you would like to reborrow, try removing `&*`: `s` + +error: aborting due to 4 previous errors diff --git a/tests/ui/box_collection.rs b/tests/ui/box_collection.rs index 0f7d3c74ddd0..7ae5446924fa 100644 --- a/tests/ui/box_collection.rs +++ b/tests/ui/box_collection.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![allow( clippy::boxed_local, clippy::needless_pass_by_value, diff --git a/tests/ui/box_collection.stderr b/tests/ui/box_collection.stderr index ebbc3d92b57f..d730e2dcc114 100644 --- a/tests/ui/box_collection.stderr +++ b/tests/ui/box_collection.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `Box>`. Consider using just `Vec<..>` - --> tests/ui/box_collection.rs:21:15 + --> tests/ui/box_collection.rs:20:15 | LL | fn test1(foo: Box>) {} | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | fn test1(foo: Box>) {} = help: to override `-D warnings` add `#[allow(clippy::box_collection)]` error: you seem to be trying to use `Box`. Consider using just `String` - --> tests/ui/box_collection.rs:29:15 + --> tests/ui/box_collection.rs:28:15 | LL | fn test3(foo: Box) {} | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn test3(foo: Box) {} = help: `String` is already on the heap, `Box` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashMap<..>` - --> tests/ui/box_collection.rs:32:15 + --> tests/ui/box_collection.rs:31:15 | LL | fn test4(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn test4(foo: Box>) {} = help: `HashMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashSet<..>` - --> tests/ui/box_collection.rs:35:15 + --> tests/ui/box_collection.rs:34:15 | LL | fn test5(foo: Box>) {} | ^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | fn test5(foo: Box>) {} = help: `HashSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `VecDeque<..>` - --> tests/ui/box_collection.rs:38:15 + --> tests/ui/box_collection.rs:37:15 | LL | fn test6(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | fn test6(foo: Box>) {} = help: `VecDeque<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `LinkedList<..>` - --> tests/ui/box_collection.rs:41:15 + --> tests/ui/box_collection.rs:40:15 | LL | fn test7(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn test7(foo: Box>) {} = help: `LinkedList<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeMap<..>` - --> tests/ui/box_collection.rs:44:15 + --> tests/ui/box_collection.rs:43:15 | LL | fn test8(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | fn test8(foo: Box>) {} = help: `BTreeMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeSet<..>` - --> tests/ui/box_collection.rs:47:15 + --> tests/ui/box_collection.rs:46:15 | LL | fn test9(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | fn test9(foo: Box>) {} = help: `BTreeSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BinaryHeap<..>` - --> tests/ui/box_collection.rs:50:16 + --> tests/ui/box_collection.rs:49:16 | LL | fn test10(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index bf7635fdf09b..0c9d21243546 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,5 +1,4 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] -#![allow(clippy::unnecessary_map_or)] use std::string::String; @@ -13,7 +12,7 @@ impl TestStruct { fn is_rust_file(filename: &str) -> bool { std::path::Path::new(filename) .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + .is_some_and(|ext| ext.eq_ignore_ascii_case("rs")) //~^ case_sensitive_file_extension_comparisons } @@ -21,18 +20,18 @@ fn main() { // std::string::String and &str should trigger the lint failure with .ext12 let _ = std::path::Path::new(&String::new()) .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); //~^ case_sensitive_file_extension_comparisons let _ = std::path::Path::new("str") .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); //~^ case_sensitive_file_extension_comparisons // The fixup should preserve the indentation level { let _ = std::path::Path::new("str") .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); //~^ case_sensitive_file_extension_comparisons } @@ -42,11 +41,11 @@ fn main() { // std::string::String and &str should trigger the lint failure with .EXT12 let _ = std::path::Path::new(&String::new()) .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12")); //~^ case_sensitive_file_extension_comparisons let _ = std::path::Path::new("str") .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12")); //~^ case_sensitive_file_extension_comparisons // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase @@ -76,3 +75,11 @@ fn main() { let _ = "str".ends_with(".123"); TestStruct {}.ends_with(".123"); } + +#[clippy::msrv = "1.69"] +fn msrv_check() { + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + //~^ case_sensitive_file_extension_comparisons +} diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 0c4070a42d4b..f8a947aa827b 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,5 +1,4 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] -#![allow(clippy::unnecessary_map_or)] use std::string::String; @@ -64,3 +63,9 @@ fn main() { let _ = "str".ends_with(".123"); TestStruct {}.ends_with(".123"); } + +#[clippy::msrv = "1.69"] +fn msrv_check() { + let _ = String::new().ends_with(".ext12"); + //~^ case_sensitive_file_extension_comparisons +} diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index e035534d2699..93bee8e76671 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,5 +1,5 @@ error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5 | LL | filename.ends_with(".rs") | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,11 +11,81 @@ help: use std::path::Path | LL ~ std::path::Path::new(filename) LL + .extension() -LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +LL + .is_some_and(|ext| ext.eq_ignore_ascii_case("rs")) | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 + | +LL | let _ = String::new().ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> tests/ui/case_sensitive_file_extension_comparisons.rs:21:13 + | +LL | let _ = "str".ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> tests/ui/case_sensitive_file_extension_comparisons.rs:26:17 + | +LL | let _ = "str".ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> tests/ui/case_sensitive_file_extension_comparisons.rs:34:13 + | +LL | let _ = String::new().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> tests/ui/case_sensitive_file_extension_comparisons.rs:36:13 + | +LL | let _ = "str".ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> tests/ui/case_sensitive_file_extension_comparisons.rs:69:13 | LL | let _ = String::new().ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,61 +98,5 @@ LL + .extension() LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | -error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:22:13 - | -LL | let _ = "str".ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new("str") -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); - | - -error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:27:17 - | -LL | let _ = "str".ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new("str") -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); - | - -error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:35:13 - | -LL | let _ = String::new().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new(&String::new()) -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:37:13 - | -LL | let _ = "str".ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new("str") -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/char_indices_as_byte_indices.fixed b/tests/ui/char_indices_as_byte_indices.fixed new file mode 100644 index 000000000000..04c8f6782c51 --- /dev/null +++ b/tests/ui/char_indices_as_byte_indices.fixed @@ -0,0 +1,65 @@ +#![feature(round_char_boundary)] +#![warn(clippy::char_indices_as_byte_indices)] + +trait StrExt { + fn use_index(&self, _: usize); +} +impl StrExt for str { + fn use_index(&self, _: usize) {} +} + +fn bad(prim: &str, string: String) { + for (idx, _) in prim.char_indices() { + let _ = prim[..idx]; + //~^ char_indices_as_byte_indices + prim.split_at(idx); + //~^ char_indices_as_byte_indices + + // This won't panic, but it can still return a wrong substring + let _ = prim[..prim.floor_char_boundary(idx)]; + //~^ char_indices_as_byte_indices + + // can't use #[expect] here because the .fixed file will still have the attribute and create an + // unfulfilled expectation, but make sure lint level attributes work on the use expression: + #[allow(clippy::char_indices_as_byte_indices)] + let _ = prim[..idx]; + } + + for c in prim.char_indices() { + let _ = prim[..c.0]; + //~^ char_indices_as_byte_indices + prim.split_at(c.0); + //~^ char_indices_as_byte_indices + } + + for (idx, _) in string.char_indices() { + let _ = string[..idx]; + //~^ char_indices_as_byte_indices + string.split_at(idx); + //~^ char_indices_as_byte_indices + } +} + +fn good(prim: &str, prim2: &str) { + for (idx, _) in prim.chars().enumerate() { + // Indexing into a different string + let _ = prim2[..idx]; + + // Unknown use + std::hint::black_box(idx); + + // Method call to user defined extension trait + prim.use_index(idx); + + // str method taking a usize that doesn't represent a byte index + prim.splitn(idx, prim2); + } + + let mut string = "äa".to_owned(); + for (idx, _) in string.clone().chars().enumerate() { + // Even though the receiver is the same expression, it should not be treated as the same value. + string.clone().remove(idx); + } +} + +fn main() {} diff --git a/tests/ui/char_indices_as_byte_indices.rs b/tests/ui/char_indices_as_byte_indices.rs new file mode 100644 index 000000000000..773a4fc65f12 --- /dev/null +++ b/tests/ui/char_indices_as_byte_indices.rs @@ -0,0 +1,65 @@ +#![feature(round_char_boundary)] +#![warn(clippy::char_indices_as_byte_indices)] + +trait StrExt { + fn use_index(&self, _: usize); +} +impl StrExt for str { + fn use_index(&self, _: usize) {} +} + +fn bad(prim: &str, string: String) { + for (idx, _) in prim.chars().enumerate() { + let _ = prim[..idx]; + //~^ char_indices_as_byte_indices + prim.split_at(idx); + //~^ char_indices_as_byte_indices + + // This won't panic, but it can still return a wrong substring + let _ = prim[..prim.floor_char_boundary(idx)]; + //~^ char_indices_as_byte_indices + + // can't use #[expect] here because the .fixed file will still have the attribute and create an + // unfulfilled expectation, but make sure lint level attributes work on the use expression: + #[allow(clippy::char_indices_as_byte_indices)] + let _ = prim[..idx]; + } + + for c in prim.chars().enumerate() { + let _ = prim[..c.0]; + //~^ char_indices_as_byte_indices + prim.split_at(c.0); + //~^ char_indices_as_byte_indices + } + + for (idx, _) in string.chars().enumerate() { + let _ = string[..idx]; + //~^ char_indices_as_byte_indices + string.split_at(idx); + //~^ char_indices_as_byte_indices + } +} + +fn good(prim: &str, prim2: &str) { + for (idx, _) in prim.chars().enumerate() { + // Indexing into a different string + let _ = prim2[..idx]; + + // Unknown use + std::hint::black_box(idx); + + // Method call to user defined extension trait + prim.use_index(idx); + + // str method taking a usize that doesn't represent a byte index + prim.splitn(idx, prim2); + } + + let mut string = "äa".to_owned(); + for (idx, _) in string.clone().chars().enumerate() { + // Even though the receiver is the same expression, it should not be treated as the same value. + string.clone().remove(idx); + } +} + +fn main() {} diff --git a/tests/ui/char_indices_as_byte_indices.stderr b/tests/ui/char_indices_as_byte_indices.stderr new file mode 100644 index 000000000000..e2b4c1db78cf --- /dev/null +++ b/tests/ui/char_indices_as_byte_indices.stderr @@ -0,0 +1,130 @@ +error: indexing into a string with a character position where a byte index is expected + --> tests/ui/char_indices_as_byte_indices.rs:13:24 + | +LL | let _ = prim[..idx]; + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:12:10 + | +LL | for (idx, _) in prim.chars().enumerate() { + | ^^^ ^^^^^^^^^^^ + = note: `-D clippy::char-indices-as-byte-indices` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::char_indices_as_byte_indices)]` +help: consider using `.char_indices()` instead + | +LL - for (idx, _) in prim.chars().enumerate() { +LL + for (idx, _) in prim.char_indices() { + | + +error: passing a character position to a method that expects a byte index + --> tests/ui/char_indices_as_byte_indices.rs:15:23 + | +LL | prim.split_at(idx); + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:12:10 + | +LL | for (idx, _) in prim.chars().enumerate() { + | ^^^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for (idx, _) in prim.chars().enumerate() { +LL + for (idx, _) in prim.char_indices() { + | + +error: passing a character position to a method that expects a byte index + --> tests/ui/char_indices_as_byte_indices.rs:19:49 + | +LL | let _ = prim[..prim.floor_char_boundary(idx)]; + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:12:10 + | +LL | for (idx, _) in prim.chars().enumerate() { + | ^^^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for (idx, _) in prim.chars().enumerate() { +LL + for (idx, _) in prim.char_indices() { + | + +error: indexing into a string with a character position where a byte index is expected + --> tests/ui/char_indices_as_byte_indices.rs:29:24 + | +LL | let _ = prim[..c.0]; + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:28:9 + | +LL | for c in prim.chars().enumerate() { + | ^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for c in prim.chars().enumerate() { +LL + for c in prim.char_indices() { + | + +error: passing a character position to a method that expects a byte index + --> tests/ui/char_indices_as_byte_indices.rs:31:23 + | +LL | prim.split_at(c.0); + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:28:9 + | +LL | for c in prim.chars().enumerate() { + | ^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for c in prim.chars().enumerate() { +LL + for c in prim.char_indices() { + | + +error: indexing into a string with a character position where a byte index is expected + --> tests/ui/char_indices_as_byte_indices.rs:36:26 + | +LL | let _ = string[..idx]; + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:35:10 + | +LL | for (idx, _) in string.chars().enumerate() { + | ^^^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for (idx, _) in string.chars().enumerate() { +LL + for (idx, _) in string.char_indices() { + | + +error: passing a character position to a method that expects a byte index + --> tests/ui/char_indices_as_byte_indices.rs:38:25 + | +LL | string.split_at(idx); + | ^^^ + | + = note: a character can take up more than one byte, so they are not interchangeable +note: position comes from the enumerate iterator + --> tests/ui/char_indices_as_byte_indices.rs:35:10 + | +LL | for (idx, _) in string.chars().enumerate() { + | ^^^ ^^^^^^^^^^^ +help: consider using `.char_indices()` instead + | +LL - for (idx, _) in string.chars().enumerate() { +LL + for (idx, _) in string.char_indices() { + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index c17eaef2326b..bdac1e42309d 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -244,8 +244,7 @@ LL | if X.is_some() { | = note: for more information, see = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = note: `-D static-mut-refs` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(static_mut_refs)]` + = note: `#[deny(static_mut_refs)]` on by default error: aborting due to 26 previous errors diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index eb01633a25fd..85d0991bef05 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -74,3 +74,12 @@ impl ToOwned for Baz { Baz } } + +fn issue_8103() { + let foo1 = String::from("foo"); + let _ = foo1 == "foo"; + //~^ cmp_owned + let foo2 = "foo"; + let _ = foo1 == foo2; + //~^ cmp_owned +} diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index 82409f27b129..2393757d76f2 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -74,3 +74,12 @@ impl ToOwned for Baz { Baz } } + +fn issue_8103() { + let foo1 = String::from("foo"); + let _ = foo1 == "foo".to_owned(); + //~^ cmp_owned + let foo2 = "foo"; + let _ = foo1 == foo2.to_owned(); + //~^ cmp_owned +} diff --git a/tests/ui/cmp_owned/with_suggestion.stderr b/tests/ui/cmp_owned/with_suggestion.stderr index ca2ab4484727..dd9ffa70897a 100644 --- a/tests/ui/cmp_owned/with_suggestion.stderr +++ b/tests/ui/cmp_owned/with_suggestion.stderr @@ -37,5 +37,17 @@ error: this creates an owned instance just for comparison LL | "abc".chars().filter(|c| c.to_owned() != 'X'); | ^^^^^^^^^^^^ help: try: `*c` -error: aborting due to 6 previous errors +error: this creates an owned instance just for comparison + --> tests/ui/cmp_owned/with_suggestion.rs:80:21 + | +LL | let _ = foo1 == "foo".to_owned(); + | ^^^^^^^^^^^^^^^^ help: try: `"foo"` + +error: this creates an owned instance just for comparison + --> tests/ui/cmp_owned/with_suggestion.rs:83:21 + | +LL | let _ = foo1 == foo2.to_owned(); + | ^^^^^^^^^^^^^^^ help: try: `foo2` + +error: aborting due to 8 previous errors diff --git a/tests/ui/cognitive_complexity.rs b/tests/ui/cognitive_complexity.rs index 2dbec955f63f..8080c6775e0b 100644 --- a/tests/ui/cognitive_complexity.rs +++ b/tests/ui/cognitive_complexity.rs @@ -1,6 +1,11 @@ -#![allow(clippy::all)] #![warn(clippy::cognitive_complexity)] -#![allow(unused, unused_crate_dependencies)] +#![allow( + clippy::eq_op, + clippy::needless_borrows_for_generic_args, + clippy::needless_return, + clippy::nonminimal_bool, + clippy::uninlined_format_args +)] #[rustfmt::skip] fn main() { @@ -448,3 +453,22 @@ mod issue9300 { } } } + +#[clippy::cognitive_complexity = "1"] +mod issue14422 { + fn foo() { + //~^ cognitive_complexity + for _ in 0..10 { + println!("hello there"); + } + } + + fn bar() { + //~^ cognitive_complexity + for _ in 0..10 { + println!("hello there"); + } + return; + return; + } +} diff --git a/tests/ui/cognitive_complexity.stderr b/tests/ui/cognitive_complexity.stderr index 52607b87c60e..67ef4e5655bd 100644 --- a/tests/ui/cognitive_complexity.stderr +++ b/tests/ui/cognitive_complexity.stderr @@ -1,5 +1,5 @@ error: the function has a cognitive complexity of (28/25) - --> tests/ui/cognitive_complexity.rs:6:4 + --> tests/ui/cognitive_complexity.rs:11:4 | LL | fn main() { | ^^^^ @@ -9,7 +9,7 @@ LL | fn main() { = help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]` error: the function has a cognitive complexity of (7/1) - --> tests/ui/cognitive_complexity.rs:93:4 + --> tests/ui/cognitive_complexity.rs:98:4 | LL | fn kaboom() { | ^^^^^^ @@ -17,7 +17,7 @@ LL | fn kaboom() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:153:4 + --> tests/ui/cognitive_complexity.rs:158:4 | LL | fn baa() { | ^^^ @@ -25,7 +25,7 @@ LL | fn baa() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:156:13 + --> tests/ui/cognitive_complexity.rs:161:13 | LL | let x = || match 99 { | ^^ @@ -33,7 +33,7 @@ LL | let x = || match 99 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:174:4 + --> tests/ui/cognitive_complexity.rs:179:4 | LL | fn bar() { | ^^^ @@ -41,7 +41,7 @@ LL | fn bar() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:187:4 + --> tests/ui/cognitive_complexity.rs:192:4 | LL | fn dont_warn_on_tests() { | ^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn dont_warn_on_tests() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:197:4 + --> tests/ui/cognitive_complexity.rs:202:4 | LL | fn barr() { | ^^^^ @@ -57,7 +57,7 @@ LL | fn barr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:209:4 + --> tests/ui/cognitive_complexity.rs:214:4 | LL | fn barr2() { | ^^^^^ @@ -65,7 +65,7 @@ LL | fn barr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:227:4 + --> tests/ui/cognitive_complexity.rs:232:4 | LL | fn barrr() { | ^^^^^ @@ -73,7 +73,7 @@ LL | fn barrr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:239:4 + --> tests/ui/cognitive_complexity.rs:244:4 | LL | fn barrr2() { | ^^^^^^ @@ -81,7 +81,7 @@ LL | fn barrr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:257:4 + --> tests/ui/cognitive_complexity.rs:262:4 | LL | fn barrrr() { | ^^^^^^ @@ -89,7 +89,7 @@ LL | fn barrrr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:269:4 + --> tests/ui/cognitive_complexity.rs:274:4 | LL | fn barrrr2() { | ^^^^^^^ @@ -97,7 +97,7 @@ LL | fn barrrr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:287:4 + --> tests/ui/cognitive_complexity.rs:292:4 | LL | fn cake() { | ^^^^ @@ -105,7 +105,7 @@ LL | fn cake() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (4/1) - --> tests/ui/cognitive_complexity.rs:299:8 + --> tests/ui/cognitive_complexity.rs:304:8 | LL | pub fn read_file(input_path: &str) -> String { | ^^^^^^^^^ @@ -113,7 +113,7 @@ LL | pub fn read_file(input_path: &str) -> String { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:332:4 + --> tests/ui/cognitive_complexity.rs:337:4 | LL | fn void(void: Void) { | ^^^^ @@ -121,7 +121,7 @@ LL | fn void(void: Void) { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (8/1) - --> tests/ui/cognitive_complexity.rs:385:4 + --> tests/ui/cognitive_complexity.rs:390:4 | LL | fn early_ret() -> i32 { | ^^^^^^^^^ @@ -129,7 +129,7 @@ LL | fn early_ret() -> i32 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:408:13 + --> tests/ui/cognitive_complexity.rs:413:13 | LL | let x = |a: i32, b: i32| -> i32 { | ^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | let x = |a: i32, b: i32| -> i32 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:423:8 + --> tests/ui/cognitive_complexity.rs:428:8 | LL | fn moo(&self) { | ^^^ @@ -145,7 +145,7 @@ LL | fn moo(&self) { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:434:14 + --> tests/ui/cognitive_complexity.rs:439:14 | LL | async fn a() { | ^ @@ -153,12 +153,28 @@ LL | async fn a() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:443:22 + --> tests/ui/cognitive_complexity.rs:448:22 | LL | pub async fn async_method() { | ^^^^^^^^^^^^ | = help: you could split it up into multiple smaller functions -error: aborting due to 20 previous errors +error: the function has a cognitive complexity of (2/1) + --> tests/ui/cognitive_complexity.rs:459:8 + | +LL | fn foo() { + | ^^^ + | + = help: you could split it up into multiple smaller functions + +error: the function has a cognitive complexity of (2/1) + --> tests/ui/cognitive_complexity.rs:466:8 + | +LL | fn bar() { + | ^^^ + | + = help: you could split it up into multiple smaller functions + +error: aborting due to 22 previous errors diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 6e994018aef0..e1ceb04f9cb8 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -12,34 +12,40 @@ fn main() { let x = "hello"; let y = "world"; - if x == "hello" && y == "world" { - println!("Hello world!"); - } + if x == "hello" + && y == "world" { + println!("Hello world!"); + } //~^^^^^ collapsible_if - if (x == "hello" || x == "world") && (y == "world" || y == "hello") { - println!("Hello world!"); - } + if (x == "hello" || x == "world") + && (y == "world" || y == "hello") { + println!("Hello world!"); + } //~^^^^^ collapsible_if - if x == "hello" && x == "world" && (y == "world" || y == "hello") { - println!("Hello world!"); - } + if x == "hello" && x == "world" + && (y == "world" || y == "hello") { + println!("Hello world!"); + } //~^^^^^ collapsible_if - if (x == "hello" || x == "world") && y == "world" && y == "hello" { - println!("Hello world!"); - } + if (x == "hello" || x == "world") + && y == "world" && y == "hello" { + println!("Hello world!"); + } //~^^^^^ collapsible_if - if x == "hello" && x == "world" && y == "world" && y == "hello" { - println!("Hello world!"); - } + if x == "hello" && x == "world" + && y == "world" && y == "hello" { + println!("Hello world!"); + } //~^^^^^ collapsible_if - if 42 == 1337 && 'a' != 'A' { - println!("world!") - } + if 42 == 1337 + && 'a' != 'A' { + println!("world!") + } //~^^^^^ collapsible_if // Works because any if with an else statement cannot be collapsed. @@ -71,41 +77,12 @@ fn main() { assert!(true); // assert! is just an `if` } - - // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798 - if x == "hello" {// Not collapsible - if y == "world" { + if x == "hello" + && y == "world" { // Collapsible println!("Hello world!"); } - } - - if x == "hello" { // Not collapsible - if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" { - // Not collapsible - if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" && y == "world" { // Collapsible - println!("Hello world!"); - } //~^^^^^ collapsible_if - if x == "hello" { - print!("Hello "); - } else { - // Not collapsible - if y == "world" { - println!("world!") - } - } - if x == "hello" { print!("Hello "); } else { @@ -116,15 +93,11 @@ fn main() { } if x == "hello" { - /* Not collapsible */ + print!("Hello "); + } else { + // Not collapsible if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" { /* Not collapsible */ - if y == "world" { - println!("Hello world!"); + println!("world!") } } @@ -150,11 +123,13 @@ fn main() { } // Fix #5962 - if matches!(true, true) && matches!(true, true) {} + if matches!(true, true) + && matches!(true, true) {} //~^^^ collapsible_if // Issue #9375 - if matches!(true, true) && truth() && matches!(true, true) {} + if matches!(true, true) && truth() + && matches!(true, true) {} //~^^^ collapsible_if if true { @@ -163,4 +138,27 @@ fn main() { println!("Hello world!"); } } + + if true + && true { + println!("No comment, linted"); + } + //~^^^^^ collapsible_if + + if true { + // Do not collapse because of this comment + if true { + println!("Hello world!"); + } + } +} + +#[rustfmt::skip] +fn layout_check() -> u32 { + if true + && true { + } + // This is a comment, do not collapse code to it + ; 3 + //~^^^^^ collapsible_if } diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index 5cf591a658c7..0b996dca22e8 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -83,27 +83,6 @@ fn main() { assert!(true); // assert! is just an `if` } - - // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798 - if x == "hello" {// Not collapsible - if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" { // Not collapsible - if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" { - // Not collapsible - if y == "world" { - println!("Hello world!"); - } - } - if x == "hello" { if y == "world" { // Collapsible println!("Hello world!"); @@ -115,7 +94,7 @@ fn main() { print!("Hello "); } else { // Not collapsible - if y == "world" { + if let Some(42) = Some(42) { println!("world!") } } @@ -124,24 +103,11 @@ fn main() { print!("Hello "); } else { // Not collapsible - if let Some(42) = Some(42) { + if y == "world" { println!("world!") } } - if x == "hello" { - /* Not collapsible */ - if y == "world" { - println!("Hello world!"); - } - } - - if x == "hello" { /* Not collapsible */ - if y == "world" { - println!("Hello world!"); - } - } - // Test behavior wrt. `let_chains`. // None of the cases below should be collapsed. fn truth() -> bool { true } @@ -181,4 +147,28 @@ fn main() { println!("Hello world!"); } } + + if true { + if true { + println!("No comment, linted"); + } + } + //~^^^^^ collapsible_if + + if true { + // Do not collapse because of this comment + if true { + println!("Hello world!"); + } + } +} + +#[rustfmt::skip] +fn layout_check() -> u32 { + if true { + if true { + } + // This is a comment, do not collapse code to it + }; 3 + //~^^^^^ collapsible_if } diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 3cc3fe5534f2..532811462393 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -12,9 +12,10 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` help: collapse nested if block | -LL ~ if x == "hello" && y == "world" { -LL + println!("Hello world!"); -LL + } +LL ~ if x == "hello" +LL ~ && y == "world" { +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed @@ -29,9 +30,10 @@ LL | | } | help: collapse nested if block | -LL ~ if (x == "hello" || x == "world") && (y == "world" || y == "hello") { -LL + println!("Hello world!"); -LL + } +LL ~ if (x == "hello" || x == "world") { +LL ~ && (y == "world" || y == "hello") { +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed @@ -46,9 +48,10 @@ LL | | } | help: collapse nested if block | -LL ~ if x == "hello" && x == "world" && (y == "world" || y == "hello") { -LL + println!("Hello world!"); -LL + } +LL ~ if x == "hello" && x == "world" +LL ~ && (y == "world" || y == "hello") { +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed @@ -63,9 +66,10 @@ LL | | } | help: collapse nested if block | -LL ~ if (x == "hello" || x == "world") && y == "world" && y == "hello" { -LL + println!("Hello world!"); -LL + } +LL ~ if (x == "hello" || x == "world") { +LL ~ && y == "world" && y == "hello" { +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed @@ -80,9 +84,10 @@ LL | | } | help: collapse nested if block | -LL ~ if x == "hello" && x == "world" && y == "world" && y == "hello" { -LL + println!("Hello world!"); -LL + } +LL ~ if x == "hello" && x == "world" +LL ~ && y == "world" && y == "hello" { +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed @@ -97,13 +102,14 @@ LL | | } | help: collapse nested if block | -LL ~ if 42 == 1337 && 'a' != 'A' { -LL + println!("world!") -LL + } +LL ~ if 42 == 1337 +LL ~ && 'a' != 'A' { +LL | println!("world!") +LL ~ } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:107:5 + --> tests/ui/collapsible_if.rs:86:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -114,26 +120,75 @@ LL | | } | help: collapse nested if block | -LL ~ if x == "hello" && y == "world" { // Collapsible -LL + println!("Hello world!"); -LL + } +LL ~ if x == "hello" +LL ~ && y == "world" { // Collapsible +LL | println!("Hello world!"); +LL ~ } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:167:5 + --> tests/ui/collapsible_if.rs:133:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} LL | | } - | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` + | |_____^ + | +help: collapse nested if block + | +LL ~ if matches!(true, true) +LL ~ && matches!(true, true) {} + | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:173:5 + --> tests/ui/collapsible_if.rs:139:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} LL | | } - | |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}` + | |_____^ + | +help: collapse nested if block + | +LL ~ if matches!(true, true) && truth() +LL ~ && matches!(true, true) {} + | -error: aborting due to 9 previous errors +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if.rs:151:5 + | +LL | / if true { +LL | | if true { +LL | | println!("No comment, linted"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if true +LL ~ && true { +LL | println!("No comment, linted"); +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if.rs:168:5 + | +LL | / if true { +LL | | if true { +... | +LL | | }; 3 + | |_____^ + | +help: collapse nested if block + | +LL ~ if true +LL ~ && true { +LL | } +LL | // This is a comment, do not collapse code to it +LL ~ ; 3 + | + +error: aborting due to 11 previous errors diff --git a/tests/ui/collapsible_if_let_chains.fixed b/tests/ui/collapsible_if_let_chains.fixed new file mode 100644 index 000000000000..3dd9498a4c9f --- /dev/null +++ b/tests/ui/collapsible_if_let_chains.fixed @@ -0,0 +1,29 @@ +#![feature(let_chains)] +#![warn(clippy::collapsible_if)] + +fn main() { + if let Some(a) = Some(3) { + // with comment, so do not lint + if let Some(b) = Some(4) { + let _ = a + b; + } + } + + if let Some(a) = Some(3) + && let Some(b) = Some(4) { + let _ = a + b; + } + //~^^^^^ collapsible_if + + if let Some(a) = Some(3) + && a + 1 == 4 { + let _ = a; + } + //~^^^^^ collapsible_if + + if Some(3) == Some(4).map(|x| x - 1) + && let Some(b) = Some(4) { + let _ = b; + } + //~^^^^^ collapsible_if +} diff --git a/tests/ui/collapsible_if_let_chains.rs b/tests/ui/collapsible_if_let_chains.rs new file mode 100644 index 000000000000..064b9a0be484 --- /dev/null +++ b/tests/ui/collapsible_if_let_chains.rs @@ -0,0 +1,32 @@ +#![feature(let_chains)] +#![warn(clippy::collapsible_if)] + +fn main() { + if let Some(a) = Some(3) { + // with comment, so do not lint + if let Some(b) = Some(4) { + let _ = a + b; + } + } + + if let Some(a) = Some(3) { + if let Some(b) = Some(4) { + let _ = a + b; + } + } + //~^^^^^ collapsible_if + + if let Some(a) = Some(3) { + if a + 1 == 4 { + let _ = a; + } + } + //~^^^^^ collapsible_if + + if Some(3) == Some(4).map(|x| x - 1) { + if let Some(b) = Some(4) { + let _ = b; + } + } + //~^^^^^ collapsible_if +} diff --git a/tests/ui/collapsible_if_let_chains.stderr b/tests/ui/collapsible_if_let_chains.stderr new file mode 100644 index 000000000000..64a88114c47a --- /dev/null +++ b/tests/ui/collapsible_if_let_chains.stderr @@ -0,0 +1,58 @@ +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:12:5 + | +LL | / if let Some(a) = Some(3) { +LL | | if let Some(b) = Some(4) { +LL | | let _ = a + b; +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::collapsible-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL ~ && let Some(b) = Some(4) { +LL | let _ = a + b; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:19:5 + | +LL | / if let Some(a) = Some(3) { +LL | | if a + 1 == 4 { +LL | | let _ = a; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL ~ && a + 1 == 4 { +LL | let _ = a; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:26:5 + | +LL | / if Some(3) == Some(4).map(|x| x - 1) { +LL | | if let Some(b) = Some(4) { +LL | | let _ = b; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if Some(3) == Some(4).map(|x| x - 1) +LL ~ && let Some(b) = Some(4) { +LL | let _ = b; +LL ~ } + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 796cabd4b669..55ef55844957 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -303,6 +303,18 @@ pub fn test_2(x: Issue9647) { } } +// https://github.com/rust-lang/rust-clippy/issues/14281 +fn lint_emitted_at_right_node(opt: Option>) { + let n = match opt { + #[expect(clippy::collapsible_match)] + Some(n) => match n { + Ok(n) => n, + _ => return, + }, + None => return, + }; +} + fn make() -> T { unimplemented!() } diff --git a/tests/ui/crashes/enum-glob-import-crate.rs b/tests/ui/crashes/enum-glob-import-crate.rs index bbcd599f6d0b..3352e822ef84 100644 --- a/tests/ui/crashes/enum-glob-import-crate.rs +++ b/tests/ui/crashes/enum-glob-import-crate.rs @@ -1,8 +1,5 @@ //@ check-pass -#![deny(clippy::all)] -#![allow(unused_imports)] - use std::*; fn main() {} diff --git a/tests/ui/crashes/ice-11230.fixed b/tests/ui/crashes/ice-11230.fixed index 181e1ebbe5a3..c49a419f0d4b 100644 --- a/tests/ui/crashes/ice-11230.fixed +++ b/tests/ui/crashes/ice-11230.fixed @@ -12,7 +12,7 @@ fn main() { // needless_collect trait Helper<'a>: Iterator {} +// Should not be linted because we have no idea whether the iterator has side effects fn x(w: &mut dyn for<'a> Helper<'a>) { - w.next().is_none(); - //~^ needless_collect + w.collect::>().is_empty(); } diff --git a/tests/ui/crashes/ice-11230.rs b/tests/ui/crashes/ice-11230.rs index fb05dc781bc0..f66b7e961c88 100644 --- a/tests/ui/crashes/ice-11230.rs +++ b/tests/ui/crashes/ice-11230.rs @@ -12,7 +12,7 @@ fn main() { // needless_collect trait Helper<'a>: Iterator {} +// Should not be linted because we have no idea whether the iterator has side effects fn x(w: &mut dyn for<'a> Helper<'a>) { w.collect::>().is_empty(); - //~^ needless_collect } diff --git a/tests/ui/crashes/ice-11230.stderr b/tests/ui/crashes/ice-11230.stderr index b4a3f67081ae..91d59121ac4e 100644 --- a/tests/ui/crashes/ice-11230.stderr +++ b/tests/ui/crashes/ice-11230.stderr @@ -7,14 +7,5 @@ LL | for v in A.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::explicit_iter_loop)]` -error: avoid using `collect()` when not needed - --> tests/ui/crashes/ice-11230.rs:16:7 - | -LL | w.collect::>().is_empty(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` - | - = note: `-D clippy::needless-collect` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/crashes/ice-13544-original.rs b/tests/ui/crashes/ice-13544-original.rs new file mode 100644 index 000000000000..1709eaeb365e --- /dev/null +++ b/tests/ui/crashes/ice-13544-original.rs @@ -0,0 +1,45 @@ +//@ check-pass +#![warn(clippy::significant_drop_tightening)] + +use std::mem::ManuallyDrop; +use std::ops::{Deref, DerefMut}; + +trait Scopable: Sized { + type SubType: Scopable; +} + +struct Subtree(ManuallyDrop>>); + +impl Drop for Subtree { + fn drop(&mut self) { + // SAFETY: The field cannot be used after we drop + unsafe { ManuallyDrop::drop(&mut self.0) } + } +} + +impl Deref for Subtree { + type Target = Tree; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Subtree { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +enum Tree { + Group(Vec>), + Subtree(Subtree), + Leaf(T), +} + +impl Tree { + fn foo(self) -> Self { + self + } +} + +fn main() {} diff --git a/tests/ui/crashes/ice-13544-reduced.rs b/tests/ui/crashes/ice-13544-reduced.rs new file mode 100644 index 000000000000..9266e71f5d0e --- /dev/null +++ b/tests/ui/crashes/ice-13544-reduced.rs @@ -0,0 +1,16 @@ +//@ check-pass +#![warn(clippy::significant_drop_tightening)] +#![allow(unused, clippy::no_effect)] + +use std::marker::PhantomData; + +trait Trait { + type Assoc: Trait; +} +struct S(*const S, PhantomData); + +fn f(x: &mut S) { + &mut x.0; +} + +fn main() {} diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs index 3ccd33052cd6..422c29b66cf6 100644 --- a/tests/ui/crashes/ice-1588.rs +++ b/tests/ui/crashes/ice-1588.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(clippy::all)] +#![expect(clippy::no_effect)] // Test for https://github.com/rust-lang/rust-clippy/issues/1588 diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs index 34ff725d7117..813972a046f7 100644 --- a/tests/ui/crashes/ice-1969.rs +++ b/tests/ui/crashes/ice-1969.rs @@ -1,7 +1,5 @@ //@ check-pass -#![allow(clippy::all)] - // Test for https://github.com/rust-lang/rust-clippy/issues/1969 fn main() {} diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 4ce484917ae2..e06eccdf142c 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,8 +1,6 @@ //@ check-pass -#![warn(clippy::all)] -#![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] -#![allow(unused)] +#![expect(clippy::disallowed_names)] // Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs index aa3bf493c201..ca82f638b0bb 100644 --- a/tests/ui/crashes/ice-700.rs +++ b/tests/ui/crashes/ice-700.rs @@ -1,7 +1,5 @@ //@ check-pass -#![deny(clippy::all)] - // Test for https://github.com/rust-lang/rust-clippy/issues/700 fn core() {} diff --git a/tests/ui/crashes/ice-7012.rs b/tests/ui/crashes/ice-7012.rs index d76995adadf1..48c1c5a98d40 100644 --- a/tests/ui/crashes/ice-7012.rs +++ b/tests/ui/crashes/ice-7012.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(clippy::all)] +#![expect(clippy::single_match)] enum _MyOption { None, diff --git a/tests/ui/crashes/ice-7423.rs b/tests/ui/crashes/ice-7423.rs index a03981842fcc..fbf5d6520ed6 100644 --- a/tests/ui/crashes/ice-7423.rs +++ b/tests/ui/crashes/ice-7423.rs @@ -6,7 +6,7 @@ pub trait Trait { impl Trait for usize { fn f() { - extern "C" { + unsafe extern "C" { fn g() -> usize; } } diff --git a/tests/ui/crashes/ice_exact_size.rs b/tests/ui/crashes/ice_exact_size.rs index cb4685e78e22..0aa55cd0fac6 100644 --- a/tests/ui/crashes/ice_exact_size.rs +++ b/tests/ui/crashes/ice_exact_size.rs @@ -1,10 +1,7 @@ //@ check-pass -#![deny(clippy::all)] - // Test for https://github.com/rust-lang/rust-clippy/issues/1336 -#[allow(dead_code)] struct Foo; impl Iterator for Foo { diff --git a/tests/ui/crashes/needless_borrow_fp.rs b/tests/ui/crashes/needless_borrow_fp.rs index 68e39531682a..1b3b0290d909 100644 --- a/tests/ui/crashes/needless_borrow_fp.rs +++ b/tests/ui/crashes/needless_borrow_fp.rs @@ -1,6 +1,5 @@ //@ check-pass -#[deny(clippy::all)] #[derive(Debug)] pub enum Error { Type(&'static str), diff --git a/tests/ui/crate_level_checks/no_std_swap.fixed b/tests/ui/crate_level_checks/no_std_swap.fixed index e09a913ef06c..9d977e9eddc8 100644 --- a/tests/ui/crate_level_checks/no_std_swap.fixed +++ b/tests/ui/crate_level_checks/no_std_swap.fixed @@ -3,7 +3,6 @@ use core::panic::PanicInfo; -#[warn(clippy::all)] pub fn main() { let mut a = 42; let mut b = 1337; diff --git a/tests/ui/crate_level_checks/no_std_swap.rs b/tests/ui/crate_level_checks/no_std_swap.rs index 66ca97690c17..0967efe2ed8d 100644 --- a/tests/ui/crate_level_checks/no_std_swap.rs +++ b/tests/ui/crate_level_checks/no_std_swap.rs @@ -3,7 +3,6 @@ use core::panic::PanicInfo; -#[warn(clippy::all)] pub fn main() { let mut a = 42; let mut b = 1337; diff --git a/tests/ui/crate_level_checks/no_std_swap.stderr b/tests/ui/crate_level_checks/no_std_swap.stderr index 3e37bd95ef34..e16b53b51a81 100644 --- a/tests/ui/crate_level_checks/no_std_swap.stderr +++ b/tests/ui/crate_level_checks/no_std_swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are trying to swap `a` and `b` - --> tests/ui/crate_level_checks/no_std_swap.rs:11:5 + --> tests/ui/crate_level_checks/no_std_swap.rs:10:5 | LL | / a = b; ... | @@ -7,8 +7,7 @@ LL | | b = a; | |_________^ help: try: `core::mem::swap(&mut a, &mut b)` | = note: or maybe you should use `core::mem::replace`? - = note: `-D clippy::almost-swapped` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]` + = note: `#[deny(clippy::almost_swapped)]` on by default error: aborting due to 1 previous error diff --git a/tests/ui/dbg_macro/dbg_macro.fixed b/tests/ui/dbg_macro/dbg_macro.fixed index fd1a0d8934b3..3b9dee81898a 100644 --- a/tests/ui/dbg_macro/dbg_macro.fixed +++ b/tests/ui/dbg_macro/dbg_macro.fixed @@ -1,5 +1,10 @@ +#![allow( + clippy::no_effect, + clippy::uninlined_format_args, + clippy::unit_arg, + clippy::unnecessary_operation +)] #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = n.checked_sub(4) { n } else { n } diff --git a/tests/ui/dbg_macro/dbg_macro.rs b/tests/ui/dbg_macro/dbg_macro.rs index c96e2c7251c2..1dbbc6fe9845 100644 --- a/tests/ui/dbg_macro/dbg_macro.rs +++ b/tests/ui/dbg_macro/dbg_macro.rs @@ -1,5 +1,10 @@ +#![allow( + clippy::no_effect, + clippy::uninlined_format_args, + clippy::unit_arg, + clippy::unnecessary_operation +)] #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } diff --git a/tests/ui/dbg_macro/dbg_macro.stderr b/tests/ui/dbg_macro/dbg_macro.stderr index cd6dce584a2f..f1412023cc89 100644 --- a/tests/ui/dbg_macro/dbg_macro.stderr +++ b/tests/ui/dbg_macro/dbg_macro.stderr @@ -1,5 +1,5 @@ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:5:22 + --> tests/ui/dbg_macro/dbg_macro.rs:10:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + if let Some(n) = n.checked_sub(4) { n } else { n } | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:11:8 + --> tests/ui/dbg_macro/dbg_macro.rs:16:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if n <= 1 { | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:14:9 + --> tests/ui/dbg_macro/dbg_macro.rs:19:9 | LL | dbg!(1) | ^^^^^^^ @@ -37,7 +37,7 @@ LL + 1 | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:17:9 + --> tests/ui/dbg_macro/dbg_macro.rs:22:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:23:5 + --> tests/ui/dbg_macro/dbg_macro.rs:28:5 | LL | dbg!(42); | ^^^^^^^^ @@ -61,7 +61,7 @@ LL + 42; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:26:14 + --> tests/ui/dbg_macro/dbg_macro.rs:31:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + foo(3) + factorial(4); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:29:5 + --> tests/ui/dbg_macro/dbg_macro.rs:34:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + (1, 2, 3, 4, 5); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:51:5 + --> tests/ui/dbg_macro/dbg_macro.rs:56:5 | LL | dbg!(); | ^^^^^^ @@ -96,7 +96,7 @@ LL - dbg!(); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:55:13 + --> tests/ui/dbg_macro/dbg_macro.rs:60:13 | LL | let _ = dbg!(); | ^^^^^^ @@ -108,7 +108,7 @@ LL + let _ = (); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:58:9 + --> tests/ui/dbg_macro/dbg_macro.rs:63:9 | LL | bar(dbg!()); | ^^^^^^ @@ -120,7 +120,7 @@ LL + bar(()); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:61:10 + --> tests/ui/dbg_macro/dbg_macro.rs:66:10 | LL | foo!(dbg!()); | ^^^^^^ @@ -132,7 +132,7 @@ LL + foo!(()); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:64:16 + --> tests/ui/dbg_macro/dbg_macro.rs:69:16 | LL | foo2!(foo!(dbg!())); | ^^^^^^ @@ -144,7 +144,7 @@ LL + foo2!(foo!(())); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:46:13 + --> tests/ui/dbg_macro/dbg_macro.rs:51:13 | LL | dbg!(); | ^^^^^^ @@ -159,7 +159,7 @@ LL - dbg!(); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:87:9 + --> tests/ui/dbg_macro/dbg_macro.rs:92:9 | LL | dbg!(2); | ^^^^^^^ @@ -171,7 +171,7 @@ LL + 2; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:94:5 + --> tests/ui/dbg_macro/dbg_macro.rs:99:5 | LL | dbg!(1); | ^^^^^^^ @@ -183,7 +183,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:100:5 + --> tests/ui/dbg_macro/dbg_macro.rs:105:5 | LL | dbg!(1); | ^^^^^^^ @@ -195,7 +195,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:107:9 + --> tests/ui/dbg_macro/dbg_macro.rs:112:9 | LL | dbg!(1); | ^^^^^^^ @@ -207,7 +207,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:114:31 + --> tests/ui/dbg_macro/dbg_macro.rs:119:31 | LL | println!("dbg: {:?}", dbg!(s)); | ^^^^^^^ @@ -219,7 +219,7 @@ LL + println!("dbg: {:?}", s); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:117:22 + --> tests/ui/dbg_macro/dbg_macro.rs:122:22 | LL | print!("{}", dbg!(s)); | ^^^^^^^ diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 03f5ca31f5f0..40f40f7ea096 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -5,7 +5,7 @@ #![allow(clippy::missing_safety_doc)] #[link(name = "c")] -extern "C" {} +unsafe extern "C" {} #[lang = "sized"] pub trait Sized {} diff --git a/tests/ui/default_constructed_unit_structs.fixed b/tests/ui/default_constructed_unit_structs.fixed index fa4d55177823..1ca9be0ceddc 100644 --- a/tests/ui/default_constructed_unit_structs.fixed +++ b/tests/ui/default_constructed_unit_structs.fixed @@ -161,3 +161,17 @@ fn main() { let _ = ::default(); } + +fn issue12654() { + #[derive(Default)] + struct G; + + fn f(_g: G) {} + + f(<_>::default()); + f(G); + //~^ default_constructed_unit_structs + + // No lint because `as Default` hides the singleton + f(::default()); +} diff --git a/tests/ui/default_constructed_unit_structs.rs b/tests/ui/default_constructed_unit_structs.rs index 291cd89da0b7..99eb8913fc3c 100644 --- a/tests/ui/default_constructed_unit_structs.rs +++ b/tests/ui/default_constructed_unit_structs.rs @@ -161,3 +161,17 @@ fn main() { let _ = ::default(); } + +fn issue12654() { + #[derive(Default)] + struct G; + + fn f(_g: G) {} + + f(<_>::default()); + f(::default()); + //~^ default_constructed_unit_structs + + // No lint because `as Default` hides the singleton + f(::default()); +} diff --git a/tests/ui/default_constructed_unit_structs.stderr b/tests/ui/default_constructed_unit_structs.stderr index 6d4e1bdc2cc8..97fad792e4f7 100644 --- a/tests/ui/default_constructed_unit_structs.stderr +++ b/tests/ui/default_constructed_unit_structs.stderr @@ -1,41 +1,65 @@ error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:11:13 + --> tests/ui/default_constructed_unit_structs.rs:11:9 | LL | Self::default() - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^----------- + | | + | help: remove this call to `default` | = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::default_constructed_unit_structs)]` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:54:31 + --> tests/ui/default_constructed_unit_structs.rs:54:20 | LL | inner: PhantomData::default(), - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^----------- + | | + | help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:128:33 + --> tests/ui/default_constructed_unit_structs.rs:128:13 | LL | let _ = PhantomData::::default(); - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^^^^^^^^^^----------- + | | + | help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:130:42 + --> tests/ui/default_constructed_unit_structs.rs:130:31 | LL | let _: PhantomData = PhantomData::default(); - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^----------- + | | + | help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:132:55 + --> tests/ui/default_constructed_unit_structs.rs:132:31 | LL | let _: PhantomData = std::marker::PhantomData::default(); - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^^^^^^^^^^^^^^----------- + | | + | help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:134:23 + --> tests/ui/default_constructed_unit_structs.rs:134:13 | LL | let _ = UnitStruct::default(); - | ^^^^^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^----------- + | | + | help: remove this call to `default` -error: aborting due to 6 previous errors +error: use of `default` to create a unit struct + --> tests/ui/default_constructed_unit_structs.rs:172:7 + | +LL | f(::default()); + | ^^^^^^^^^^^^^^ + | +help: remove this call to `default` + | +LL - f(::default()); +LL + f(G); + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 35646e1c2391..2787f6406fe3 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -16,5 +16,6 @@ #![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention` #![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` +#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items` fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index d7be1e583b08..604732405c37 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -85,5 +85,11 @@ error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_ LL | #![warn(clippy::option_map_or_err_ok)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>` + --> tests/ui/deprecated.rs:19:9 + | +LL | #![warn(clippy::match_on_vec_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 707a9ff05857..e334203c7b2a 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -6,6 +6,8 @@ dead_code )] #![warn(clippy::expl_impl_clone_on_copy)] +#![expect(incomplete_features)] // `unsafe_fields` is incomplete for the time being +#![feature(unsafe_fields)] // `clone()` cannot be derived automatically on unsafe fields #[derive(Copy)] @@ -113,4 +115,19 @@ impl Clone for Packed { } } +fn issue14558() { + pub struct Valid { + pub unsafe actual: (), + } + + unsafe impl Copy for Valid {} + + impl Clone for Valid { + #[inline] + fn clone(&self) -> Self { + *self + } + } +} + fn main() {} diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index 20278d4f4e4a..9004ced6849e 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -1,5 +1,5 @@ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:14:1 + --> tests/ui/derive.rs:16:1 | LL | / impl Clone for Qux { LL | | @@ -10,7 +10,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:14:1 + --> tests/ui/derive.rs:16:1 | LL | / impl Clone for Qux { LL | | @@ -23,7 +23,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]` error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:40:1 + --> tests/ui/derive.rs:42:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | @@ -34,7 +34,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:40:1 + --> tests/ui/derive.rs:42:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | @@ -45,7 +45,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:53:1 + --> tests/ui/derive.rs:55:1 | LL | / impl Clone for BigArray { LL | | @@ -56,7 +56,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:53:1 + --> tests/ui/derive.rs:55:1 | LL | / impl Clone for BigArray { LL | | @@ -67,7 +67,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:66:1 + --> tests/ui/derive.rs:68:1 | LL | / impl Clone for FnPtr { LL | | @@ -78,7 +78,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:66:1 + --> tests/ui/derive.rs:68:1 | LL | / impl Clone for FnPtr { LL | | @@ -89,7 +89,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:88:1 + --> tests/ui/derive.rs:90:1 | LL | / impl Clone for Generic2 { LL | | @@ -100,7 +100,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:88:1 + --> tests/ui/derive.rs:90:1 | LL | / impl Clone for Generic2 { LL | | diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 5f2b697f88b0..8cf20d8b1a11 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -1,4 +1,3 @@ - //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] @@ -272,7 +271,7 @@ fn parenthesized_word() {} /// UXes fn plural_acronym_test() {} -extern "C" { +unsafe extern "C" { /// `foo()` //~^ doc_markdown fn in_extern(); diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index ed3925694c67..5b6f2bd8330c 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -1,4 +1,3 @@ - //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] @@ -272,7 +271,7 @@ fn parenthesized_word() {} /// UXes fn plural_acronym_test() {} -extern "C" { +unsafe extern "C" { /// foo() //~^ doc_markdown fn in_extern(); diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index d67da75a230c..98c26e6bec2e 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -1,5 +1,5 @@ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:9:9 + --> tests/ui/doc/doc-fixable.rs:8:9 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^ @@ -13,7 +13,7 @@ LL + /// The `foo_bar` function does _nothing_. See also foo::bar. (note the dot | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:9:51 + --> tests/ui/doc/doc-fixable.rs:8:51 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^^ @@ -25,7 +25,7 @@ LL + /// The foo_bar function does _nothing_. See also `foo::bar`. (note the dot | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:12:83 + --> tests/ui/doc/doc-fixable.rs:11:83 | LL | /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. B | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:15:13 + --> tests/ui/doc/doc-fixable.rs:14:13 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + /// Here be `::a::global:path`, and _::another::global::path_. :: is not a | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:15:36 + --> tests/ui/doc/doc-fixable.rs:14:36 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + /// Here be ::a::global:path, and _`::another::global::path`_. :: is not a | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:18:25 + --> tests/ui/doc/doc-fixable.rs:17:25 | LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + /// Import an item from `::awesome::global::blob::` (Intended postfix) | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:20:31 + --> tests/ui/doc/doc-fixable.rs:19:31 | LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) | ^^^^^ @@ -85,7 +85,7 @@ LL + /// These are the options for `::Cat`: (Intended trailing single colon, sho | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:22:22 + --> tests/ui/doc/doc-fixable.rs:21:22 | LL | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + /// That's not code ~`NotInCodeBlock`~. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:24:5 + --> tests/ui/doc/doc-fixable.rs:23:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:39:5 + --> tests/ui/doc/doc-fixable.rs:38:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:47:5 + --> tests/ui/doc/doc-fixable.rs:46:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:62:5 + --> tests/ui/doc/doc-fixable.rs:61:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:91:5 + --> tests/ui/doc/doc-fixable.rs:90:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:109:5 + --> tests/ui/doc/doc-fixable.rs:108:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:118:8 + --> tests/ui/doc/doc-fixable.rs:117:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + /// ## `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:122:7 + --> tests/ui/doc/doc-fixable.rs:121:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + /// # `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:125:22 + --> tests/ui/doc/doc-fixable.rs:124:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + /// Not a title #897 `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:127:5 + --> tests/ui/doc/doc-fixable.rs:126:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:135:5 + --> tests/ui/doc/doc-fixable.rs:134:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:149:5 + --> tests/ui/doc/doc-fixable.rs:148:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:161:43 + --> tests/ui/doc/doc-fixable.rs:160:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -253,7 +253,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:166:5 + --> tests/ui/doc/doc-fixable.rs:165:5 | LL | And BarQuz too. | ^^^^^^ @@ -265,7 +265,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:167:1 + --> tests/ui/doc/doc-fixable.rs:166:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:175:43 + --> tests/ui/doc/doc-fixable.rs:174:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -289,7 +289,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:180:5 + --> tests/ui/doc/doc-fixable.rs:179:5 | LL | And BarQuz too. | ^^^^^^ @@ -301,7 +301,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:181:1 + --> tests/ui/doc/doc-fixable.rs:180:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:195:5 + --> tests/ui/doc/doc-fixable.rs:194:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:215:22 + --> tests/ui/doc/doc-fixable.rs:214:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + /// An iterator over `mycrate::Collection`'s values. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:240:34 + --> tests/ui/doc/doc-fixable.rs:239:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:264:22 + --> tests/ui/doc/doc-fixable.rs:263:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -361,7 +361,7 @@ LL + /// There is no try (`do()` or do_not()). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:264:30 + --> tests/ui/doc/doc-fixable.rs:263:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -373,7 +373,7 @@ LL + /// There is no try (do() or `do_not()`). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:269:5 + --> tests/ui/doc/doc-fixable.rs:268:5 | LL | /// ABes | ^^^^ @@ -385,7 +385,7 @@ LL + /// `ABes` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:276:9 + --> tests/ui/doc/doc-fixable.rs:275:9 | LL | /// foo() | ^^^^^ @@ -397,7 +397,7 @@ LL + /// `foo()` | error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:281:5 + --> tests/ui/doc/doc-fixable.rs:280:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 1bdf01e4e22e..7146fd7941ab 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -103,7 +103,7 @@ macro_rules! very_unsafe { /// /// Please keep the seat belt fastened pub unsafe fn drive() { - whee() + unsafe { whee() } } }; } diff --git a/tests/ui/double_ended_iterator_last.fixed b/tests/ui/double_ended_iterator_last.fixed index 17d0d71a8854..2ce0c04c3017 100644 --- a/tests/ui/double_ended_iterator_last.fixed +++ b/tests/ui/double_ended_iterator_last.fixed @@ -52,28 +52,35 @@ fn main() { let _ = CustomLast.last(); } +// Should not be linted because applying the lint would move the original iterator. This can only be +// linted if the iterator is used thereafter. fn issue_14139() { let mut index = [true, true, false, false, false, true].iter(); - let mut subindex = index.by_ref().take(3); - let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let subindex = index.by_ref().take(3); + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); - let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); let subindex = &mut subindex; - let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); let subindex = &mut subindex; - let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); - let (mut subindex, _) = (index.by_ref().take(3), 42); - let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let (subindex, _) = (index.by_ref().take(3), 42); + let _ = subindex.last(); + let _ = index.next(); } fn drop_order() { @@ -90,3 +97,14 @@ fn drop_order() { //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` println!("Done"); } + +fn issue_14444() { + let mut squares = vec![]; + let last_square = [1, 2, 3] + .into_iter() + .map(|x| { + squares.push(x * x); + Some(x * x) + }) + .last(); +} diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs index 41bc669b1719..a4eb9b3337b9 100644 --- a/tests/ui/double_ended_iterator_last.rs +++ b/tests/ui/double_ended_iterator_last.rs @@ -52,28 +52,35 @@ fn main() { let _ = CustomLast.last(); } +// Should not be linted because applying the lint would move the original iterator. This can only be +// linted if the iterator is used thereafter. fn issue_14139() { let mut index = [true, true, false, false, false, true].iter(); let subindex = index.by_ref().take(3); - let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); - let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); let subindex = &mut subindex; - let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let mut subindex = index.by_ref().take(3); let subindex = &mut subindex; - let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); let mut index = [true, true, false, false, false, true].iter(); let (subindex, _) = (index.by_ref().take(3), 42); - let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.last(); + let _ = index.next(); } fn drop_order() { @@ -90,3 +97,14 @@ fn drop_order() { //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` println!("Done"); } + +fn issue_14444() { + let mut squares = vec![]; + let last_square = [1, 2, 3] + .into_iter() + .map(|x| { + squares.push(x * x); + Some(x * x) + }) + .last(); +} diff --git a/tests/ui/double_ended_iterator_last.stderr b/tests/ui/double_ended_iterator_last.stderr index 1702a24d7a05..fe8cf2dcb259 100644 --- a/tests/ui/double_ended_iterator_last.stderr +++ b/tests/ui/double_ended_iterator_last.stderr @@ -18,55 +18,7 @@ LL | let _ = DeIterator.last(); | help: try: `next_back()` error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:58:13 - | -LL | let _ = subindex.last(); - | ^^^^^^^^^^^^^^^ - | -help: try - | -LL ~ let mut subindex = index.by_ref().take(3); -LL ~ let _ = subindex.next_back(); - | - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:62:13 - | -LL | let _ = subindex.last(); - | ^^^^^^^^^------ - | | - | help: try: `next_back()` - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:67:13 - | -LL | let _ = subindex.last(); - | ^^^^^^^^^------ - | | - | help: try: `next_back()` - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:72:13 - | -LL | let _ = subindex.last(); - | ^^^^^^^^^------ - | | - | help: try: `next_back()` - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:76:13 - | -LL | let _ = subindex.last(); - | ^^^^^^^^^^^^^^^ - | -help: try - | -LL ~ let (mut subindex, _) = (index.by_ref().take(3), 42); -LL ~ let _ = subindex.next_back(); - | - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:89:36 + --> tests/ui/double_ended_iterator_last.rs:96:36 | LL | println!("Last element is {}", v.last().unwrap().0); | ^^^^^^^^ @@ -78,5 +30,5 @@ LL ~ let mut v = v.into_iter(); LL ~ println!("Last element is {}", v.next_back().unwrap().0); | -error: aborting due to 8 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/double_ended_iterator_last_unfixable.rs b/tests/ui/double_ended_iterator_last_unfixable.rs index 3f125c7f20c1..7c5de8832d69 100644 --- a/tests/ui/double_ended_iterator_last_unfixable.rs +++ b/tests/ui/double_ended_iterator_last_unfixable.rs @@ -1,10 +1,13 @@ //@no-rustfix #![warn(clippy::double_ended_iterator_last)] +// Should not be linted because applying the lint would move the original iterator. This can only be +// linted if the iterator is used thereafter. fn main() { let mut index = [true, true, false, false, false, true].iter(); let subindex = (index.by_ref().take(3), 42); - let _ = subindex.0.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + let _ = subindex.0.last(); + let _ = index.next(); } fn drop_order() { diff --git a/tests/ui/double_ended_iterator_last_unfixable.stderr b/tests/ui/double_ended_iterator_last_unfixable.stderr index f4be757d00d2..845afc11f042 100644 --- a/tests/ui/double_ended_iterator_last_unfixable.stderr +++ b/tests/ui/double_ended_iterator_last_unfixable.stderr @@ -1,21 +1,5 @@ error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13 - | -LL | let _ = subindex.0.last(); - | ^^^^^^^^^^^------ - | | - | help: try: `next_back()` - | -note: this must be made mutable to use `.next_back()` - --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13 - | -LL | let _ = subindex.0.last(); - | ^^^^^^^^^^ - = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` - -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^^------ @@ -24,10 +8,12 @@ LL | println!("Last element is {}", v.0.last().unwrap().0); | = note: this change will alter drop order which may be undesirable note: this must be made mutable to use `.next_back()` - --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^ + = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/eager_transmute.fixed b/tests/ui/eager_transmute.fixed index 14cbb6113e62..47a32ec836cc 100644 --- a/tests/ui/eager_transmute.fixed +++ b/tests/ui/eager_transmute.fixed @@ -71,8 +71,10 @@ fn f(op: u8, op2: Data, unrelated: u8) { } unsafe fn f2(op: u8) { - (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); - //~^ eager_transmute + unsafe { + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); + //~^ eager_transmute + } } #[rustc_layout_scalar_valid_range_end(254)] diff --git a/tests/ui/eager_transmute.rs b/tests/ui/eager_transmute.rs index 48d7d50cdaef..906cd7bccc86 100644 --- a/tests/ui/eager_transmute.rs +++ b/tests/ui/eager_transmute.rs @@ -71,8 +71,10 @@ fn f(op: u8, op2: Data, unrelated: u8) { } unsafe fn f2(op: u8) { - (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); - //~^ eager_transmute + unsafe { + (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); + //~^ eager_transmute + } } #[rustc_layout_scalar_valid_range_end(254)] diff --git a/tests/ui/eager_transmute.stderr b/tests/ui/eager_transmute.stderr index 54850d110eb2..c719ca8adc12 100644 --- a/tests/ui/eager_transmute.stderr +++ b/tests/ui/eager_transmute.stderr @@ -157,19 +157,19 @@ LL + let _: Option = (..=3).contains(&op).then(|| unsafe { std::mem: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:74:24 + --> tests/ui/eager_transmute.rs:75:28 | -LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `bool::then` to only transmute if the condition holds | -LL - (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); -LL + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); +LL - (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); +LL + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:104:62 + --> tests/ui/eager_transmute.rs:106:62 | LL | let _: Option> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _: Option> = (v1 > 0).then(|| unsafe { std::mem::transm | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:111:86 + --> tests/ui/eager_transmute.rs:113:86 | LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| u | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:118:93 + --> tests/ui/eager_transmute.rs:120:93 | LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/empty_docs.rs b/tests/ui/empty_docs.rs index d7768e07901a..57f8976cd6a7 100644 --- a/tests/ui/empty_docs.rs +++ b/tests/ui/empty_docs.rs @@ -84,7 +84,7 @@ mod issue_12377 { use proc_macro_attr::with_empty_docs; #[with_empty_docs] - extern "C" { + unsafe extern "C" { type Test; } diff --git a/tests/ui/empty_enum_variants_with_brackets.fixed b/tests/ui/empty_enum_variants_with_brackets.fixed index 885f6a50025e..abdf6ca5cb61 100644 --- a/tests/ui/empty_enum_variants_with_brackets.fixed +++ b/tests/ui/empty_enum_variants_with_brackets.fixed @@ -6,8 +6,7 @@ pub enum PublicTestEnum { NonEmptyParentheses(i32, i32), // No error EmptyBraces, //~^ empty_enum_variants_with_brackets - EmptyParentheses, - //~^ empty_enum_variants_with_brackets + EmptyParentheses(), // No error as enum is pub } enum TestEnum { @@ -20,6 +19,67 @@ enum TestEnum { AnotherEnum, // No error } +mod issue12551 { + enum EvenOdd { + // Used as functions -> no error + Even(), + Odd(), + // Not used as a function + Unknown, + //~^ empty_enum_variants_with_brackets + } + + fn even_odd(x: i32) -> EvenOdd { + (x % 2 == 0).then(EvenOdd::Even).unwrap_or_else(EvenOdd::Odd) + } + + fn natural_number(x: i32) -> NaturalOrNot { + (x > 0) + .then(NaturalOrNot::Natural) + .unwrap_or_else(NaturalOrNot::NotNatural) + } + + enum NaturalOrNot { + // Used as functions -> no error + Natural(), + NotNatural(), + // Not used as a function + Unknown, + //~^ empty_enum_variants_with_brackets + } + + enum RedundantParenthesesFunctionCall { + // Used as a function call but with redundant parentheses + Parentheses, + //~^ empty_enum_variants_with_brackets + // Not used as a function + NoParentheses, + } + + #[allow(clippy::no_effect)] + fn redundant_parentheses_function_call() { + // The parentheses in the below line are redundant. + RedundantParenthesesFunctionCall::Parentheses; + RedundantParenthesesFunctionCall::NoParentheses; + } + + // Same test as above but with usage of the enum occurring before the definition. + #[allow(clippy::no_effect)] + fn redundant_parentheses_function_call_2() { + // The parentheses in the below line are redundant. + RedundantParenthesesFunctionCall2::Parentheses; + RedundantParenthesesFunctionCall2::NoParentheses; + } + + enum RedundantParenthesesFunctionCall2 { + // Used as a function call but with redundant parentheses + Parentheses, + //~^ empty_enum_variants_with_brackets + // Not used as a function + NoParentheses, + } +} + enum TestEnumWithFeatures { NonEmptyBraces { #[cfg(feature = "thisisneverenabled")] @@ -28,4 +88,18 @@ enum TestEnumWithFeatures { NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error } +#[derive(Clone)] +enum Foo { + Variant1(i32), + Variant2, + Variant3, //~ ERROR: enum variant has empty brackets +} + +#[derive(Clone)] +pub enum PubFoo { + Variant1(i32), + Variant2, + Variant3(), +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.rs b/tests/ui/empty_enum_variants_with_brackets.rs index 092712ee2ead..63a5a8e9143e 100644 --- a/tests/ui/empty_enum_variants_with_brackets.rs +++ b/tests/ui/empty_enum_variants_with_brackets.rs @@ -6,8 +6,7 @@ pub enum PublicTestEnum { NonEmptyParentheses(i32, i32), // No error EmptyBraces {}, //~^ empty_enum_variants_with_brackets - EmptyParentheses(), - //~^ empty_enum_variants_with_brackets + EmptyParentheses(), // No error as enum is pub } enum TestEnum { @@ -20,6 +19,67 @@ enum TestEnum { AnotherEnum, // No error } +mod issue12551 { + enum EvenOdd { + // Used as functions -> no error + Even(), + Odd(), + // Not used as a function + Unknown(), + //~^ empty_enum_variants_with_brackets + } + + fn even_odd(x: i32) -> EvenOdd { + (x % 2 == 0).then(EvenOdd::Even).unwrap_or_else(EvenOdd::Odd) + } + + fn natural_number(x: i32) -> NaturalOrNot { + (x > 0) + .then(NaturalOrNot::Natural) + .unwrap_or_else(NaturalOrNot::NotNatural) + } + + enum NaturalOrNot { + // Used as functions -> no error + Natural(), + NotNatural(), + // Not used as a function + Unknown(), + //~^ empty_enum_variants_with_brackets + } + + enum RedundantParenthesesFunctionCall { + // Used as a function call but with redundant parentheses + Parentheses(), + //~^ empty_enum_variants_with_brackets + // Not used as a function + NoParentheses, + } + + #[allow(clippy::no_effect)] + fn redundant_parentheses_function_call() { + // The parentheses in the below line are redundant. + RedundantParenthesesFunctionCall::Parentheses(); + RedundantParenthesesFunctionCall::NoParentheses; + } + + // Same test as above but with usage of the enum occurring before the definition. + #[allow(clippy::no_effect)] + fn redundant_parentheses_function_call_2() { + // The parentheses in the below line are redundant. + RedundantParenthesesFunctionCall2::Parentheses(); + RedundantParenthesesFunctionCall2::NoParentheses; + } + + enum RedundantParenthesesFunctionCall2 { + // Used as a function call but with redundant parentheses + Parentheses(), + //~^ empty_enum_variants_with_brackets + // Not used as a function + NoParentheses, + } +} + enum TestEnumWithFeatures { NonEmptyBraces { #[cfg(feature = "thisisneverenabled")] @@ -28,4 +88,18 @@ enum TestEnumWithFeatures { NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error } +#[derive(Clone)] +enum Foo { + Variant1(i32), + Variant2, + Variant3(), //~ ERROR: enum variant has empty brackets +} + +#[derive(Clone)] +pub enum PubFoo { + Variant1(i32), + Variant2, + Variant3(), +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.stderr b/tests/ui/empty_enum_variants_with_brackets.stderr index a9ae3b476dd6..7fe85e829a35 100644 --- a/tests/ui/empty_enum_variants_with_brackets.stderr +++ b/tests/ui/empty_enum_variants_with_brackets.stderr @@ -9,15 +9,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:9:21 - | -LL | EmptyParentheses(), - | ^^ - | - = help: remove the brackets - -error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:16:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:15:16 | LL | EmptyBraces {}, | ^^^ @@ -25,12 +17,66 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:18:21 + --> tests/ui/empty_enum_variants_with_brackets.rs:17:21 | LL | EmptyParentheses(), | ^^ | = help: remove the brackets -error: aborting due to 4 previous errors +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:28:16 + | +LL | Unknown(), + | ^^ + | + = help: remove the brackets + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:47:16 + | +LL | Unknown(), + | ^^ + | + = help: remove the brackets + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:53:20 + | +LL | Parentheses(), + | ^^ + | +help: remove the brackets + | +LL ~ Parentheses, +LL | +... +LL | // The parentheses in the below line are redundant. +LL ~ RedundantParenthesesFunctionCall::Parentheses; + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:76:20 + | +LL | Parentheses(), + | ^^ + | +help: remove the brackets + | +LL ~ RedundantParenthesesFunctionCall2::Parentheses; +LL | RedundantParenthesesFunctionCall2::NoParentheses; +... +LL | // Used as a function call but with redundant parentheses +LL ~ Parentheses, + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:95:13 + | +LL | Variant3(), + | ^^ + | + = help: remove the brackets + +error: aborting due to 8 previous errors diff --git a/tests/ui/empty_line_after/doc_comments.1.fixed b/tests/ui/empty_line_after/doc_comments.1.fixed index e4ba09ea1d47..70ab235b694f 100644 --- a/tests/ui/empty_line_after/doc_comments.1.fixed +++ b/tests/ui/empty_line_after/doc_comments.1.fixed @@ -142,4 +142,9 @@ impl Foo for LineComment { fn bar() {} } +//~v empty_line_after_doc_comments +/// Docs for this item. +// fn some_item() {} +impl LineComment {} // or any other nameless item kind + fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.2.fixed b/tests/ui/empty_line_after/doc_comments.2.fixed index a20f9bc20eb5..87c636c6ad2c 100644 --- a/tests/ui/empty_line_after/doc_comments.2.fixed +++ b/tests/ui/empty_line_after/doc_comments.2.fixed @@ -152,4 +152,10 @@ impl Foo for LineComment { fn bar() {} } +//~v empty_line_after_doc_comments +// /// Docs for this item. +// fn some_item() {} + +impl LineComment {} // or any other nameless item kind + fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.rs b/tests/ui/empty_line_after/doc_comments.rs index 9e3ddfd5abe1..91e9c1ac0b6d 100644 --- a/tests/ui/empty_line_after/doc_comments.rs +++ b/tests/ui/empty_line_after/doc_comments.rs @@ -155,4 +155,10 @@ impl Foo for LineComment { fn bar() {} } +//~v empty_line_after_doc_comments +/// Docs for this item. +// fn some_item() {} + +impl LineComment {} // or any other nameless item kind + fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.stderr b/tests/ui/empty_line_after/doc_comments.stderr index fe25ba9afcb9..ae8cb91ba12f 100644 --- a/tests/ui/empty_line_after/doc_comments.stderr +++ b/tests/ui/empty_line_after/doc_comments.stderr @@ -87,7 +87,7 @@ LL | fn new_code() {} | ----------- the comment documents this function | = help: if the empty line is unintentional, remove it -help: if the doc comment should not document `new_code` comment it out +help: if the doc comment should not document function `new_code` then comment it out | LL | // /// docs for `old_code` | ++ @@ -107,7 +107,7 @@ LL | struct Multiple; | --------------- the comment documents this struct | = help: if the empty lines are unintentional, remove them -help: if the doc comment should not document `Multiple` comment it out +help: if the doc comment should not document struct `Multiple` then comment it out | LL ~ // /// Docs LL ~ // /// for OldA @@ -149,7 +149,7 @@ LL | fn new_code() {} | ----------- the comment documents this function | = help: if the empty line is unintentional, remove it -help: if the doc comment should not document `new_code` comment it out +help: if the doc comment should not document function `new_code` then comment it out | LL - /** LL + /* @@ -167,7 +167,7 @@ LL | fn new_code2() {} | ------------ the comment documents this function | = help: if the empty line is unintentional, remove it -help: if the doc comment should not document `new_code2` comment it out +help: if the doc comment should not document function `new_code2` then comment it out | LL | // /// Docs for `old_code2` | ++ @@ -183,10 +183,26 @@ LL | fn bar() {} | ------ the comment documents this function | = help: if the empty line is unintentional, remove it -help: if the doc comment should not document `bar` comment it out +help: if the doc comment should not document function `bar` then comment it out | LL | // /// comment on assoc item | ++ -error: aborting due to 11 previous errors +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:159:1 + | +LL | / /// Docs for this item. +LL | | // fn some_item() {} +LL | | + | |_^ +LL | impl LineComment {} // or any other nameless item kind + | - the comment documents this implementation + | + = help: if the empty line is unintentional, remove it +help: if the doc comment should not document the following item then comment it out + | +LL | // /// Docs for this item. + | ++ + +error: aborting due to 12 previous errors diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 69452a8d9a67..f2df9f0204ea 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -226,4 +226,26 @@ fn issue11976() { } } +mod issue14449 { + use std::collections::BTreeMap; + + pub struct Meow { + map: BTreeMap, + } + + impl Meow { + fn pet(&self, _key: &str, _v: u32) -> u32 { + 42 + } + } + + pub fn f(meow: &Meow, x: String) { + if meow.map.contains_key(&x) { + let _ = meow.pet(&x, 1); + } else { + let _ = meow.pet(&x, 0); + } + } +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 3578324f01c5..166eea417ac2 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -232,4 +232,26 @@ fn issue11976() { } } +mod issue14449 { + use std::collections::BTreeMap; + + pub struct Meow { + map: BTreeMap, + } + + impl Meow { + fn pet(&self, _key: &str, _v: u32) -> u32 { + 42 + } + } + + pub fn f(meow: &Meow, x: String) { + if meow.map.contains_key(&x) { + let _ = meow.pet(&x, 1); + } else { + let _ = meow.pet(&x, 0); + } + } +} + fn main() {} diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 7235f7d5b82a..ec6bed152e79 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -59,7 +59,7 @@ fn f_str_t(_: &str, _: T) {} fn f_box_t(_: &Box) {} -extern "C" { +unsafe extern "C" { fn var(_: u32, ...); } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index c4d2b28ff4b5..ca58c650d9ce 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -59,7 +59,7 @@ fn f_str_t(_: &str, _: T) {} fn f_box_t(_: &Box) {} -extern "C" { +unsafe extern "C" { fn var(_: u32, ...); } diff --git a/tests/ui/filter_map_bool_then_unfixable.rs b/tests/ui/filter_map_bool_then_unfixable.rs new file mode 100644 index 000000000000..68294292502a --- /dev/null +++ b/tests/ui/filter_map_bool_then_unfixable.rs @@ -0,0 +1,63 @@ +#![allow(clippy::question_mark, unused)] +#![warn(clippy::filter_map_bool_then)] +//@no-rustfix + +fn issue11617() { + let mut x: Vec = vec![0; 10]; + let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| { + //~^ filter_map_bool_then + (x[i] != *v).then(|| { + x[i] = i; + i + }) + }); +} + +mod issue14368 { + + fn do_something(_: ()) -> bool { + true + } + + fn option_with_early_return(x: &[Option]) { + let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); + //~^ filter_map_bool_then + let _ = x + .iter() + .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(()))); + //~^ filter_map_bool_then + let _ = x.iter().filter_map(|&x| { + //~^ filter_map_bool_then + match x { + Some(x) => x, + None => return None, + } + .then(|| do_something(())) + }); + } + + #[derive(Copy, Clone)] + enum Foo { + One(bool), + Two, + Three(Option), + } + + fn nested_type_with_early_return(x: &[Foo]) { + let _ = x.iter().filter_map(|&x| { + //~^ filter_map_bool_then + match x { + Foo::One(x) => x, + Foo::Two => return None, + Foo::Three(inner) => { + if inner? == 0 { + return Some(false); + } else { + true + } + }, + } + .then(|| do_something(())) + }); + } +} diff --git a/tests/ui/filter_map_bool_then_unfixable.stderr b/tests/ui/filter_map_bool_then_unfixable.stderr new file mode 100644 index 000000000000..2025958136ba --- /dev/null +++ b/tests/ui/filter_map_bool_then_unfixable.stderr @@ -0,0 +1,65 @@ +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then_unfixable.rs:7:48 + | +LL | let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| { + | ________________________________________________^ +LL | | +LL | | (x[i] != *v).then(|| { +LL | | x[i] = i; +LL | | i +LL | | }) +LL | | }); + | |______^ + | + = help: consider using `filter` then `map` instead + = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]` + +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then_unfixable.rs:23:26 + | +LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `filter` then `map` instead + +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then_unfixable.rs:27:14 + | +LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(()))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `filter` then `map` instead + +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then_unfixable.rs:29:26 + | +LL | let _ = x.iter().filter_map(|&x| { + | __________________________^ +LL | | +LL | | match x { +LL | | Some(x) => x, +... | +LL | | .then(|| do_something(())) +LL | | }); + | |__________^ + | + = help: consider using `filter` then `map` instead + +error: usage of `bool::then` in `filter_map` + --> tests/ui/filter_map_bool_then_unfixable.rs:47:26 + | +LL | let _ = x.iter().filter_map(|&x| { + | __________________________^ +LL | | +LL | | match x { +LL | | Foo::One(x) => x, +... | +LL | | .then(|| do_something(())) +LL | | }); + | |__________^ + | + = help: consider using `filter` then `map` instead + +error: aborting due to 5 previous errors + diff --git a/tests/ui/filter_map_next.rs b/tests/ui/filter_map_next.rs index 2a2237ed16cf..5414e01c8700 100644 --- a/tests/ui/filter_map_next.rs +++ b/tests/ui/filter_map_next.rs @@ -1,4 +1,4 @@ -#![warn(clippy::all, clippy::pedantic)] +#![warn(clippy::filter_map_next)] fn main() { let a = ["1", "lol", "3", "NaN", "5"]; diff --git a/tests/ui/filter_map_next_fixable.fixed b/tests/ui/filter_map_next_fixable.fixed index 285863ef340d..09c416041a4e 100644 --- a/tests/ui/filter_map_next_fixable.fixed +++ b/tests/ui/filter_map_next_fixable.fixed @@ -1,5 +1,4 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(unused)] +#![warn(clippy::filter_map_next)] fn main() { let a = ["1", "lol", "3", "NaN", "5"]; diff --git a/tests/ui/filter_map_next_fixable.rs b/tests/ui/filter_map_next_fixable.rs index af911689b7c7..3d686ef41d91 100644 --- a/tests/ui/filter_map_next_fixable.rs +++ b/tests/ui/filter_map_next_fixable.rs @@ -1,5 +1,4 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(unused)] +#![warn(clippy::filter_map_next)] fn main() { let a = ["1", "lol", "3", "NaN", "5"]; diff --git a/tests/ui/filter_map_next_fixable.stderr b/tests/ui/filter_map_next_fixable.stderr index 707dec8687b1..1002837732b8 100644 --- a/tests/ui/filter_map_next_fixable.stderr +++ b/tests/ui/filter_map_next_fixable.stderr @@ -1,5 +1,5 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead - --> tests/ui/filter_map_next_fixable.rs:7:32 + --> tests/ui/filter_map_next_fixable.rs:6:32 | LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` @@ -8,7 +8,7 @@ LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next = help: to override `-D warnings` add `#[allow(clippy::filter_map_next)]` error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead - --> tests/ui/filter_map_next_fixable.rs:21:26 + --> tests/ui/filter_map_next_fixable.rs:20:26 | LL | let _: Option = a.iter().filter_map(|s| s.parse().ok()).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` diff --git a/tests/ui/find_map.rs b/tests/ui/find_map.rs index aba1f2cbe581..a9a8508d5b7d 100644 --- a/tests/ui/find_map.rs +++ b/tests/ui/find_map.rs @@ -1,6 +1,5 @@ //@ check-pass -#![warn(clippy::all, clippy::pedantic)] #![allow(clippy::useless_vec)] #[derive(Debug, Copy, Clone)] diff --git a/tests/ui/fn_params_excessive_bools.rs b/tests/ui/fn_params_excessive_bools.rs index cc18708d25fa..25d25663d1e4 100644 --- a/tests/ui/fn_params_excessive_bools.rs +++ b/tests/ui/fn_params_excessive_bools.rs @@ -1,7 +1,7 @@ #![warn(clippy::fn_params_excessive_bools)] #![allow(clippy::too_many_arguments)] -extern "C" { +unsafe extern "C" { // Should not lint, most of the time users have no control over extern function signatures fn f(_: bool, _: bool, _: bool, _: bool); } @@ -14,8 +14,8 @@ macro_rules! foo { foo!(); -#[no_mangle] -extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {} +#[unsafe(no_mangle)] +unsafe extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {} fn g(_: bool, _: bool, _: bool, _: bool) {} //~^ ERROR: more than 3 bools in function parameters fn h(_: bool, _: bool, _: bool) {} @@ -39,8 +39,8 @@ impl S { fn f(&self, _: bool, _: bool, _: bool, _: bool) {} //~^ ERROR: more than 3 bools in function parameters fn g(&self, _: bool, _: bool, _: bool) {} - #[no_mangle] - extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {} + #[unsafe(no_mangle)] + unsafe extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {} } impl Trait for S { diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index 4e84dcf7d5b7..009815633d75 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -1,6 +1,3 @@ -#![warn(clippy::all)] -#![allow(unused_variables)] -#![allow(unused_assignments)] #![allow(clippy::if_same_then_else)] #![allow(clippy::deref_addrof)] #![allow(clippy::nonminimal_bool)] diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index 972bd3a6a2e6..d9dc2a55f5b6 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -1,5 +1,5 @@ error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` - --> tests/ui/formatting.rs:16:6 + --> tests/ui/formatting.rs:13:6 | LL | a =- 35; | ^^^^ @@ -9,7 +9,7 @@ LL | a =- 35; = help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> tests/ui/formatting.rs:20:6 + --> tests/ui/formatting.rs:17:6 | LL | a =* &191; | ^^^^ @@ -17,7 +17,7 @@ LL | a =* &191; = note: to remove this lint, use either `*=` or `= *` error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> tests/ui/formatting.rs:26:6 + --> tests/ui/formatting.rs:23:6 | LL | b =! false; | ^^^^ @@ -25,17 +25,16 @@ LL | b =! false; = note: to remove this lint, use either `!=` or `= !` error: possibly missing a comma here - --> tests/ui/formatting.rs:38:19 + --> tests/ui/formatting.rs:35:19 | LL | -1, -2, -3 // <= no comma here | ^ | = note: to remove this lint, add a comma or write the expr in a single line - = note: `-D clippy::possible-missing-comma` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::possible_missing_comma)]` + = note: `#[deny(clippy::possible_missing_comma)]` on by default error: possibly missing a comma here - --> tests/ui/formatting.rs:45:19 + --> tests/ui/formatting.rs:42:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -43,7 +42,7 @@ LL | -1, -2, -3 // <= no comma here = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> tests/ui/formatting.rs:85:11 + --> tests/ui/formatting.rs:82:11 | LL | -1 | ^ diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 8618004efb89..be98b2277958 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -73,3 +73,46 @@ fn main() { for _i in [1, 2, 3].iter().collect::>() {} //~^ from_iter_instead_of_collect } + +fn issue14581() { + let nums = [0, 1, 2]; + let _ = &nums.iter().map(|&num| char::from_u32(num).unwrap()).collect::(); + //~^ from_iter_instead_of_collect +} + +fn test_implicit_generic_args(iter: impl Iterator + Copy) { + struct S<'l, T = i32, const A: usize = 3, const B: usize = 3> { + a: [&'l T; A], + b: [&'l T; B], + } + + impl<'l, T, const A: usize, const B: usize> FromIterator<&'l T> for S<'l, T, A, B> { + fn from_iter>(_: I) -> Self { + todo!() + } + } + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::>(); + //~^ from_iter_instead_of_collect + + let _ = iter.collect::(); + //~^ from_iter_instead_of_collect +} diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index c46397e8ff56..ce20fef2ac33 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -73,3 +73,46 @@ fn main() { for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} //~^ from_iter_instead_of_collect } + +fn issue14581() { + let nums = [0, 1, 2]; + let _ = &String::from_iter(nums.iter().map(|&num| char::from_u32(num).unwrap())); + //~^ from_iter_instead_of_collect +} + +fn test_implicit_generic_args(iter: impl Iterator + Copy) { + struct S<'l, T = i32, const A: usize = 3, const B: usize = 3> { + a: [&'l T; A], + b: [&'l T; B], + } + + impl<'l, T, const A: usize, const B: usize> FromIterator<&'l T> for S<'l, T, A, B> { + fn from_iter>(_: I) -> Self { + todo!() + } + } + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = >::from_iter(iter); + //~^ from_iter_instead_of_collect + + let _ = ::from_iter(iter); + //~^ from_iter_instead_of_collect +} diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index b46d97af152f..ec11a375c0d8 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -91,5 +91,59 @@ error: usage of `FromIterator::from_iter` LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` -error: aborting due to 15 previous errors +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:79:14 + | +LL | let _ = &String::from_iter(nums.iter().map(|&num| char::from_u32(num).unwrap())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `nums.iter().map(|&num| char::from_u32(num).unwrap()).collect::()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:95:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:98:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:101:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:104:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:107:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:110:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:113:13 + | +LL | let _ = >::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::>()` + +error: usage of `FromIterator::from_iter` + --> tests/ui/from_iter_instead_of_collect.rs:116:13 + | +LL | let _ = ::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::()` + +error: aborting due to 24 previous errors diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 9c1ca8bf9300..ceaba392dc20 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,5 +1,3 @@ -#![warn(clippy::all)] -#![allow(dead_code, unused_unsafe)] #![allow(clippy::missing_safety_doc, clippy::uninlined_format_args)] // TOO_MANY_ARGUMENTS diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index c8770023f77a..65cc627cc44c 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -1,5 +1,5 @@ error: this function has too many arguments (8/7) - --> tests/ui/functions.rs:8:1 + --> tests/ui/functions.rs:6:1 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f = help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]` error: this function has too many arguments (8/7) - --> tests/ui/functions.rs:12:1 + --> tests/ui/functions.rs:10:1 | LL | / fn bad_multiline( LL | | @@ -20,88 +20,87 @@ LL | | ) { | |_^ error: this function has too many arguments (8/7) - --> tests/ui/functions.rs:48:5 + --> tests/ui/functions.rs:46:5 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) - --> tests/ui/functions.rs:58:5 + --> tests/ui/functions.rs:56:5 | LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:68:34 + --> tests/ui/functions.rs:66:34 | LL | println!("{}", unsafe { *p }); | ^ | - = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::not_unsafe_ptr_arg_deref)]` + = note: `#[deny(clippy::not_unsafe_ptr_arg_deref)]` on by default error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:71:35 + --> tests/ui/functions.rs:69:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:74:33 + --> tests/ui/functions.rs:72:33 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:86:30 + --> tests/ui/functions.rs:84:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:89:31 + --> tests/ui/functions.rs:87:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:92:29 + --> tests/ui/functions.rs:90:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:99:30 + --> tests/ui/functions.rs:97:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:102:31 + --> tests/ui/functions.rs:100:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:105:29 + --> tests/ui/functions.rs:103:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:115:34 + --> tests/ui/functions.rs:113:34 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:118:35 + --> tests/ui/functions.rs:116:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:121:33 + --> tests/ui/functions.rs:119:33 | LL | unsafe { std::ptr::read(p) }; | ^ diff --git a/tests/ui/if_not_else.fixed b/tests/ui/if_not_else.fixed index d26a15156cd8..4e6f43e5671e 100644 --- a/tests/ui/if_not_else.fixed +++ b/tests/ui/if_not_else.fixed @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![warn(clippy::if_not_else)] fn foo() -> bool { diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 6171cf116495..6cd2e3bd63fe 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![warn(clippy::if_not_else)] fn foo() -> bool { diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index f44dd0aabc86..824837bd52bb 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -1,5 +1,5 @@ error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:12:5 + --> tests/ui/if_not_else.rs:11:5 | LL | / if !bla() { LL | | @@ -24,7 +24,7 @@ LL + } | error: unnecessary `!=` operation - --> tests/ui/if_not_else.rs:19:5 + --> tests/ui/if_not_else.rs:18:5 | LL | / if 4 != 5 { LL | | @@ -47,7 +47,7 @@ LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:34:5 + --> tests/ui/if_not_else.rs:33:5 | LL | / if !(foo() && bla()) { LL | | @@ -79,7 +79,7 @@ LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:53:5 + --> tests/ui/if_not_else.rs:52:5 | LL | / if !foo() { LL | | @@ -102,7 +102,7 @@ LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:61:5 + --> tests/ui/if_not_else.rs:60:5 | LL | / if !bla() { LL | | @@ -125,7 +125,7 @@ LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:72:5 + --> tests/ui/if_not_else.rs:71:5 | LL | / if !foo() { LL | | diff --git a/tests/ui/ignore_without_reason.rs b/tests/ui/ignore_without_reason.rs new file mode 100644 index 000000000000..53ac34c27248 --- /dev/null +++ b/tests/ui/ignore_without_reason.rs @@ -0,0 +1,14 @@ +#![warn(clippy::ignore_without_reason)] + +fn main() {} + +#[test] +fn unignored_test() {} + +#[test] +#[ignore = "Some good reason"] +fn ignored_with_reason() {} + +#[test] +#[ignore] //~ ignore_without_reason +fn ignored_without_reason() {} diff --git a/tests/ui/ignore_without_reason.stderr b/tests/ui/ignore_without_reason.stderr new file mode 100644 index 000000000000..4c0210c2bbc0 --- /dev/null +++ b/tests/ui/ignore_without_reason.stderr @@ -0,0 +1,12 @@ +error: `#[ignore]` without reason + --> tests/ui/ignore_without_reason.rs:13:1 + | +LL | #[ignore] + | ^^^^^^^^^ + | + = help: add a reason with `= ".."` + = note: `-D clippy::ignore-without-reason` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ignore_without_reason)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index 1cb639b60a9a..728c6e015c15 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -165,3 +165,46 @@ with_span!( x } ); + +fn desugared_closure_14446() { + let _ = async || return 0; + //~^ implicit_return + #[rustfmt::skip] + let _ = async || -> i32 { return 0 }; + //~^ implicit_return + let _ = async |a: i32| return a; + //~^ implicit_return + #[rustfmt::skip] + let _ = async |a: i32| { return a }; + //~^ implicit_return + + let _ = async || return 0; + let _ = async || -> i32 { return 0 }; + let _ = async |a: i32| return a; + #[rustfmt::skip] + let _ = async |a: i32| { return a; }; + + let _ = async || return foo().await; + //~^ implicit_return + let _ = async || { + foo().await; + return foo().await + }; + //~^^ implicit_return + #[rustfmt::skip] + let _ = async || { return foo().await }; + //~^ implicit_return + let _ = async || -> bool { return foo().await }; + //~^ implicit_return + + let _ = async || return foo().await; + let _ = async || { + foo().await; + return foo().await; + }; + #[rustfmt::skip] + let _ = async || { return foo().await; }; + let _ = async || -> bool { + return foo().await; + }; +} diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 99d75e4987e4..3381fffb6e45 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -165,3 +165,46 @@ with_span!( x } ); + +fn desugared_closure_14446() { + let _ = async || 0; + //~^ implicit_return + #[rustfmt::skip] + let _ = async || -> i32 { 0 }; + //~^ implicit_return + let _ = async |a: i32| a; + //~^ implicit_return + #[rustfmt::skip] + let _ = async |a: i32| { a }; + //~^ implicit_return + + let _ = async || return 0; + let _ = async || -> i32 { return 0 }; + let _ = async |a: i32| return a; + #[rustfmt::skip] + let _ = async |a: i32| { return a; }; + + let _ = async || foo().await; + //~^ implicit_return + let _ = async || { + foo().await; + foo().await + }; + //~^^ implicit_return + #[rustfmt::skip] + let _ = async || { foo().await }; + //~^ implicit_return + let _ = async || -> bool { foo().await }; + //~^ implicit_return + + let _ = async || return foo().await; + let _ = async || { + foo().await; + return foo().await; + }; + #[rustfmt::skip] + let _ = async || { return foo().await; }; + let _ = async || -> bool { + return foo().await; + }; +} diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr index 02044df47ac3..05cd7f62583b 100644 --- a/tests/ui/implicit_return.stderr +++ b/tests/ui/implicit_return.stderr @@ -183,5 +183,93 @@ help: add `return` as shown LL | return true | ++++++ -error: aborting due to 16 previous errors +error: missing `return` statement + --> tests/ui/implicit_return.rs:170:22 + | +LL | let _ = async || 0; + | ^ + | +help: add `return` as shown + | +LL | let _ = async || return 0; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:173:31 + | +LL | let _ = async || -> i32 { 0 }; + | ^ + | +help: add `return` as shown + | +LL | let _ = async || -> i32 { return 0 }; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:175:28 + | +LL | let _ = async |a: i32| a; + | ^ + | +help: add `return` as shown + | +LL | let _ = async |a: i32| return a; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:178:30 + | +LL | let _ = async |a: i32| { a }; + | ^ + | +help: add `return` as shown + | +LL | let _ = async |a: i32| { return a }; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:187:22 + | +LL | let _ = async || foo().await; + | ^^^^^ + | +help: add `return` as shown + | +LL | let _ = async || return foo().await; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:191:9 + | +LL | foo().await + | ^^^^^ + | +help: add `return` as shown + | +LL | return foo().await + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:195:24 + | +LL | let _ = async || { foo().await }; + | ^^^^^ + | +help: add `return` as shown + | +LL | let _ = async || { return foo().await }; + | ++++++ + +error: missing `return` statement + --> tests/ui/implicit_return.rs:197:32 + | +LL | let _ = async || -> bool { foo().await }; + | ^^^^^ + | +help: add `return` as shown + | +LL | let _ = async || -> bool { return foo().await }; + | ++++++ + +error: aborting due to 24 previous errors diff --git a/tests/ui/items_after_test_module/root_module.fixed b/tests/ui/items_after_test_module/root_module.fixed index f036b368a667..c00d6440f1c6 100644 --- a/tests/ui/items_after_test_module/root_module.fixed +++ b/tests/ui/items_after_test_module/root_module.fixed @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::items_after_test_module)] fn main() {} diff --git a/tests/ui/items_after_test_module/root_module.rs b/tests/ui/items_after_test_module/root_module.rs index de0cbb120330..23d191e3b13b 100644 --- a/tests/ui/items_after_test_module/root_module.rs +++ b/tests/ui/items_after_test_module/root_module.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::items_after_test_module)] fn main() {} diff --git a/tests/ui/items_after_test_module/root_module.stderr b/tests/ui/items_after_test_module/root_module.stderr index bed8d4bd5a00..952489ff5ef9 100644 --- a/tests/ui/items_after_test_module/root_module.stderr +++ b/tests/ui/items_after_test_module/root_module.stderr @@ -1,5 +1,5 @@ error: items after a test module - --> tests/ui/items_after_test_module/root_module.rs:12:1 + --> tests/ui/items_after_test_module/root_module.rs:11:1 | LL | mod tests { | ^^^^^^^^^ diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index e9fb44e89598..231fac7cdde7 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -29,3 +29,30 @@ fn main() { let _: Vec = v.to_vec(); //~^ iter_cloned_collect } + +mod issue9119 { + + use std::iter; + + #[derive(Clone)] + struct Example(u16); + + impl iter::FromIterator for Vec { + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect() + } + } + + fn foo() { + let examples = [Example(1), Example(0x1234)]; + let encoded: Vec = examples.iter().cloned().collect(); + assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]); + + let a = [&&String::new()]; + let v: Vec<&&String> = a.to_vec(); + //~^ iter_cloned_collect + } +} diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index c9b8abcc9a0d..e73b6ecae802 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -33,3 +33,30 @@ fn main() { let _: Vec = v.iter().copied().collect(); //~^ iter_cloned_collect } + +mod issue9119 { + + use std::iter; + + #[derive(Clone)] + struct Example(u16); + + impl iter::FromIterator for Vec { + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect() + } + } + + fn foo() { + let examples = [Example(1), Example(0x1234)]; + let encoded: Vec = examples.iter().cloned().collect(); + assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]); + + let a = [&&String::new()]; + let v: Vec<&&String> = a.iter().cloned().collect(); + //~^ iter_cloned_collect + } +} diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index 119698cb4634..f8a507943270 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -36,5 +36,11 @@ error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling LL | let _: Vec = v.iter().copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` -error: aborting due to 5 previous errors +error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable + --> tests/ui/iter_cloned_collect.rs:59:33 + | +LL | let v: Vec<&&String> = a.iter().cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` + +error: aborting due to 6 previous errors diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index 7fcab6592e26..874f749b33d0 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -166,3 +166,18 @@ fn msrv_1_54() { let _ = map.values().map(|v| v + 2).collect::>(); //~^ iter_kv_map } + +fn issue14595() { + pub struct Foo(BTreeMap); + + impl AsRef> for Foo { + fn as_ref(&self) -> &BTreeMap { + &self.0 + } + } + + let map = Foo(BTreeMap::default()); + + let _ = map.as_ref().values().copied().collect::>(); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index b590aef7b803..f570e3c32cb6 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -170,3 +170,18 @@ fn msrv_1_54() { let _ = map.iter().map(|(_, v)| v + 2).collect::>(); //~^ iter_kv_map } + +fn issue14595() { + pub struct Foo(BTreeMap); + + impl AsRef> for Foo { + fn as_ref(&self) -> &BTreeMap { + &self.0 + } + } + + let map = Foo(BTreeMap::default()); + + let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 00d566ed14a2..31ee76c25b7a 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -263,5 +263,11 @@ error: iterating on a map's values LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` -error: aborting due to 38 previous errors +error: iterating on a map's values + --> tests/ui/iter_kv_map.rs:185:13 + | +LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` + +error: aborting due to 39 previous errors diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 999912690290..b0e548f17909 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -59,7 +59,7 @@ fn main() { iter: impl Iterator + 'a, target: String, ) -> impl Iterator + 'a { - iter.filter(move |&(&a, b)| a == 1 && b == &target).cloned() + iter.filter(move |&&(&a, ref b)| a == 1 && b == &target).cloned() //~^ iter_overeager_cloned } diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 6a860dad5afd..cedf62a6b473 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -60,7 +60,7 @@ fn main() { iter: impl Iterator + 'a, target: String, ) -> impl Iterator + 'a { - iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) + iter.cloned().filter(move |&(&a, ref b)| a == 1 && b == &target) //~^ iter_overeager_cloned } diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index f3239b59582e..1616dec95b79 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -120,10 +120,10 @@ LL | let _ = vec.iter().cloned().find(f); error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:63:9 | -LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) - | ^^^^------------------------------------------------------- +LL | iter.cloned().filter(move |&(&a, ref b)| a == 1 && b == &target) + | ^^^^------------------------------------------------------------ | | - | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()` + | help: try: `.filter(move |&&(&a, ref b)| a == 1 && b == &target).cloned()` error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:75:13 diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index c2159c58de1e..4c7215f0abeb 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -1,7 +1,10 @@ +#![allow( + clippy::future_not_send, + clippy::manual_async_fn, + clippy::never_loop, + clippy::uninlined_format_args +)] #![warn(clippy::large_futures)] -#![allow(clippy::never_loop)] -#![allow(clippy::future_not_send)] -#![allow(clippy::manual_async_fn)] async fn big_fut(_arg: [u8; 1024 * 16]) {} diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 567f6344afea..2b5860583f5e 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,7 +1,10 @@ +#![allow( + clippy::future_not_send, + clippy::manual_async_fn, + clippy::never_loop, + clippy::uninlined_format_args +)] #![warn(clippy::large_futures)] -#![allow(clippy::never_loop)] -#![allow(clippy::future_not_send)] -#![allow(clippy::manual_async_fn)] async fn big_fut(_arg: [u8; 1024 * 16]) {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index fd6ba4e3563d..4280c9e2af28 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:10:9 + --> tests/ui/large_futures.rs:13:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await; = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:13:5 + --> tests/ui/large_futures.rs:16:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:18:9 + --> tests/ui/large_futures.rs:21:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:24:13 + --> tests/ui/large_futures.rs:27:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:32:5 + --> tests/ui/large_futures.rs:35:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:35:5 + --> tests/ui/large_futures.rs:38:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:48:5 + --> tests/ui/large_futures.rs:51:5 | LL | / async { LL | | @@ -61,7 +61,7 @@ LL + }) | error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:61:13 + --> tests/ui/large_futures.rs:64:13 | LL | / async { LL | | diff --git a/tests/ui/len_without_is_empty_expect.rs b/tests/ui/len_without_is_empty_expect.rs new file mode 100644 index 000000000000..9d1245e2d02a --- /dev/null +++ b/tests/ui/len_without_is_empty_expect.rs @@ -0,0 +1,28 @@ +//@no-rustfix +#![allow(clippy::len_without_is_empty)] + +// Check that the lint expectation is fulfilled even if the lint is allowed at the type level. +pub struct Empty; + +impl Empty { + #[expect(clippy::len_without_is_empty)] + pub fn len(&self) -> usize { + 0 + } +} + +// Check that the lint expectation is not triggered if it should not +pub struct Empty2; + +impl Empty2 { + #[expect(clippy::len_without_is_empty)] //~ ERROR: this lint expectation is unfulfilled + pub fn len(&self) -> usize { + 0 + } + + pub fn is_empty(&self) -> bool { + false + } +} + +fn main() {} diff --git a/tests/ui/len_without_is_empty_expect.stderr b/tests/ui/len_without_is_empty_expect.stderr new file mode 100644 index 000000000000..e96870f054e4 --- /dev/null +++ b/tests/ui/len_without_is_empty_expect.stderr @@ -0,0 +1,11 @@ +error: this lint expectation is unfulfilled + --> tests/ui/len_without_is_empty_expect.rs:18:14 + | +LL | #[expect(clippy::len_without_is_empty)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unfulfilled-lint-expectations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/manual_abs_diff.fixed b/tests/ui/manual_abs_diff.fixed new file mode 100644 index 000000000000..f1b1278ea6d2 --- /dev/null +++ b/tests/ui/manual_abs_diff.fixed @@ -0,0 +1,106 @@ +#![warn(clippy::manual_abs_diff)] + +use std::time::Duration; + +fn main() { + let a: usize = 5; + let b: usize = 3; + let c: usize = 8; + let d: usize = 11; + + let _ = a.abs_diff(b); + //~^ manual_abs_diff + let _ = b.abs_diff(a); + //~^ manual_abs_diff + + let _ = b.abs_diff(5); + //~^ manual_abs_diff + let _ = b.abs_diff(5); + //~^ manual_abs_diff + + let _ = a.abs_diff(b); + //~^ manual_abs_diff + let _ = b.abs_diff(a); + //~^ manual_abs_diff + + #[allow(arithmetic_overflow)] + { + let _ = if a > b { b - a } else { a - b }; + let _ = if a < b { a - b } else { b - a }; + } + + let _ = (a + b).abs_diff(c + d); + let _ = (c + d).abs_diff(a + b); + + const A: usize = 5; + const B: usize = 3; + // check const context + const _: usize = A.abs_diff(B); + //~^ manual_abs_diff + + let a = Duration::from_secs(3); + let b = Duration::from_secs(5); + let _ = a.abs_diff(b); + //~^ manual_abs_diff + + let a: i32 = 3; + let b: i32 = -5; + let _ = if a > b { a - b } else { b - a }; + let _ = a.abs_diff(b); + //~^ manual_abs_diff +} + +// FIXME: bunch of patterns that should be linted +fn fixme() { + let a: usize = 5; + let b: usize = 3; + let c: usize = 8; + let d: usize = 11; + + { + let out; + if a > b { + out = a - b; + } else { + out = b - a; + } + } + + { + let mut out = 0; + if a > b { + out = a - b; + } else if a < b { + out = b - a; + } + } + + #[allow(clippy::implicit_saturating_sub)] + let _ = if a > b { + a - b + } else if a < b { + b - a + } else { + 0 + }; + + let a: i32 = 3; + let b: i32 = 5; + let _: u32 = if a > b { a - b } else { b - a } as u32; +} + +fn non_primitive_ty() { + #[derive(Eq, PartialEq, PartialOrd)] + struct S(i32); + + impl std::ops::Sub for S { + type Output = S; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } + } + + let (a, b) = (S(10), S(20)); + let _ = if a < b { b - a } else { a - b }; +} diff --git a/tests/ui/manual_abs_diff.rs b/tests/ui/manual_abs_diff.rs new file mode 100644 index 000000000000..60ef819c12d3 --- /dev/null +++ b/tests/ui/manual_abs_diff.rs @@ -0,0 +1,116 @@ +#![warn(clippy::manual_abs_diff)] + +use std::time::Duration; + +fn main() { + let a: usize = 5; + let b: usize = 3; + let c: usize = 8; + let d: usize = 11; + + let _ = if a > b { a - b } else { b - a }; + //~^ manual_abs_diff + let _ = if a < b { b - a } else { a - b }; + //~^ manual_abs_diff + + let _ = if 5 > b { 5 - b } else { b - 5 }; + //~^ manual_abs_diff + let _ = if b > 5 { b - 5 } else { 5 - b }; + //~^ manual_abs_diff + + let _ = if a >= b { a - b } else { b - a }; + //~^ manual_abs_diff + let _ = if a <= b { b - a } else { a - b }; + //~^ manual_abs_diff + + #[allow(arithmetic_overflow)] + { + let _ = if a > b { b - a } else { a - b }; + let _ = if a < b { a - b } else { b - a }; + } + + let _ = if (a + b) > (c + d) { + //~^ manual_abs_diff + (a + b) - (c + d) + } else { + (c + d) - (a + b) + }; + let _ = if (a + b) < (c + d) { + //~^ manual_abs_diff + (c + d) - (a + b) + } else { + (a + b) - (c + d) + }; + + const A: usize = 5; + const B: usize = 3; + // check const context + const _: usize = if A > B { A - B } else { B - A }; + //~^ manual_abs_diff + + let a = Duration::from_secs(3); + let b = Duration::from_secs(5); + let _ = if a > b { a - b } else { b - a }; + //~^ manual_abs_diff + + let a: i32 = 3; + let b: i32 = -5; + let _ = if a > b { a - b } else { b - a }; + let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 }; + //~^ manual_abs_diff +} + +// FIXME: bunch of patterns that should be linted +fn fixme() { + let a: usize = 5; + let b: usize = 3; + let c: usize = 8; + let d: usize = 11; + + { + let out; + if a > b { + out = a - b; + } else { + out = b - a; + } + } + + { + let mut out = 0; + if a > b { + out = a - b; + } else if a < b { + out = b - a; + } + } + + #[allow(clippy::implicit_saturating_sub)] + let _ = if a > b { + a - b + } else if a < b { + b - a + } else { + 0 + }; + + let a: i32 = 3; + let b: i32 = 5; + let _: u32 = if a > b { a - b } else { b - a } as u32; +} + +fn non_primitive_ty() { + #[derive(Eq, PartialEq, PartialOrd)] + struct S(i32); + + impl std::ops::Sub for S { + type Output = S; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } + } + + let (a, b) = (S(10), S(20)); + let _ = if a < b { b - a } else { a - b }; +} diff --git a/tests/ui/manual_abs_diff.stderr b/tests/ui/manual_abs_diff.stderr new file mode 100644 index 000000000000..c14c1dc830fb --- /dev/null +++ b/tests/ui/manual_abs_diff.stderr @@ -0,0 +1,83 @@ +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:11:13 + | +LL | let _ = if a > b { a - b } else { b - a }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` + | + = note: `-D clippy::manual-abs-diff` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_abs_diff)]` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:13:13 + | +LL | let _ = if a < b { b - a } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(a)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:16:13 + | +LL | let _ = if 5 > b { 5 - b } else { b - 5 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(5)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:18:13 + | +LL | let _ = if b > 5 { b - 5 } else { 5 - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(5)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:21:13 + | +LL | let _ = if a >= b { a - b } else { b - a }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:23:13 + | +LL | let _ = if a <= b { b - a } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(a)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:32:13 + | +LL | let _ = if (a + b) > (c + d) { + | _____________^ +LL | | +LL | | (a + b) - (c + d) +LL | | } else { +LL | | (c + d) - (a + b) +LL | | }; + | |_____^ help: replace with `abs_diff`: `(a + b).abs_diff(c + d)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:38:13 + | +LL | let _ = if (a + b) < (c + d) { + | _____________^ +LL | | +LL | | (c + d) - (a + b) +LL | | } else { +LL | | (a + b) - (c + d) +LL | | }; + | |_____^ help: replace with `abs_diff`: `(c + d).abs_diff(a + b)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:48:22 + | +LL | const _: usize = if A > B { A - B } else { B - A }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `A.abs_diff(B)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:53:13 + | +LL | let _ = if a > b { a - b } else { b - a }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` + +error: manual absolute difference pattern without using `abs_diff` + --> tests/ui/manual_abs_diff.rs:59:13 + | +LL | let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` + +error: aborting due to 11 previous errors + diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index ad0266d39e98..a284ca9f6253 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -75,7 +75,7 @@ impl S { async fn elided(_: &i32) -> i32 { 42 } // should be ignored -fn elided_not_bound(_: &i32) -> impl Future { +fn elided_not_bound(_: &i32) -> impl Future + use<> { async { 42 } } @@ -84,7 +84,7 @@ async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } // should be ignored #[allow(clippy::needless_lifetimes)] -fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future { +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + use<> { async { 42 } } @@ -94,7 +94,7 @@ mod issue_5765 { struct A; impl A { - fn f(&self) -> impl Future { + fn f(&self) -> impl Future + use<> { async {} } } diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index fe367b4bc7b9..188f8a4982c3 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -102,7 +102,7 @@ fn elided(_: &i32) -> impl Future + '_ { } // should be ignored -fn elided_not_bound(_: &i32) -> impl Future { +fn elided_not_bound(_: &i32) -> impl Future + use<> { async { 42 } } @@ -114,7 +114,7 @@ fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + // should be ignored #[allow(clippy::needless_lifetimes)] -fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future { +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + use<> { async { 42 } } @@ -124,7 +124,7 @@ mod issue_5765 { struct A; impl A { - fn f(&self) -> impl Future { + fn f(&self) -> impl Future + use<> { async {} } } diff --git a/tests/ui/manual_dangling_ptr.fixed b/tests/ui/manual_dangling_ptr.fixed new file mode 100644 index 000000000000..b6afe7898906 --- /dev/null +++ b/tests/ui/manual_dangling_ptr.fixed @@ -0,0 +1,44 @@ +#![warn(clippy::manual_dangling_ptr)] +use std::mem; + +pub fn foo(_const: *const f32, _mut: *mut i32) {} + +fn main() { + let _: *const u8 = std::ptr::dangling(); + //~^ manual_dangling_ptr + let _ = std::ptr::dangling::(); + //~^ manual_dangling_ptr + let _ = std::ptr::dangling_mut::(); + //~^ manual_dangling_ptr + + let _ = std::ptr::dangling::(); + //~^ manual_dangling_ptr + let _ = std::ptr::dangling::(); + //~^ manual_dangling_ptr + let _ = std::ptr::dangling::(); + //~^ manual_dangling_ptr + + foo(std::ptr::dangling(), std::ptr::dangling_mut()); + //~^ manual_dangling_ptr + //~| manual_dangling_ptr +} + +fn should_not_lint() { + let _ = 0x10 as *mut i32; + let _ = mem::align_of::() as *const u8; + + foo(0 as _, 0 as _); +} + +#[clippy::msrv = "1.83"] +fn _msrv_1_83() { + // `{core, std}::ptr::dangling` was stabilized in 1.84. Do not lint this + foo(4 as *const _, 4 as *mut _); +} + +#[clippy::msrv = "1.84"] +fn _msrv_1_84() { + foo(std::ptr::dangling(), std::ptr::dangling_mut()); + //~^ manual_dangling_ptr + //~| manual_dangling_ptr +} diff --git a/tests/ui/manual_dangling_ptr.rs b/tests/ui/manual_dangling_ptr.rs new file mode 100644 index 000000000000..581ad50113e2 --- /dev/null +++ b/tests/ui/manual_dangling_ptr.rs @@ -0,0 +1,44 @@ +#![warn(clippy::manual_dangling_ptr)] +use std::mem; + +pub fn foo(_const: *const f32, _mut: *mut i32) {} + +fn main() { + let _: *const u8 = 1 as *const _; + //~^ manual_dangling_ptr + let _ = 2 as *const u32; + //~^ manual_dangling_ptr + let _ = 4 as *mut f32; + //~^ manual_dangling_ptr + + let _ = mem::align_of::() as *const u8; + //~^ manual_dangling_ptr + let _ = mem::align_of::() as *const u32; + //~^ manual_dangling_ptr + let _ = mem::align_of::() as *const usize; + //~^ manual_dangling_ptr + + foo(4 as *const _, 4 as *mut _); + //~^ manual_dangling_ptr + //~| manual_dangling_ptr +} + +fn should_not_lint() { + let _ = 0x10 as *mut i32; + let _ = mem::align_of::() as *const u8; + + foo(0 as _, 0 as _); +} + +#[clippy::msrv = "1.83"] +fn _msrv_1_83() { + // `{core, std}::ptr::dangling` was stabilized in 1.84. Do not lint this + foo(4 as *const _, 4 as *mut _); +} + +#[clippy::msrv = "1.84"] +fn _msrv_1_84() { + foo(4 as *const _, 4 as *mut _); + //~^ manual_dangling_ptr + //~| manual_dangling_ptr +} diff --git a/tests/ui/manual_dangling_ptr.stderr b/tests/ui/manual_dangling_ptr.stderr new file mode 100644 index 000000000000..e3bc9b16b0d9 --- /dev/null +++ b/tests/ui/manual_dangling_ptr.stderr @@ -0,0 +1,65 @@ +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:7:24 + | +LL | let _: *const u8 = 1 as *const _; + | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()` + | + = note: `-D clippy::manual-dangling-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_dangling_ptr)]` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:9:13 + | +LL | let _ = 2 as *const u32; + | ^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:11:13 + | +LL | let _ = 4 as *mut f32; + | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling_mut::()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:14:13 + | +LL | let _ = mem::align_of::() as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:16:13 + | +LL | let _ = mem::align_of::() as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:18:13 + | +LL | let _ = mem::align_of::() as *const usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:21:9 + | +LL | foo(4 as *const _, 4 as *mut _); + | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:21:24 + | +LL | foo(4 as *const _, 4 as *mut _); + | ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:41:9 + | +LL | foo(4 as *const _, 4 as *mut _); + | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()` + +error: manual creation of a dangling pointer + --> tests/ui/manual_dangling_ptr.rs:41:24 + | +LL | foo(4 as *const _, 4 as *mut _); + | ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/manual_find.rs b/tests/ui/manual_find.rs index 20b557f21d14..7b9846cfe429 100644 --- a/tests/ui/manual_find.rs +++ b/tests/ui/manual_find.rs @@ -23,4 +23,32 @@ fn tuple(arr: Vec<(String, i32)>) -> Option { None } +mod issue9521 { + fn condition(x: u32, y: u32) -> Result { + todo!() + } + + fn find_with_early_return(v: Vec) -> Option { + for x in v { + if condition(x, 10).ok()? { + return Some(x); + } + } + None + } + + fn find_with_early_break(v: Vec) -> Option { + for x in v { + if if x < 3 { + break; + } else { + x < 10 + } { + return Some(x); + } + } + None + } +} + fn main() {} diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed index c1c929585cfd..cd7adc20b127 100644 --- a/tests/ui/manual_ignore_case_cmp.fixed +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -1,5 +1,11 @@ -#![allow(clippy::all)] -#![deny(clippy::manual_ignore_case_cmp)] +#![warn(clippy::manual_ignore_case_cmp)] +#![allow( + clippy::deref_addrof, + clippy::op_ref, + clippy::ptr_arg, + clippy::short_circuit_statement, + clippy::unnecessary_operation +)] use std::ffi::{OsStr, OsString}; diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs index ca401e595fe9..85f6719827c9 100644 --- a/tests/ui/manual_ignore_case_cmp.rs +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -1,5 +1,11 @@ -#![allow(clippy::all)] -#![deny(clippy::manual_ignore_case_cmp)] +#![warn(clippy::manual_ignore_case_cmp)] +#![allow( + clippy::deref_addrof, + clippy::op_ref, + clippy::ptr_arg, + clippy::short_circuit_statement, + clippy::unnecessary_operation +)] use std::ffi::{OsStr, OsString}; diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr index 47378a65799f..fa7fadd91076 100644 --- a/tests/ui/manual_ignore_case_cmp.stderr +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -1,14 +1,11 @@ error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:9:8 + --> tests/ui/manual_ignore_case_cmp.rs:15:8 | LL | if a.to_ascii_lowercase() == b.to_ascii_lowercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/manual_ignore_case_cmp.rs:2:9 - | -LL | #![deny(clippy::manual_ignore_case_cmp)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::manual-ignore-case-cmp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_ignore_case_cmp)]` help: consider using `.eq_ignore_ascii_case()` instead | LL - if a.to_ascii_lowercase() == b.to_ascii_lowercase() { @@ -16,7 +13,7 @@ LL + if a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:13:8 + --> tests/ui/manual_ignore_case_cmp.rs:19:8 | LL | if a.to_ascii_uppercase() == b.to_ascii_uppercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +25,7 @@ LL + if a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:17:13 + --> tests/ui/manual_ignore_case_cmp.rs:23:13 | LL | let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +37,7 @@ LL + let r = a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:19:18 + --> tests/ui/manual_ignore_case_cmp.rs:25:18 | LL | let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +49,7 @@ LL + let r = r || a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:21:10 + --> tests/ui/manual_ignore_case_cmp.rs:27:10 | LL | r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +61,7 @@ LL + r && a.eq_ignore_ascii_case(&b.to_uppercase()); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:24:8 + --> tests/ui/manual_ignore_case_cmp.rs:30:8 | LL | if a.to_ascii_lowercase() != b.to_ascii_lowercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,7 +73,7 @@ LL + if !a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:28:8 + --> tests/ui/manual_ignore_case_cmp.rs:34:8 | LL | if a.to_ascii_uppercase() != b.to_ascii_uppercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +85,7 @@ LL + if !a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:32:13 + --> tests/ui/manual_ignore_case_cmp.rs:38:13 | LL | let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +97,7 @@ LL + let r = !a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:34:18 + --> tests/ui/manual_ignore_case_cmp.rs:40:18 | LL | let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +109,7 @@ LL + let r = r || !a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:36:10 + --> tests/ui/manual_ignore_case_cmp.rs:42:10 | LL | r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +121,7 @@ LL + r && !a.eq_ignore_ascii_case(&b.to_uppercase()); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:48:5 + --> tests/ui/manual_ignore_case_cmp.rs:54:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +133,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:52:5 + --> tests/ui/manual_ignore_case_cmp.rs:58:5 | LL | a.to_ascii_lowercase() == 'a'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +145,7 @@ LL + a.eq_ignore_ascii_case(&'a'); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:54:5 + --> tests/ui/manual_ignore_case_cmp.rs:60:5 | LL | 'a' == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +157,7 @@ LL + 'a'.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:58:5 + --> tests/ui/manual_ignore_case_cmp.rs:64:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +169,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:60:5 + --> tests/ui/manual_ignore_case_cmp.rs:66:5 | LL | a.to_ascii_lowercase() == b'a'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +181,7 @@ LL + a.eq_ignore_ascii_case(&b'a'); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:62:5 + --> tests/ui/manual_ignore_case_cmp.rs:68:5 | LL | b'a' == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +193,7 @@ LL + b'a'.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:66:5 + --> tests/ui/manual_ignore_case_cmp.rs:72:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +205,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:68:5 + --> tests/ui/manual_ignore_case_cmp.rs:74:5 | LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,57 +216,9 @@ LL - a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); LL + a.to_uppercase().eq_ignore_ascii_case(b); | -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:70:5 - | -LL | a.to_ascii_lowercase() == "a"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_ascii_lowercase() == "a"; -LL + a.eq_ignore_ascii_case("a"); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:72:5 - | -LL | "a" == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - "a" == b.to_ascii_lowercase(); -LL + "a".eq_ignore_ascii_case(b); - | - error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:76:5 | -LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.eq_ignore_ascii_case(b); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:78:5 - | -LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.to_uppercase().eq_ignore_ascii_case(b); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:80:5 - | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -280,7 +229,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:82:5 + --> tests/ui/manual_ignore_case_cmp.rs:78:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -291,9 +240,57 @@ LL - "a" == b.to_ascii_lowercase(); LL + "a".eq_ignore_ascii_case(b); | +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:82:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:84:5 + | +LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.to_uppercase().eq_ignore_ascii_case(b); + | + error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:86:5 | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == "a"; +LL + a.eq_ignore_ascii_case("a"); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:88:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - "a" == b.to_ascii_lowercase(); +LL + "a".eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:92:5 + | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -303,30 +300,6 @@ LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); LL + a.eq_ignore_ascii_case(&b); | -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:88:5 - | -LL | a.to_ascii_lowercase() == "a"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_ascii_lowercase() == "a"; -LL + a.eq_ignore_ascii_case("a"); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:90:5 - | -LL | "a" == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - "a" == b.to_ascii_lowercase(); -LL + "a".eq_ignore_ascii_case(&b); - | - error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:94:5 | @@ -354,18 +327,42 @@ LL + "a".eq_ignore_ascii_case(&b); error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:100:5 | -LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `.eq_ignore_ascii_case()` instead | -LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.eq_ignore_ascii_case(b); +LL - a.to_ascii_lowercase() == "a"; +LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:102:5 | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - "a" == b.to_ascii_lowercase(); +LL + "a".eq_ignore_ascii_case(&b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:106:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:108:5 + | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -376,7 +373,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:104:5 + --> tests/ui/manual_ignore_case_cmp.rs:110:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +385,7 @@ LL + "a".eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:107:5 + --> tests/ui/manual_ignore_case_cmp.rs:113:5 | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -399,81 +396,9 @@ LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); LL + b.eq_ignore_ascii_case(&a); | -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:109:5 - | -LL | b.to_ascii_lowercase() == "a"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - b.to_ascii_lowercase() == "a"; -LL + b.eq_ignore_ascii_case("a"); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:111:5 - | -LL | "a" == a.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - "a" == a.to_ascii_lowercase(); -LL + "a".eq_ignore_ascii_case(&a); - | - error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:115:5 | -LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.eq_ignore_ascii_case(b); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:117:5 - | -LL | a.to_ascii_lowercase() == "a"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - a.to_ascii_lowercase() == "a"; -LL + a.eq_ignore_ascii_case("a"); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:119:5 - | -LL | "a" == b.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - "a" == b.to_ascii_lowercase(); -LL + "a".eq_ignore_ascii_case(b); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:122:5 - | -LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider using `.eq_ignore_ascii_case()` instead - | -LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); -LL + b.eq_ignore_ascii_case(&a); - | - -error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:124:5 - | LL | b.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -484,7 +409,7 @@ LL + b.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:126:5 + --> tests/ui/manual_ignore_case_cmp.rs:117:5 | LL | "a" == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +421,7 @@ LL + "a".eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:130:5 + --> tests/ui/manual_ignore_case_cmp.rs:121:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,19 +433,67 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:134:5 + --> tests/ui/manual_ignore_case_cmp.rs:123:5 | -LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == "a"; +LL + a.eq_ignore_ascii_case("a"); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:125:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - "a" == b.to_ascii_lowercase(); +LL + "a".eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:128:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `.eq_ignore_ascii_case()` instead | -LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.eq_ignore_ascii_case(&b); +LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); +LL + b.eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:138:5 + --> tests/ui/manual_ignore_case_cmp.rs:130:5 + | +LL | b.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - b.to_ascii_lowercase() == "a"; +LL + b.eq_ignore_ascii_case("a"); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:132:5 + | +LL | "a" == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - "a" == a.to_ascii_lowercase(); +LL + "a".eq_ignore_ascii_case(&a); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:136:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -534,13 +507,13 @@ LL + a.eq_ignore_ascii_case(b); error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:140:5 | -LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `.eq_ignore_ascii_case()` instead | -LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); -LL + b.eq_ignore_ascii_case(&a); +LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison @@ -556,19 +529,19 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:148:5 + --> tests/ui/manual_ignore_case_cmp.rs:146:5 | -LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `.eq_ignore_ascii_case()` instead | -LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); -LL + a.eq_ignore_ascii_case(b); +LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); +LL + b.eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:152:5 + --> tests/ui/manual_ignore_case_cmp.rs:150:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -582,6 +555,30 @@ LL + a.eq_ignore_ascii_case(b); error: manual case-insensitive ASCII comparison --> tests/ui/manual_ignore_case_cmp.rs:154:5 | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:158:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - a.to_ascii_lowercase() == b.to_ascii_lowercase(); +LL + a.eq_ignore_ascii_case(b); + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:160:5 + | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed index 44f15d61f856..ec87fe217aee 100644 --- a/tests/ui/manual_inspect.fixed +++ b/tests/ui/manual_inspect.fixed @@ -1,5 +1,5 @@ +#![allow(clippy::no_effect, clippy::op_ref, clippy::uninlined_format_args)] #![warn(clippy::manual_inspect)] -#![allow(clippy::no_effect, clippy::op_ref)] fn main() { let _ = Some(0).inspect(|&x| { @@ -107,7 +107,7 @@ fn main() { let _ = || { let _x = x; }; - return; + return ; } println!("test"); }); @@ -185,3 +185,12 @@ fn main() { }); } } + +#[rustfmt::skip] +fn layout_check() { + if let Some(x) = Some(1).inspect(|&x| { println!("{x}"); //~ manual_inspect + // Do not collapse code into this comment + }) { + println!("{x}"); + } +} diff --git a/tests/ui/manual_inspect.rs b/tests/ui/manual_inspect.rs index d34f2abce6ae..e679636201e6 100644 --- a/tests/ui/manual_inspect.rs +++ b/tests/ui/manual_inspect.rs @@ -1,5 +1,5 @@ +#![allow(clippy::no_effect, clippy::op_ref, clippy::uninlined_format_args)] #![warn(clippy::manual_inspect)] -#![allow(clippy::no_effect, clippy::op_ref)] fn main() { let _ = Some(0).map(|x| { @@ -197,3 +197,12 @@ fn main() { }); } } + +#[rustfmt::skip] +fn layout_check() { + if let Some(x) = Some(1).map(|x| { println!("{x}"); //~ manual_inspect + // Do not collapse code into this comment + x }) { + println!("{x}"); + } +} diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr index 510325d2baaa..eb98f9f5995a 100644 --- a/tests/ui/manual_inspect.stderr +++ b/tests/ui/manual_inspect.stderr @@ -98,7 +98,7 @@ LL | if x.is_empty() { LL | let _ = || { LL ~ let _x = x; LL | }; -LL ~ return; +LL ~ return ; LL | } LL ~ println!("test"); | @@ -187,5 +187,18 @@ LL | LL ~ println!("{}", x); | -error: aborting due to 13 previous errors +error: using `map` over `inspect` + --> tests/ui/manual_inspect.rs:203:30 + | +LL | if let Some(x) = Some(1).map(|x| { println!("{x}"); + | ^^^ + | +help: try + | +LL ~ if let Some(x) = Some(1).inspect(|&x| { println!("{x}"); +LL | // Do not collapse code into this comment +LL ~ }) { + | + +error: aborting due to 14 previous errors diff --git a/tests/ui/manual_is_power_of_two.fixed b/tests/ui/manual_is_power_of_two.fixed index 6f29d76bd210..8a1ab785dfbf 100644 --- a/tests/ui/manual_is_power_of_two.fixed +++ b/tests/ui/manual_is_power_of_two.fixed @@ -1,4 +1,17 @@ #![warn(clippy::manual_is_power_of_two)] +#![allow(clippy::precedence)] + +macro_rules! binop { + ($a: expr, equal, $b: expr) => { + $a == $b + }; + ($a: expr, and, $b: expr) => { + $a & $b + }; + ($a: expr, minus, $b: expr) => { + $a - $b + }; +} fn main() { let a = 16_u64; @@ -7,6 +20,8 @@ fn main() { //~^ manual_is_power_of_two let _ = a.is_power_of_two(); //~^ manual_is_power_of_two + let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two // Test different orders of expression let _ = a.is_power_of_two(); @@ -23,4 +38,23 @@ fn main() { // is_power_of_two only works for unsigned integers let _ = b.count_ones() == 1; let _ = b & (b - 1) == 0; + + let i: i32 = 3; + let _ = (i as u32).is_power_of_two(); + //~^ manual_is_power_of_two + + let _ = binop!(a.count_ones(), equal, 1); + let _ = binop!(a, and, a - 1) == 0; + let _ = a & binop!(a, minus, 1) == 0; +} + +#[clippy::msrv = "1.31"] +const fn low_msrv(a: u32) -> bool { + a & (a - 1) == 0 +} + +#[clippy::msrv = "1.32"] +const fn high_msrv(a: u32) -> bool { + a.is_power_of_two() + //~^ manual_is_power_of_two } diff --git a/tests/ui/manual_is_power_of_two.rs b/tests/ui/manual_is_power_of_two.rs index 0c44d7a660b4..57a3b05e0336 100644 --- a/tests/ui/manual_is_power_of_two.rs +++ b/tests/ui/manual_is_power_of_two.rs @@ -1,10 +1,25 @@ #![warn(clippy::manual_is_power_of_two)] +#![allow(clippy::precedence)] + +macro_rules! binop { + ($a: expr, equal, $b: expr) => { + $a == $b + }; + ($a: expr, and, $b: expr) => { + $a & $b + }; + ($a: expr, minus, $b: expr) => { + $a - $b + }; +} fn main() { let a = 16_u64; let _ = a.count_ones() == 1; //~^ manual_is_power_of_two + let _ = u64::count_ones(a) == 1; + //~^ manual_is_power_of_two let _ = a & (a - 1) == 0; //~^ manual_is_power_of_two @@ -23,4 +38,23 @@ fn main() { // is_power_of_two only works for unsigned integers let _ = b.count_ones() == 1; let _ = b & (b - 1) == 0; + + let i: i32 = 3; + let _ = i as u32 & (i as u32 - 1) == 0; + //~^ manual_is_power_of_two + + let _ = binop!(a.count_ones(), equal, 1); + let _ = binop!(a, and, a - 1) == 0; + let _ = a & binop!(a, minus, 1) == 0; +} + +#[clippy::msrv = "1.31"] +const fn low_msrv(a: u32) -> bool { + a & (a - 1) == 0 +} + +#[clippy::msrv = "1.32"] +const fn high_msrv(a: u32) -> bool { + a & (a - 1) == 0 + //~^ manual_is_power_of_two } diff --git a/tests/ui/manual_is_power_of_two.stderr b/tests/ui/manual_is_power_of_two.stderr index ad12ee10565f..5781a093d5f2 100644 --- a/tests/ui/manual_is_power_of_two.stderr +++ b/tests/ui/manual_is_power_of_two.stderr @@ -1,5 +1,5 @@ error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:6:13 + --> tests/ui/manual_is_power_of_two.rs:19:13 | LL | let _ = a.count_ones() == 1; | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` @@ -8,34 +8,52 @@ LL | let _ = a.count_ones() == 1; = help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:8:13 + --> tests/ui/manual_is_power_of_two.rs:21:13 + | +LL | let _ = u64::count_ones(a) == 1; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:23:13 | LL | let _ = a & (a - 1) == 0; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:12:13 + --> tests/ui/manual_is_power_of_two.rs:27:13 | LL | let _ = 1 == a.count_ones(); | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:14:13 + --> tests/ui/manual_is_power_of_two.rs:29:13 | LL | let _ = (a - 1) & a == 0; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:16:13 + --> tests/ui/manual_is_power_of_two.rs:31:13 | LL | let _ = 0 == a & (a - 1); | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:18:13 + --> tests/ui/manual_is_power_of_two.rs:33:13 | LL | let _ = 0 == (a - 1) & a; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` -error: aborting due to 6 previous errors +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:43:13 + | +LL | let _ = i as u32 & (i as u32 - 1) == 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:58:5 + | +LL | a & (a - 1) == 0 + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 9 previous errors diff --git a/tests/ui/manual_map_option.rs b/tests/ui/manual_map_option.rs index 9477d0d795d2..40133748d459 100644 --- a/tests/ui/manual_map_option.rs +++ b/tests/ui/manual_map_option.rs @@ -101,7 +101,7 @@ fn main() { match &mut Some(String::new()) { //~^ manual_map - Some(ref x) => Some(x.len()), + &mut Some(ref x) => Some(x.len()), None => None, }; diff --git a/tests/ui/manual_map_option.stderr b/tests/ui/manual_map_option.stderr index 8f9bce4c265c..486379c1e5f3 100644 --- a/tests/ui/manual_map_option.stderr +++ b/tests/ui/manual_map_option.stderr @@ -127,7 +127,7 @@ error: manual implementation of `Option::map` | LL | / match &mut Some(String::new()) { LL | | -LL | | Some(ref x) => Some(x.len()), +LL | | &mut Some(ref x) => Some(x.len()), LL | | None => None, LL | | }; | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())` diff --git a/tests/ui/manual_map_option_2.fixed b/tests/ui/manual_map_option_2.fixed index d698cc74ea65..206c6d5d0776 100644 --- a/tests/ui/manual_map_option_2.fixed +++ b/tests/ui/manual_map_option_2.fixed @@ -115,7 +115,7 @@ mod with_type_coercion { fn with_fn_ret(s: &Option) -> Option<(String, &str)> { // Don't lint, `map` doesn't work as the return type is adjusted. match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, } } @@ -124,7 +124,7 @@ mod with_type_coercion { if true { // Don't lint, `map` doesn't work as the return type is adjusted. return match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, }; } @@ -136,7 +136,7 @@ mod with_type_coercion { let x: Option<(String, &'a str)>; x = { match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, } }; diff --git a/tests/ui/manual_map_option_2.rs b/tests/ui/manual_map_option_2.rs index 069c2381f6db..a47dc950760e 100644 --- a/tests/ui/manual_map_option_2.rs +++ b/tests/ui/manual_map_option_2.rs @@ -143,7 +143,7 @@ mod with_type_coercion { fn with_fn_ret(s: &Option) -> Option<(String, &str)> { // Don't lint, `map` doesn't work as the return type is adjusted. match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, } } @@ -152,7 +152,7 @@ mod with_type_coercion { if true { // Don't lint, `map` doesn't work as the return type is adjusted. return match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, }; } @@ -164,7 +164,7 @@ mod with_type_coercion { let x: Option<(String, &'a str)>; x = { match s { - Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }), None => None, } }; diff --git a/tests/ui/manual_ok_err.fixed b/tests/ui/manual_ok_err.fixed index bc169b64be9f..e6f799aa58d6 100644 --- a/tests/ui/manual_ok_err.fixed +++ b/tests/ui/manual_ok_err.fixed @@ -80,6 +80,11 @@ fn no_lint() { Ok(3) => None, Ok(v) => Some(v), }; + + let _ = match funcall() { + Ok(v @ 1..) => Some(v), + _ => None, + }; } const fn cf(x: Result) -> Option { diff --git a/tests/ui/manual_ok_err.rs b/tests/ui/manual_ok_err.rs index 03c730d4b4e4..972b2c41ee7a 100644 --- a/tests/ui/manual_ok_err.rs +++ b/tests/ui/manual_ok_err.rs @@ -116,6 +116,11 @@ fn no_lint() { Ok(3) => None, Ok(v) => Some(v), }; + + let _ = match funcall() { + Ok(v @ 1..) => Some(v), + _ => None, + }; } const fn cf(x: Result) -> Option { diff --git a/tests/ui/manual_ok_err.stderr b/tests/ui/manual_ok_err.stderr index 13fceacda107..040e170f397e 100644 --- a/tests/ui/manual_ok_err.stderr +++ b/tests/ui/manual_ok_err.stderr @@ -94,7 +94,7 @@ LL | | }; | |_____^ help: replace with: `(-S).ok()` error: manual implementation of `ok` - --> tests/ui/manual_ok_err.rs:132:12 + --> tests/ui/manual_ok_err.rs:137:12 | LL | } else if let Ok(n) = "1".parse::() { | ____________^ diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index ca8491131c06..016f520e216c 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,5 +1,5 @@ #![warn(clippy::manual_retain)] -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; fn main() { @@ -31,7 +31,7 @@ fn binary_heap_retain() { // Do lint, because we use pattern matching let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]); - tuples.retain(|(ref x, ref y)| *x == 0); + tuples.retain(|&(ref x, ref y)| *x == 0); //~^ manual_retain tuples.retain(|(x, y)| *x == 0); //~^ manual_retain @@ -99,7 +99,7 @@ fn btree_set_retain() { // Do lint, because we use pattern matching let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]); - tuples.retain(|(ref x, ref y)| *x == 0); + tuples.retain(|&(ref x, ref y)| *x == 0); //~^ manual_retain tuples.retain(|(x, y)| *x == 0); //~^ manual_retain @@ -166,7 +166,7 @@ fn hash_set_retain() { // Do lint, because we use pattern matching let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]); - tuples.retain(|(ref x, ref y)| *x == 0); + tuples.retain(|&(ref x, ref y)| *x == 0); //~^ manual_retain tuples.retain(|(x, y)| *x == 0); //~^ manual_retain @@ -220,7 +220,7 @@ fn vec_retain() { // Do lint, because we use pattern matching let mut tuples = vec![(0, 1), (1, 2), (2, 3)]; - tuples.retain(|(ref x, ref y)| *x == 0); + tuples.retain(|&(ref x, ref y)| *x == 0); //~^ manual_retain tuples.retain(|(x, y)| *x == 0); //~^ manual_retain diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index cd05a41f3f25..62f9b7b0595d 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,5 +1,5 @@ #![warn(clippy::manual_retain)] -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; fn main() { @@ -31,7 +31,7 @@ fn binary_heap_retain() { // Do lint, because we use pattern matching let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]); - tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); //~^ manual_retain @@ -103,7 +103,7 @@ fn btree_set_retain() { // Do lint, because we use pattern matching let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]); - tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); //~^ manual_retain @@ -174,7 +174,7 @@ fn hash_set_retain() { // Do lint, because we use pattern matching let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]); - tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); //~^ manual_retain @@ -228,7 +228,7 @@ fn vec_retain() { // Do lint, because we use pattern matching let mut tuples = vec![(0, 1), (1, 2), (2, 3)]; - tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); //~^ manual_retain diff --git a/tests/ui/manual_retain.stderr b/tests/ui/manual_retain.stderr index 2f81647dd8b7..e7d3e34b5d7d 100644 --- a/tests/ui/manual_retain.stderr +++ b/tests/ui/manual_retain.stderr @@ -22,8 +22,8 @@ LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().colle error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:34:5 | -LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` +LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:36:5 @@ -74,8 +74,8 @@ LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:106:5 | -LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` +LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:108:5 @@ -126,8 +126,8 @@ LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:177:5 | -LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` +LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:179:5 @@ -162,8 +162,8 @@ LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:231:5 | -LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` +LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` --> tests/ui/manual_retain.rs:233:5 diff --git a/tests/ui/manual_strip_fixable.fixed b/tests/ui/manual_strip_fixable.fixed index 75a3f1645de3..b59e3719d951 100644 --- a/tests/ui/manual_strip_fixable.fixed +++ b/tests/ui/manual_strip_fixable.fixed @@ -1,4 +1,5 @@ #![warn(clippy::manual_strip)] +#![allow(clippy::uninlined_format_args)] fn main() { let s = "abc"; diff --git a/tests/ui/manual_strip_fixable.rs b/tests/ui/manual_strip_fixable.rs index 5080068449e2..4fb3a9bf007f 100644 --- a/tests/ui/manual_strip_fixable.rs +++ b/tests/ui/manual_strip_fixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::manual_strip)] +#![allow(clippy::uninlined_format_args)] fn main() { let s = "abc"; diff --git a/tests/ui/manual_strip_fixable.stderr b/tests/ui/manual_strip_fixable.stderr index 1c276e5d8fdf..da8b0cd08f89 100644 --- a/tests/ui/manual_strip_fixable.stderr +++ b/tests/ui/manual_strip_fixable.stderr @@ -1,11 +1,11 @@ error: stripping a prefix manually - --> tests/ui/manual_strip_fixable.rs:7:24 + --> tests/ui/manual_strip_fixable.rs:8:24 | LL | let stripped = &s["ab".len()..]; | ^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip_fixable.rs:6:5 + --> tests/ui/manual_strip_fixable.rs:7:5 | LL | if s.starts_with("ab") { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,13 +19,13 @@ LL ~ println!("{stripped}{}", stripped); | error: stripping a suffix manually - --> tests/ui/manual_strip_fixable.rs:13:24 + --> tests/ui/manual_strip_fixable.rs:14:24 | LL | let stripped = &s[..s.len() - "bc".len()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the suffix was tested here - --> tests/ui/manual_strip_fixable.rs:12:5 + --> tests/ui/manual_strip_fixable.rs:13:5 | LL | if s.ends_with("bc") { | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 07e4bdd483a8..e12287a70939 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -18,11 +18,9 @@ fn option_unwrap_or() { // multiline case #[rustfmt::skip] - Some(1).unwrap_or({ - 42 + 42 - + 42 + 42 + 42 - + 42 + 42 + 42 - }); + Some(1).unwrap_or(42 + 42 + + 42 + 42 + 42 + + 42 + 42 + 42); // string case Some("Bob").unwrap_or("Alice"); @@ -125,11 +123,9 @@ fn result_unwrap_or() { // multiline case #[rustfmt::skip] - Ok::(1).unwrap_or({ - 42 + 42 - + 42 + 42 + 42 - + 42 + 42 + 42 - }); + Ok::(1).unwrap_or(42 + 42 + + 42 + 42 + 42 + + 42 + 42 + 42); // string case Ok::<&str, &str>("Bob").unwrap_or("Alice"); @@ -159,11 +155,7 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => s, }; - // could lint, but unused_variables takes care of it - match Ok::<&str, &str>("Alice") { - Ok(s) => s, - Err(s) => "Bob", - }; + Ok::<&str, &str>("Alice").unwrap_or("Bob"); Ok::(1).unwrap_or(42); @@ -250,4 +242,12 @@ mod issue_13018 { } } +fn implicit_deref(v: Vec) { + let _ = if let Some(s) = v.first() { s } else { "" }; +} + +fn allowed_manual_unwrap_or_zero() -> u32 { + Some(42).unwrap_or(0) +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index c88b6f95da68..53cffcab5b56 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -216,8 +216,8 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => s, }; - // could lint, but unused_variables takes care of it match Ok::<&str, &str>("Alice") { + //~^ manual_unwrap_or Ok(s) => s, Err(s) => "Bob", }; @@ -316,4 +316,17 @@ mod issue_13018 { } } +fn implicit_deref(v: Vec) { + let _ = if let Some(s) = v.first() { s } else { "" }; +} + +fn allowed_manual_unwrap_or_zero() -> u32 { + if let Some(x) = Some(42) { + //~^ manual_unwrap_or + x + } else { + 0 + } +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index a5deb55786e9..320e895fb823 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -44,11 +44,9 @@ LL | | }; | help: replace with | -LL ~ Some(1).unwrap_or({ -LL + 42 + 42 -LL + + 42 + 42 + 42 -LL + + 42 + 42 + 42 -LL ~ }); +LL ~ Some(1).unwrap_or(42 + 42 +LL + + 42 + 42 + 42 +LL ~ + 42 + 42 + 42); | error: this pattern reimplements `Option::unwrap_or` @@ -145,11 +143,9 @@ LL | | }; | help: replace with | -LL ~ Ok::(1).unwrap_or({ -LL + 42 + 42 -LL + + 42 + 42 + 42 -LL + + 42 + 42 + 42 -LL ~ }); +LL ~ Ok::(1).unwrap_or(42 + 42 +LL + + 42 + 42 + 42 +LL ~ + 42 + 42 + 42); | error: this pattern reimplements `Result::unwrap_or` @@ -162,6 +158,16 @@ LL | | Err(_) => "Alice", LL | | }; | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")` +error: this pattern reimplements `Result::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:219:5 + | +LL | / match Ok::<&str, &str>("Alice") { +LL | | +LL | | Ok(s) => s, +LL | | Err(s) => "Bob", +LL | | }; + | |_____^ help: replace with: `Ok::<&str, &str>("Alice").unwrap_or("Bob")` + error: this pattern reimplements `Result::unwrap_or` --> tests/ui/manual_unwrap_or.rs:225:5 | @@ -184,5 +190,16 @@ LL | | None => 0, LL | | }; | |_________^ help: replace with: `some_macro!().unwrap_or(0)` -error: aborting due to 16 previous errors +error: this pattern reimplements `Option::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:324:5 + | +LL | / if let Some(x) = Some(42) { +LL | | +LL | | x +LL | | } else { +LL | | 0 +LL | | } + | |_____^ help: replace with: `Some(42).unwrap_or(0)` + +error: aborting due to 18 previous errors diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index 832376fa5af1..9dae9fcae079 100644 --- a/tests/ui/manual_unwrap_or_default.fixed +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -1,5 +1,5 @@ #![warn(clippy::manual_unwrap_or_default)] -#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] +#![allow(clippy::unnecessary_literal_unwrap)] fn main() { let x: Option> = None; @@ -36,10 +36,12 @@ fn main() { // Issue #12531 unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { - match a { - // `*b` being correct depends on `a == Some(_)` - Some(_) => (*b).unwrap_or_default(), - _ => 0, + unsafe { + match a { + // `*b` being correct depends on `a == Some(_)` + Some(_) => (*b).unwrap_or_default(), + _ => 0, + } } } @@ -99,3 +101,8 @@ fn issue_12928() { let y = if let Some(Y(a, _)) = x { a } else { 0 }; let y = if let Some(Y(a, ..)) = x { a } else { 0 }; } + +// For symetry with `manual_unwrap_or` test +fn allowed_manual_unwrap_or_zero() -> u32 { + Some(42).unwrap_or_default() +} diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index bedb3f0af0f3..539d7a8bbae5 100644 --- a/tests/ui/manual_unwrap_or_default.rs +++ b/tests/ui/manual_unwrap_or_default.rs @@ -1,5 +1,5 @@ #![warn(clippy::manual_unwrap_or_default)] -#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] +#![allow(clippy::unnecessary_literal_unwrap)] fn main() { let x: Option> = None; @@ -68,14 +68,16 @@ fn main() { // Issue #12531 unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { - match a { - // `*b` being correct depends on `a == Some(_)` - Some(_) => match *b { - //~^ manual_unwrap_or_default - Some(v) => v, + unsafe { + match a { + // `*b` being correct depends on `a == Some(_)` + Some(_) => match *b { + //~^ manual_unwrap_or_default + Some(v) => v, + _ => 0, + }, _ => 0, - }, - _ => 0, + } } } @@ -135,3 +137,13 @@ fn issue_12928() { let y = if let Some(Y(a, _)) = x { a } else { 0 }; let y = if let Some(Y(a, ..)) = x { a } else { 0 }; } + +// For symetry with `manual_unwrap_or` test +fn allowed_manual_unwrap_or_zero() -> u32 { + if let Some(x) = Some(42) { + //~^ manual_unwrap_or_default + x + } else { + 0 + } +} diff --git a/tests/ui/manual_unwrap_or_default.stderr b/tests/ui/manual_unwrap_or_default.stderr index ca9aa159152e..e8f38a2e3899 100644 --- a/tests/ui/manual_unwrap_or_default.stderr +++ b/tests/ui/manual_unwrap_or_default.stderr @@ -76,15 +76,26 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:73:20 + --> tests/ui/manual_unwrap_or_default.rs:74:24 | -LL | Some(_) => match *b { - | ____________________^ +LL | Some(_) => match *b { + | ________________________^ LL | | -LL | | Some(v) => v, -LL | | _ => 0, -LL | | }, - | |_________^ help: replace it with: `(*b).unwrap_or_default()` +LL | | Some(v) => v, +LL | | _ => 0, +LL | | }, + | |_____________^ help: replace it with: `(*b).unwrap_or_default()` -error: aborting due to 8 previous errors +error: if let can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:143:5 + | +LL | / if let Some(x) = Some(42) { +LL | | +LL | | x +LL | | } else { +LL | | 0 +LL | | } + | |_____^ help: replace it with: `Some(42).unwrap_or_default()` + +error: aborting due to 9 previous errors diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed index 948fec970d86..f8379ed23c5b 100644 --- a/tests/ui/map_flatten_fixable.fixed +++ b/tests/ui/map_flatten_fixable.fixed @@ -1,10 +1,11 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::let_underscore_untyped)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::map_identity)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::unnecessary_wraps)] #![feature(result_flattening)] +#![allow( + clippy::let_underscore_untyped, + clippy::missing_docs_in_private_items, + clippy::map_identity, + clippy::redundant_closure, + clippy::unnecessary_wraps +)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs index 67a91ab94147..040a9ca85f64 100644 --- a/tests/ui/map_flatten_fixable.rs +++ b/tests/ui/map_flatten_fixable.rs @@ -1,10 +1,11 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::let_underscore_untyped)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::map_identity)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::unnecessary_wraps)] #![feature(result_flattening)] +#![allow( + clippy::let_underscore_untyped, + clippy::missing_docs_in_private_items, + clippy::map_identity, + clippy::redundant_closure, + clippy::unnecessary_wraps +)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten_fixable.stderr b/tests/ui/map_flatten_fixable.stderr index 05d4d9a6ad85..fe68eb7e4ab4 100644 --- a/tests/ui/map_flatten_fixable.stderr +++ b/tests/ui/map_flatten_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:16:47 + --> tests/ui/map_flatten_fixable.rs:17:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` @@ -8,43 +8,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:18:47 + --> tests/ui/map_flatten_fixable.rs:19:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:20:47 + --> tests/ui/map_flatten_fixable.rs:21:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:22:47 + --> tests/ui/map_flatten_fixable.rs:23:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:26:47 + --> tests/ui/map_flatten_fixable.rs:27:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:30:40 + --> tests/ui/map_flatten_fixable.rs:31:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten_fixable.rs:34:42 + --> tests/ui/map_flatten_fixable.rs:35:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:44:10 + --> tests/ui/map_flatten_fixable.rs:45:10 | LL | .map(|n| match n { | __________^ @@ -74,7 +74,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:65:10 + --> tests/ui/map_flatten_fixable.rs:66:10 | LL | .map(|_| { | __________^ diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs deleted file mode 100644 index f3174ec9734d..000000000000 --- a/tests/ui/match_on_vec_items.rs +++ /dev/null @@ -1,161 +0,0 @@ -#![warn(clippy::match_on_vec_items)] -#![allow(clippy::redundant_at_rest_pattern, clippy::useless_vec)] -//@no-rustfix -fn match_with_wildcard() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 1; - - // Lint, may panic - match arr[idx] { - //~^ match_on_vec_items - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Lint, may panic - match arr[range] { - //~^ match_on_vec_items - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} - -fn match_without_wildcard() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 2; - - // Lint, may panic - match arr[idx] { - //~^ match_on_vec_items - 0 => println!("0"), - 1 => println!("1"), - num => {}, - } - - // Lint, may panic - match arr[range] { - //~^ match_on_vec_items - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - [ref sub @ ..] => {}, - } -} - -fn match_wildcard_and_action() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Lint, may panic - match arr[idx] { - //~^ match_on_vec_items - 0 => println!("0"), - 1 => println!("1"), - _ => println!("Hello, World!"), - } - - // Lint, may panic - match arr[range] { - //~^ match_on_vec_items - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => println!("Hello, World!"), - } -} - -fn match_vec_ref() { - let arr = &vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Lint, may panic - match arr[idx] { - //~^ match_on_vec_items - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Lint, may panic - match arr[range] { - //~^ match_on_vec_items - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} - -fn match_with_get() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Ok - match arr.get(idx) { - Some(0) => println!("0"), - Some(1) => println!("1"), - _ => {}, - } - - // Ok - match arr.get(range) { - Some(&[0, 1]) => println!("0 1"), - Some(&[1, 2]) => println!("1 2"), - _ => {}, - } -} - -fn match_with_array() { - let arr = [0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Ok - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Ok - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} - -fn match_with_endless_range() { - let arr = vec![0, 1, 2, 3]; - let range = ..; - - // Ok - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - [0, 1, 2, 3] => println!("0, 1, 2, 3"), - _ => {}, - } - - // Ok - match arr[..] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - [0, 1, 2, 3] => println!("0, 1, 2, 3"), - _ => {}, - } -} - -fn main() { - match_with_wildcard(); - match_without_wildcard(); - match_wildcard_and_action(); - match_vec_ref(); - match_with_get(); - match_with_array(); - match_with_endless_range(); -} diff --git a/tests/ui/match_on_vec_items.stderr b/tests/ui/match_on_vec_items.stderr deleted file mode 100644 index ae79e1305f7f..000000000000 --- a/tests/ui/match_on_vec_items.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:10:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try: `arr.get(idx)` - | - = note: `-D clippy::match-on-vec-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::match_on_vec_items)]` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:18:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try: `arr.get(range)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:32:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try: `arr.get(idx)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:40:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try: `arr.get(range)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:54:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try: `arr.get(idx)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:62:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try: `arr.get(range)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:76:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try: `arr.get(idx)` - -error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:84:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try: `arr.get(range)` - -error: aborting due to 8 previous errors - diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 3a3eee4c958b..bdf39796ebfc 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -171,3 +171,20 @@ fn issue_10447() -> usize { 2 } + +fn issue14634() { + macro_rules! id { + ($i:ident) => { + $i + }; + } + dbg!(3); + println!("here"); + //~^^^ match_single_binding + let id!(a) = dbg!(3); + println!("found {a}"); + //~^^^ match_single_binding + let id!(b) = dbg!(3); + let id!(_a) = dbg!(b + 1); + //~^^^ match_single_binding +} diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index ada51254c6cd..419ff95d873b 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -229,3 +229,23 @@ fn issue_10447() -> usize { 2 } + +fn issue14634() { + macro_rules! id { + ($i:ident) => { + $i + }; + } + match dbg!(3) { + _ => println!("here"), + } + //~^^^ match_single_binding + match dbg!(3) { + id!(a) => println!("found {a}"), + } + //~^^^ match_single_binding + let id!(_a) = match dbg!(3) { + id!(b) => dbg!(b + 1), + }; + //~^^^ match_single_binding +} diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 7e1ec32dac2f..bdd0134a5f1c 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -336,5 +336,47 @@ LL | | _ => println!("1"), LL | | }, | |_________^ help: consider using the match body instead: `println!("1")` -error: aborting due to 24 previous errors +error: this match could be replaced by its scrutinee and body + --> tests/ui/match_single_binding.rs:239:5 + | +LL | / match dbg!(3) { +LL | | _ => println!("here"), +LL | | } + | |_____^ + | +help: consider using the scrutinee and body instead + | +LL ~ dbg!(3); +LL + println!("here"); + | + +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:243:5 + | +LL | / match dbg!(3) { +LL | | id!(a) => println!("found {a}"), +LL | | } + | |_____^ + | +help: consider using a `let` statement + | +LL ~ let id!(a) = dbg!(3); +LL + println!("found {a}"); + | + +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:247:5 + | +LL | / let id!(_a) = match dbg!(3) { +LL | | id!(b) => dbg!(b + 1), +LL | | }; + | |______^ + | +help: consider using a `let` statement + | +LL ~ let id!(b) = dbg!(3); +LL + let id!(_a) = dbg!(b + 1); + | + +error: aborting due to 27 previous errors diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 76b0d131dd41..2f4004181f6a 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,6 +1,5 @@ //@aux-build:option_helpers.rs -#![warn(clippy::all, clippy::pedantic)] #![allow( clippy::disallowed_names, clippy::default_trait_access, @@ -19,8 +18,7 @@ clippy::wrong_self_convention, clippy::unused_async, clippy::unused_self, - clippy::useless_vec, - unused + clippy::useless_vec )] #[macro_use] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 353b999d7da0..b226ce7c65da 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> tests/ui/methods.rs:104:5 + --> tests/ui/methods.rs:102:5 | LL | / fn new() -> i32 { LL | | @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods.rs:126:13 + --> tests/ui/methods.rs:124:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index f3eeb85f20ed..ee19d3ff7142 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![allow(clippy::manual_clamp)] use std::cmp::{max as my_max, max, min as my_min, min}; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index 84b4d3754552..87510a465a08 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,80 +1,79 @@ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:22:5 + --> tests/ui/min_max.rs:21:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::min-max` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::min_max)]` + = note: `#[deny(clippy::min_max)]` on by default error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:25:5 + --> tests/ui/min_max.rs:24:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:28:5 + --> tests/ui/min_max.rs:27:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:31:5 + --> tests/ui/min_max.rs:30:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:34:5 + --> tests/ui/min_max.rs:33:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:45:5 + --> tests/ui/min_max.rs:44:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:48:5 + --> tests/ui/min_max.rs:47:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:54:5 + --> tests/ui/min_max.rs:53:5 | LL | x.min(1).max(3); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:57:5 + --> tests/ui/min_max.rs:56:5 | LL | x.max(3).min(1); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:60:5 + --> tests/ui/min_max.rs:59:5 | LL | f.max(3f32).min(1f32); | ^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:67:5 + --> tests/ui/min_max.rs:66:5 | LL | max(x.min(1), 3); | ^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:72:5 + --> tests/ui/min_max.rs:71:5 | LL | s.max("Zoo").min("Apple"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:75:5 + --> tests/ui/min_max.rs:74:5 | LL | s.min("Apple").max("Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/misnamed_getters.fixed b/tests/ui/misnamed_getters.fixed index cada5307b1c8..bc123d1a40ba 100644 --- a/tests/ui/misnamed_getters.fixed +++ b/tests/ui/misnamed_getters.fixed @@ -54,63 +54,63 @@ impl B { unsafe fn a(&self) -> &u8 { //~^ misnamed_getters - &self.a + unsafe { &self.a } } unsafe fn a_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.a + unsafe { &mut self.a } } unsafe fn b(self) -> u8 { //~^ misnamed_getters - self.b + unsafe { self.b } } unsafe fn b_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.b + unsafe { &mut self.b } } unsafe fn c(&self) -> &u8 { - &self.b + unsafe { &self.b } } unsafe fn c_mut(&mut self) -> &mut u8 { - &mut self.a + unsafe { &mut self.a } } unsafe fn a_unchecked(&self) -> &u8 { //~^ misnamed_getters - &self.a + unsafe { &self.a } } unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.a + unsafe { &mut self.a } } unsafe fn b_unchecked(self) -> u8 { //~^ misnamed_getters - self.b + unsafe { self.b } } unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.b + unsafe { &mut self.b } } unsafe fn c_unchecked(&self) -> &u8 { - &self.b + unsafe { &self.b } } unsafe fn c_unchecked_mut(&mut self) -> &mut u8 { - &mut self.a + unsafe { &mut self.a } } } diff --git a/tests/ui/misnamed_getters.rs b/tests/ui/misnamed_getters.rs index f529c56b4717..6590101157c3 100644 --- a/tests/ui/misnamed_getters.rs +++ b/tests/ui/misnamed_getters.rs @@ -54,63 +54,63 @@ impl B { unsafe fn a(&self) -> &u8 { //~^ misnamed_getters - &self.b + unsafe { &self.b } } unsafe fn a_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.b + unsafe { &mut self.b } } unsafe fn b(self) -> u8 { //~^ misnamed_getters - self.a + unsafe { self.a } } unsafe fn b_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.a + unsafe { &mut self.a } } unsafe fn c(&self) -> &u8 { - &self.b + unsafe { &self.b } } unsafe fn c_mut(&mut self) -> &mut u8 { - &mut self.a + unsafe { &mut self.a } } unsafe fn a_unchecked(&self) -> &u8 { //~^ misnamed_getters - &self.b + unsafe { &self.b } } unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.b + unsafe { &mut self.b } } unsafe fn b_unchecked(self) -> u8 { //~^ misnamed_getters - self.a + unsafe { self.a } } unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { //~^ misnamed_getters - &mut self.a + unsafe { &mut self.a } } unsafe fn c_unchecked(&self) -> &u8 { - &self.b + unsafe { &self.b } } unsafe fn c_unchecked_mut(&mut self) -> &mut u8 { - &mut self.a + unsafe { &mut self.a } } } diff --git a/tests/ui/misnamed_getters.stderr b/tests/ui/misnamed_getters.stderr index 5dd1d75bcf6f..aaf21cecb925 100644 --- a/tests/ui/misnamed_getters.stderr +++ b/tests/ui/misnamed_getters.stderr @@ -73,8 +73,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn a(&self) -> &u8 { LL | | LL | | -LL | | &self.b - | | ------- help: consider using: `&self.a` +LL | | unsafe { &self.b } + | | ------- help: consider using: `&self.a` LL | | } | |_____^ @@ -84,8 +84,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn a_mut(&mut self) -> &mut u8 { LL | | LL | | -LL | | &mut self.b - | | ----------- help: consider using: `&mut self.a` +LL | | unsafe { &mut self.b } + | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ @@ -95,8 +95,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn b(self) -> u8 { LL | | LL | | -LL | | self.a - | | ------ help: consider using: `self.b` +LL | | unsafe { self.a } + | | ------ help: consider using: `self.b` LL | | } | |_____^ @@ -106,8 +106,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn b_mut(&mut self) -> &mut u8 { LL | | LL | | -LL | | &mut self.a - | | ----------- help: consider using: `&mut self.b` +LL | | unsafe { &mut self.a } + | | ----------- help: consider using: `&mut self.b` LL | | } | |_____^ @@ -117,8 +117,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn a_unchecked(&self) -> &u8 { LL | | LL | | -LL | | &self.b - | | ------- help: consider using: `&self.a` +LL | | unsafe { &self.b } + | | ------- help: consider using: `&self.a` LL | | } | |_____^ @@ -128,8 +128,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { LL | | LL | | -LL | | &mut self.b - | | ----------- help: consider using: `&mut self.a` +LL | | unsafe { &mut self.b } + | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ @@ -139,8 +139,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn b_unchecked(self) -> u8 { LL | | LL | | -LL | | self.a - | | ------ help: consider using: `self.b` +LL | | unsafe { self.a } + | | ------ help: consider using: `self.b` LL | | } | |_____^ @@ -150,8 +150,8 @@ error: getter function appears to return the wrong field LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { LL | | LL | | -LL | | &mut self.a - | | ----------- help: consider using: `&mut self.b` +LL | | unsafe { &mut self.a } + | | ----------- help: consider using: `&mut self.b` LL | | } | |_____^ diff --git a/tests/ui/misnamed_getters_2021.fixed b/tests/ui/misnamed_getters_2021.fixed new file mode 100644 index 000000000000..7112719a9f28 --- /dev/null +++ b/tests/ui/misnamed_getters_2021.fixed @@ -0,0 +1,24 @@ +//@edition: 2021 +#![allow(unused)] +#![allow(clippy::struct_field_names)] +#![warn(clippy::misnamed_getters)] + +// Edition 2021 specific check, where `unsafe` blocks are not required +// inside `unsafe fn`. + +union B { + a: u8, + b: u8, +} + +impl B { + unsafe fn a(&self) -> &u8 { + //~^ misnamed_getters + + &self.a + } +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/misnamed_getters_2021.rs b/tests/ui/misnamed_getters_2021.rs new file mode 100644 index 000000000000..19b5d086041f --- /dev/null +++ b/tests/ui/misnamed_getters_2021.rs @@ -0,0 +1,24 @@ +//@edition: 2021 +#![allow(unused)] +#![allow(clippy::struct_field_names)] +#![warn(clippy::misnamed_getters)] + +// Edition 2021 specific check, where `unsafe` blocks are not required +// inside `unsafe fn`. + +union B { + a: u8, + b: u8, +} + +impl B { + unsafe fn a(&self) -> &u8 { + //~^ misnamed_getters + + &self.b + } +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/misnamed_getters_2021.stderr b/tests/ui/misnamed_getters_2021.stderr new file mode 100644 index 000000000000..5495e2e3733f --- /dev/null +++ b/tests/ui/misnamed_getters_2021.stderr @@ -0,0 +1,16 @@ +error: getter function appears to return the wrong field + --> tests/ui/misnamed_getters_2021.rs:15:5 + | +LL | / unsafe fn a(&self) -> &u8 { +LL | | +LL | | +LL | | &self.b + | | ------- help: consider using: `&self.a` +LL | | } + | |_____^ + | + = note: `-D clippy::misnamed-getters` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/missing_asserts_for_indexing.fixed b/tests/ui/missing_asserts_for_indexing.fixed index 3bbafe0bba3f..9018f38100ef 100644 --- a/tests/ui/missing_asserts_for_indexing.fixed +++ b/tests/ui/missing_asserts_for_indexing.fixed @@ -139,4 +139,31 @@ fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { let _ = v4[0] + v4[1] + v4[2]; } +// ok +fn same_index_multiple_times(v1: &[u8]) { + let _ = v1[0] + v1[0]; +} + +// ok +fn highest_index_first(v1: &[u8]) { + let _ = v1[2] + v1[1] + v1[0]; +} + +fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { + assert!(v1.len() == 3); + assert_eq!(v2.len(), 4); + assert!(v3.len() == 3); + assert_eq!(4, v4.len()); + + let _ = v1[0] + v1[1] + v1[2]; + //~^ missing_asserts_for_indexing + + let _ = v2[0] + v2[1] + v2[2]; + + let _ = v3[0] + v3[1] + v3[2]; + //~^ missing_asserts_for_indexing + + let _ = v4[0] + v4[1] + v4[2]; +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing.rs b/tests/ui/missing_asserts_for_indexing.rs index f8ea0173c13f..44c5eddf3d8b 100644 --- a/tests/ui/missing_asserts_for_indexing.rs +++ b/tests/ui/missing_asserts_for_indexing.rs @@ -139,4 +139,31 @@ fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { let _ = v4[0] + v4[1] + v4[2]; } +// ok +fn same_index_multiple_times(v1: &[u8]) { + let _ = v1[0] + v1[0]; +} + +// ok +fn highest_index_first(v1: &[u8]) { + let _ = v1[2] + v1[1] + v1[0]; +} + +fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { + assert_eq!(v1.len(), 2); + assert_eq!(v2.len(), 4); + assert_eq!(2, v3.len()); + assert_eq!(4, v4.len()); + + let _ = v1[0] + v1[1] + v1[2]; + //~^ missing_asserts_for_indexing + + let _ = v2[0] + v2[1] + v2[2]; + + let _ = v3[0] + v3[1] + v3[2]; + //~^ missing_asserts_for_indexing + + let _ = v4[0] + v4[1] + v4[2]; +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing.stderr b/tests/ui/missing_asserts_for_indexing.stderr index 5d30920ccf52..b610de94b530 100644 --- a/tests/ui/missing_asserts_for_indexing.stderr +++ b/tests/ui/missing_asserts_for_indexing.stderr @@ -301,5 +301,57 @@ LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ = note: asserting the length before indexing will elide bounds checks -error: aborting due to 11 previous errors +error: indexing into a slice multiple times with an `assert` that does not cover the highest index + --> tests/ui/missing_asserts_for_indexing.rs:158:13 + | +LL | assert_eq!(v1.len(), 2); + | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` +... +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:158:13 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:158:21 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:158:29 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: indexing into a slice multiple times with an `assert` that does not cover the highest index + --> tests/ui/missing_asserts_for_indexing.rs:163:13 + | +LL | assert_eq!(2, v3.len()); + | ----------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` +... +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:163:13 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:163:21 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing.rs:163:29 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: aborting due to 13 previous errors diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index a520151a2dd9..eb98969efa47 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -73,4 +73,17 @@ pub fn issue11856(values: &[i32]) -> usize { ascending.len() } +fn assert_after_indexing(v1: &[u8]) { + let _ = v1[1] + v1[2]; + //~^ ERROR: indexing into a slice multiple times without an `assert` + assert!(v1.len() > 2); +} + +fn issue14255(v1: &[u8]) { + assert_ne!(v1.len(), 2); + + let _ = v1[0] + v1[1] + v1[2]; + //~^ missing_asserts_for_indexing +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index 24109b052a8a..a17ad0232138 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -180,5 +180,48 @@ LL | let _ = x[0] + x[1]; | ^^^^ = note: asserting the length before indexing will elide bounds checks -error: aborting due to 8 previous errors +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 + | +LL | let _ = v1[1] + v1[2]; + | ^^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 + | +LL | let _ = v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:21 + | +LL | let _ = v1[1] + v1[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: indexing into a slice multiple times without an `assert` + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:21 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:29 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: aborting due to 10 previous errors diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 10df44e73b85..65eb2d5938b6 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -144,7 +144,7 @@ mod msrv { #[clippy::msrv = "1.62"] mod with_extern { - const extern "C" fn c() {} + const unsafe extern "C" fn c() {} //~^ missing_const_for_fn #[rustfmt::skip] @@ -153,7 +153,7 @@ mod msrv { //~^ missing_const_for_fn // any item functions in extern block won't trigger this lint - extern "C" { + unsafe extern "C" { fn c_in_block(); } } diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index bc44b34daef7..3690d2f799ff 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -144,7 +144,7 @@ mod msrv { #[clippy::msrv = "1.62"] mod with_extern { - extern "C" fn c() {} + unsafe extern "C" fn c() {} //~^ missing_const_for_fn #[rustfmt::skip] @@ -153,7 +153,7 @@ mod msrv { //~^ missing_const_for_fn // any item functions in extern block won't trigger this lint - extern "C" { + unsafe extern "C" { fn c_in_block(); } } diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 5df5a54ff521..10e07d12f5a4 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -212,12 +212,12 @@ LL | const fn union_access_can_be_const() { error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:147:9 | -LL | extern "C" fn c() {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" fn c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `const` | -LL | const extern "C" fn c() {} +LL | const unsafe extern "C" fn c() {} | +++++ error: this could be a `const fn` diff --git a/tests/ui/missing_panics_doc.rs b/tests/ui/missing_panics_doc.rs index 95e361c5d555..ffdae8504f72 100644 --- a/tests/ui/missing_panics_doc.rs +++ b/tests/ui/missing_panics_doc.rs @@ -151,6 +151,45 @@ pub fn debug_assertions() { debug_assert_ne!(1, 2); } +pub fn partially_const(n: usize) { + //~^ missing_panics_doc + + const { + assert!(N > 5); + } + + assert!(N > n); +} + +pub fn expect_allow(i: Option) { + #[expect(clippy::missing_panics_doc)] + i.unwrap(); + + #[allow(clippy::missing_panics_doc)] + i.unwrap(); +} + +pub fn expect_allow_with_error(i: Option) { + //~^ missing_panics_doc + + #[expect(clippy::missing_panics_doc)] + i.unwrap(); + + #[allow(clippy::missing_panics_doc)] + i.unwrap(); + + i.unwrap(); +} + +pub fn expect_after_error(x: Option, y: Option) { + //~^ missing_panics_doc + + let x = x.unwrap(); + + #[expect(clippy::missing_panics_doc)] + let y = y.unwrap(); +} + // all function must be triggered the lint. // `pub` is required, because the lint does not consider unreachable items pub mod issue10240 { diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index a83e2fa367dd..7f0acf8de9b7 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -73,76 +73,112 @@ LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:157:5 + --> tests/ui/missing_panics_doc.rs:154:1 + | +LL | pub fn partially_const(n: usize) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:161:5 + | +LL | assert!(N > n); + | ^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:172:1 + | +LL | pub fn expect_allow_with_error(i: Option) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:181:5 + | +LL | i.unwrap(); + | ^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:184:1 + | +LL | pub fn expect_after_error(x: Option, y: Option) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:187:13 + | +LL | let x = x.unwrap(); + | ^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:196:5 | LL | pub fn option_unwrap(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:160:9 + --> tests/ui/missing_panics_doc.rs:199:9 | LL | o.unwrap() | ^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:163:5 + --> tests/ui/missing_panics_doc.rs:202:5 | LL | pub fn option_expect(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:166:9 + --> tests/ui/missing_panics_doc.rs:205:9 | LL | o.expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:169:5 + --> tests/ui/missing_panics_doc.rs:208:5 | LL | pub fn result_unwrap(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:172:9 + --> tests/ui/missing_panics_doc.rs:211:9 | LL | res.unwrap() | ^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:175:5 + --> tests/ui/missing_panics_doc.rs:214:5 | LL | pub fn result_expect(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:178:9 + --> tests/ui/missing_panics_doc.rs:217:9 | LL | res.expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:181:5 + --> tests/ui/missing_panics_doc.rs:220:5 | LL | pub fn last_unwrap(v: &[u32]) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:183:10 + --> tests/ui/missing_panics_doc.rs:222:10 | LL | *v.last().unwrap() | ^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:186:5 + --> tests/ui/missing_panics_doc.rs:225:5 | LL | pub fn last_expect(v: &[u32]) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:188:10 + --> tests/ui/missing_panics_doc.rs:227:10 | LL | *v.last().expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/missing_transmute_annotations.fixed b/tests/ui/missing_transmute_annotations.fixed index a3c94ab139ec..58faeaee09d4 100644 --- a/tests/ui/missing_transmute_annotations.fixed +++ b/tests/ui/missing_transmute_annotations.fixed @@ -18,8 +18,10 @@ fn bar(x: i32) -> i32 { } unsafe fn foo1() -> i32 { - // Should not warn! - std::mem::transmute([1u16, 2u16]) + unsafe { + // Should not warn! + std::mem::transmute([1u16, 2u16]) + } } // Should not warn! @@ -31,33 +33,35 @@ enum Foo { } unsafe fn foo2() -> i32 { - let mut i: i32 = 0; - i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations + unsafe { + let mut i: i32 = 0; + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations - let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); - //~^ ERROR: transmute used without annotations - bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); - //~^ ERROR: transmute used without annotations + let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations - i = local_bad_transmute!([1u16, 2u16]); + i = local_bad_transmute!([1u16, 2u16]); - // Should not warn. - i = bad_transmute!([1u16, 2u16]); + // Should not warn. + i = bad_transmute!([1u16, 2u16]); - i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]); - //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]); + //~^ ERROR: transmute used without annotations - i = std::mem::transmute::(Foo::A); - //~^ ERROR: transmute used without annotations + i = std::mem::transmute::(Foo::A); + //~^ ERROR: transmute used without annotations - i + i + } } fn main() { diff --git a/tests/ui/missing_transmute_annotations.rs b/tests/ui/missing_transmute_annotations.rs index c12e1b0f8d22..c9a4c5fa83b2 100644 --- a/tests/ui/missing_transmute_annotations.rs +++ b/tests/ui/missing_transmute_annotations.rs @@ -18,8 +18,10 @@ fn bar(x: i32) -> i32 { } unsafe fn foo1() -> i32 { - // Should not warn! - std::mem::transmute([1u16, 2u16]) + unsafe { + // Should not warn! + std::mem::transmute([1u16, 2u16]) + } } // Should not warn! @@ -31,33 +33,35 @@ enum Foo { } unsafe fn foo2() -> i32 { - let mut i: i32 = 0; - i = std::mem::transmute([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<_, _>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<_, i32>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations - i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); - //~^ ERROR: transmute used without annotations + unsafe { + let mut i: i32 = 0; + i = std::mem::transmute([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<_, _>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<_, i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations - let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); - //~^ ERROR: transmute used without annotations - bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); - //~^ ERROR: transmute used without annotations + let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations - i = local_bad_transmute!([1u16, 2u16]); + i = local_bad_transmute!([1u16, 2u16]); - // Should not warn. - i = bad_transmute!([1u16, 2u16]); + // Should not warn. + i = bad_transmute!([1u16, 2u16]); - i = std::mem::transmute([0i16, 0i16]); - //~^ ERROR: transmute used without annotations + i = std::mem::transmute([0i16, 0i16]); + //~^ ERROR: transmute used without annotations - i = std::mem::transmute(Foo::A); - //~^ ERROR: transmute used without annotations + i = std::mem::transmute(Foo::A); + //~^ ERROR: transmute used without annotations - i + i + } } fn main() { diff --git a/tests/ui/missing_transmute_annotations.stderr b/tests/ui/missing_transmute_annotations.stderr index 5903ed488ef1..63f7e28ee7dc 100644 --- a/tests/ui/missing_transmute_annotations.stderr +++ b/tests/ui/missing_transmute_annotations.stderr @@ -1,41 +1,41 @@ error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:35:19 + --> tests/ui/missing_transmute_annotations.rs:38:23 | -LL | i = std::mem::transmute([1u16, 2u16]); - | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | i = std::mem::transmute([1u16, 2u16]); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` | = note: `-D clippy::missing-transmute-annotations` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:37:19 + --> tests/ui/missing_transmute_annotations.rs:40:23 | -LL | i = std::mem::transmute::<_, _>([1u16, 2u16]); - | ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | i = std::mem::transmute::<_, _>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:39:19 + --> tests/ui/missing_transmute_annotations.rs:42:23 | -LL | i = std::mem::transmute::<_, i32>([1u16, 2u16]); - | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | i = std::mem::transmute::<_, i32>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:41:19 + --> tests/ui/missing_transmute_annotations.rs:44:23 | -LL | i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:44:32 + --> tests/ui/missing_transmute_annotations.rs:47:36 | -LL | let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:46:19 + --> tests/ui/missing_transmute_annotations.rs:49:23 | -LL | bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +LL | bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations --> tests/ui/missing_transmute_annotations.rs:11:19 @@ -43,31 +43,31 @@ error: transmute used without annotations LL | std::mem::transmute($e) | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` ... -LL | i = local_bad_transmute!([1u16, 2u16]); - | ---------------------------------- in this macro invocation +LL | i = local_bad_transmute!([1u16, 2u16]); + | ---------------------------------- in this macro invocation | = note: this error originates in the macro `local_bad_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:54:19 + --> tests/ui/missing_transmute_annotations.rs:57:23 | -LL | i = std::mem::transmute([0i16, 0i16]); - | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>` +LL | i = std::mem::transmute([0i16, 0i16]); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:57:19 + --> tests/ui/missing_transmute_annotations.rs:60:23 | -LL | i = std::mem::transmute(Foo::A); - | ^^^^^^^^^ help: consider adding missing annotations: `transmute::` +LL | i = std::mem::transmute(Foo::A); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:64:35 + --> tests/ui/missing_transmute_annotations.rs:68:35 | LL | let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) }; | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` error: transmute used without annotations - --> tests/ui/missing_transmute_annotations.rs:67:30 + --> tests/ui/missing_transmute_annotations.rs:71:30 | LL | let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]); | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index b5d356a50217..4c1d6b1ccb59 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -88,11 +88,13 @@ static mut COUNTER: usize = 0; /// /// Don't ever call this from multiple threads pub unsafe fn mutates_static() -> usize { - COUNTER += 1; - COUNTER + unsafe { + COUNTER += 1; + COUNTER + } } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn unmangled(i: bool) -> bool { !i } diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 14ea16662fdb..71d546718ae7 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -88,11 +88,13 @@ static mut COUNTER: usize = 0; /// /// Don't ever call this from multiple threads pub unsafe fn mutates_static() -> usize { - COUNTER += 1; - COUNTER + unsafe { + COUNTER += 1; + COUNTER + } } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn unmangled(i: bool) -> bool { !i } diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index b8c10f3eeb8f..1b0b351518cb 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,4 +1,10 @@ -#![allow(unused, clippy::needless_lifetimes, clippy::needless_pass_by_ref_mut)] +#![allow( + unused, + clippy::needless_lifetimes, + clippy::needless_pass_by_ref_mut, + clippy::redundant_allocation, + clippy::boxed_local +)] #![warn(clippy::mut_from_ref)] struct Foo; @@ -40,6 +46,18 @@ fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { unsafe { unimplemented!() } } +fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { + //~^ mut_from_ref + + unsafe { unimplemented!() } +} + +fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { + //~^ mut_from_ref + + unsafe { unimplemented!() } +} + // this is OK, because the result borrows y fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 { unsafe { unimplemented!() } @@ -50,6 +68,20 @@ fn also_works<'a>(x: &'a u32, y: &'a mut u32) -> &'a mut u32 { unsafe { unimplemented!() } } +fn works_tuples<'a>(x: (&'a u32, &'a mut u32)) -> &'a mut u32 { + unsafe { unimplemented!() } +} + +fn works_box<'a>(x: &'a u32, y: Box<&'a mut u32>) -> &'a mut u32 { + unsafe { unimplemented!() } +} + +struct RefMut<'a>(&'a mut u32); + +fn works_parameter<'a>(x: &'a u32, y: RefMut<'a>) -> &'a mut u32 { + unsafe { unimplemented!() } +} + unsafe fn also_broken(x: &u32) -> &mut u32 { //~^ mut_from_ref diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index 8c3c8e0c3d85..097426873465 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -1,11 +1,11 @@ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:7:39 + --> tests/ui/mut_from_ref.rs:13:39 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:7:29 + --> tests/ui/mut_from_ref.rs:13:29 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^ @@ -13,64 +13,88 @@ LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]` error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:15:25 + --> tests/ui/mut_from_ref.rs:21:25 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:15:16 + --> tests/ui/mut_from_ref.rs:21:16 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:25:21 + --> tests/ui/mut_from_ref.rs:31:21 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:25:12 + --> tests/ui/mut_from_ref.rs:31:12 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:31:50 + --> tests/ui/mut_from_ref.rs:37:50 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:31:25 + --> tests/ui/mut_from_ref.rs:37:25 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:37:67 + --> tests/ui/mut_from_ref.rs:43:67 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:37:27 + --> tests/ui/mut_from_ref.rs:43:27 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:53:35 + --> tests/ui/mut_from_ref.rs:49:46 + | +LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { + | ^^^^^^^^^^^ + | +note: immutable borrow here + --> tests/ui/mut_from_ref.rs:49:24 + | +LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { + | ^^^^^^^ ^^^^^^^ + +error: mutable borrow from immutable input(s) + --> tests/ui/mut_from_ref.rs:55:37 + | +LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { + | ^^^^^^^^^^^ + | +note: immutable borrow here + --> tests/ui/mut_from_ref.rs:55:24 + | +LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { + | ^^^^^^^ + +error: mutable borrow from immutable input(s) + --> tests/ui/mut_from_ref.rs:85:35 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:53:26 + --> tests/ui/mut_from_ref.rs:85:26 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 80a712a9286a..7db5c9f274f6 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![warn(clippy::mutex_integer)] #![warn(clippy::mutex_atomic)] #![allow(clippy::borrow_as_ptr)] diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 838fc1d7c36e..a6d5d60fbf05 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -1,5 +1,5 @@ error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:8:5 + --> tests/ui/mutex_atomic.rs:7:5 | LL | Mutex::new(true); | ^^^^^^^^^^^^^^^^ @@ -8,31 +8,31 @@ LL | Mutex::new(true); = help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]` error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:11:5 + --> tests/ui/mutex_atomic.rs:10:5 | LL | Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:14:5 + --> tests/ui/mutex_atomic.rs:13:5 | LL | Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:18:5 + --> tests/ui/mutex_atomic.rs:17:5 | LL | Mutex::new(&x as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:21:5 + --> tests/ui/mutex_atomic.rs:20:5 | LL | Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:24:5 + --> tests/ui/mutex_atomic.rs:23:5 | LL | Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ @@ -41,31 +41,31 @@ LL | Mutex::new(0u32); = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]` error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:27:5 + --> tests/ui/mutex_atomic.rs:26:5 | LL | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:31:5 + --> tests/ui/mutex_atomic.rs:30:5 | LL | Mutex::new(0u8); | ^^^^^^^^^^^^^^^ error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:34:5 + --> tests/ui/mutex_atomic.rs:33:5 | LL | Mutex::new(0i16); | ^^^^^^^^^^^^^^^^ error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:37:25 + --> tests/ui/mutex_atomic.rs:36:25 | LL | let _x: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:41:5 + --> tests/ui/mutex_atomic.rs:40:5 | LL | Mutex::new(X); | ^^^^^^^^^^^^^ diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index e4504bc2784c..84924cac62d5 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -89,7 +89,7 @@ fn should_not_lint( tuple_struct: TupleStruct, s: Struct, ) { - if let [ref a] = slice {} + if let [a] = slice {} if let &[ref a, b] = slice {} if let &[ref a, .., b] = slice {} diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 7edfda60b979..280cef43340c 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -89,7 +89,7 @@ fn should_not_lint( tuple_struct: TupleStruct, s: Struct, ) { - if let [ref a] = slice {} + if let [a] = slice {} if let &[ref a, b] = slice {} if let &[ref a, .., b] = slice {} diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 6551fa56b42c..b09efe9888f5 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -126,3 +126,87 @@ fn main() { fn foo(_: impl IntoIterator) {} fn bar>(_: Vec, _: I) {} fn baz>(_: I, _: (), _: impl IntoIterator) {} + +mod issue9191 { + use std::cell::Cell; + use std::collections::HashSet; + use std::hash::Hash; + use std::marker::PhantomData; + use std::ops::Deref; + + fn captures_ref_mut(xs: Vec, mut ys: HashSet) { + if xs.iter().map(|x| ys.remove(x)).collect::>().contains(&true) { + todo!() + } + } + + #[derive(Debug, Clone)] + struct MyRef<'a>(PhantomData<&'a mut Cell>>, *mut Cell>); + + impl MyRef<'_> { + fn new(target: &mut Cell>) -> Self { + MyRef(PhantomData, target) + } + + fn get(&mut self) -> &mut Cell> { + unsafe { &mut *self.1 } + } + } + + fn captures_phantom(xs: Vec, mut ys: Cell>) { + let mut ys_ref = MyRef::new(&mut ys); + if xs + .iter() + .map({ + let mut ys_ref = ys_ref.clone(); + move |x| ys_ref.get().get_mut().remove(x) + }) + .collect::>() + .contains(&true) + { + todo!() + } + } +} + +pub fn issue8055(v: impl IntoIterator) -> Result, usize> { + let mut zeros = 0; + + let res: Vec<_> = v + .into_iter() + .filter(|i| { + if *i == 0 { + zeros += 1 + }; + *i != 0 + }) + .collect(); + + if zeros != 0 { + return Err(zeros); + } + Ok(res.into_iter()) +} + +mod issue8055_regression { + struct Foo { + inner: T, + marker: core::marker::PhantomData, + } + + impl Iterator for Foo { + type Item = T::Item; + fn next(&mut self) -> Option { + self.inner.next() + } + } + + fn foo() { + Foo { + inner: [].iter(), + marker: core::marker::PhantomData, + } + .collect::>() + .len(); + } +} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 973c41c68754..da4182966bb1 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -126,3 +126,87 @@ fn main() { fn foo(_: impl IntoIterator) {} fn bar>(_: Vec, _: I) {} fn baz>(_: I, _: (), _: impl IntoIterator) {} + +mod issue9191 { + use std::cell::Cell; + use std::collections::HashSet; + use std::hash::Hash; + use std::marker::PhantomData; + use std::ops::Deref; + + fn captures_ref_mut(xs: Vec, mut ys: HashSet) { + if xs.iter().map(|x| ys.remove(x)).collect::>().contains(&true) { + todo!() + } + } + + #[derive(Debug, Clone)] + struct MyRef<'a>(PhantomData<&'a mut Cell>>, *mut Cell>); + + impl MyRef<'_> { + fn new(target: &mut Cell>) -> Self { + MyRef(PhantomData, target) + } + + fn get(&mut self) -> &mut Cell> { + unsafe { &mut *self.1 } + } + } + + fn captures_phantom(xs: Vec, mut ys: Cell>) { + let mut ys_ref = MyRef::new(&mut ys); + if xs + .iter() + .map({ + let mut ys_ref = ys_ref.clone(); + move |x| ys_ref.get().get_mut().remove(x) + }) + .collect::>() + .contains(&true) + { + todo!() + } + } +} + +pub fn issue8055(v: impl IntoIterator) -> Result, usize> { + let mut zeros = 0; + + let res: Vec<_> = v + .into_iter() + .filter(|i| { + if *i == 0 { + zeros += 1 + }; + *i != 0 + }) + .collect(); + + if zeros != 0 { + return Err(zeros); + } + Ok(res.into_iter()) +} + +mod issue8055_regression { + struct Foo { + inner: T, + marker: core::marker::PhantomData, + } + + impl Iterator for Foo { + type Item = T::Item; + fn next(&mut self) -> Option { + self.inner.next() + } + } + + fn foo() { + Foo { + inner: [].iter(), + marker: core::marker::PhantomData, + } + .collect::>() + .len(); + } +} diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index d59393fb3f3c..e9d811986aa4 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -534,4 +534,11 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +pub fn issue14607<'s>(x: &'s u8) { + #[expect(clippy::redundant_closure_call)] + (|| { + let _: &'s u8 = x; + })(); +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index e24907ab5fcd..0b6eb9755b93 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -534,4 +534,11 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +pub fn issue14607<'s>(x: &'s u8) { + #[expect(clippy::redundant_closure_call)] + (|| { + let _: &'s u8 = x; + })(); +} + fn main() {} diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index f0c5a716ac99..bdad3e3d5b00 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -1,8 +1,9 @@ #![allow( clippy::if_same_then_else, clippy::no_effect, + clippy::ptr_arg, clippy::redundant_closure_call, - clippy::ptr_arg + clippy::uninlined_format_args )] #![warn(clippy::needless_pass_by_ref_mut)] //@no-rustfix @@ -300,7 +301,7 @@ struct Data { } // Unsafe functions should not warn. unsafe fn get_mut_unchecked(ptr: &mut NonNull>) -> &mut T { - &mut (*ptr.as_ptr()).value + unsafe { &mut (*ptr.as_ptr()).value } } // Unsafe blocks should not warn. fn get_mut_unchecked2(ptr: &mut NonNull>) -> &mut T { diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 6637a255b5f5..94d98f0e9b12 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:11:11 + --> tests/ui/needless_pass_by_ref_mut.rs:12:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:37:12 + --> tests/ui/needless_pass_by_ref_mut.rs:38:12 | LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:48:12 + --> tests/ui/needless_pass_by_ref_mut.rs:49:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:51:29 + --> tests/ui/needless_pass_by_ref_mut.rs:52:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:129:16 + --> tests/ui/needless_pass_by_ref_mut.rs:130:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:134:16 + --> tests/ui/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:139:16 + --> tests/ui/needless_pass_by_ref_mut.rs:140:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:144:16 + --> tests/ui/needless_pass_by_ref_mut.rs:145:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:149:24 + --> tests/ui/needless_pass_by_ref_mut.rs:150:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:154:24 + --> tests/ui/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:159:32 + --> tests/ui/needless_pass_by_ref_mut.rs:160:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:164:24 + --> tests/ui/needless_pass_by_ref_mut.rs:165:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:164:45 + --> tests/ui/needless_pass_by_ref_mut.rs:165:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:200:16 + --> tests/ui/needless_pass_by_ref_mut.rs:201:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:205:20 + --> tests/ui/needless_pass_by_ref_mut.rs:206:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,115 +96,115 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:218:39 + --> tests/ui/needless_pass_by_ref_mut.rs:219:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:227:26 + --> tests/ui/needless_pass_by_ref_mut.rs:228:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:247:30 + --> tests/ui/needless_pass_by_ref_mut.rs:248:30 | LL | async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:267:16 + --> tests/ui/needless_pass_by_ref_mut.rs:268:16 | LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:279:22 + --> tests/ui/needless_pass_by_ref_mut.rs:280:22 | LL | async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:334:12 + --> tests/ui/needless_pass_by_ref_mut.rs:335:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:337:18 + --> tests/ui/needless_pass_by_ref_mut.rs:338:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:337:45 + --> tests/ui/needless_pass_by_ref_mut.rs:338:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:346:46 + --> tests/ui/needless_pass_by_ref_mut.rs:347:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:363:18 + --> tests/ui/needless_pass_by_ref_mut.rs:364:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:365:19 + --> tests/ui/needless_pass_by_ref_mut.rs:366:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:367:18 + --> tests/ui/needless_pass_by_ref_mut.rs:368:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:369:11 + --> tests/ui/needless_pass_by_ref_mut.rs:370:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:372:23 + --> tests/ui/needless_pass_by_ref_mut.rs:373:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:374:20 + --> tests/ui/needless_pass_by_ref_mut.rs:375:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:376:18 + --> tests/ui/needless_pass_by_ref_mut.rs:377:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:378:25 + --> tests/ui/needless_pass_by_ref_mut.rs:379:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:380:20 + --> tests/ui/needless_pass_by_ref_mut.rs:381:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:382:20 + --> tests/ui/needless_pass_by_ref_mut.rs:383:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` diff --git a/tests/ui/needless_pass_by_ref_mut_2021.rs b/tests/ui/needless_pass_by_ref_mut_2021.rs new file mode 100644 index 000000000000..994eba9cae3d --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut_2021.rs @@ -0,0 +1,12 @@ +//@edition: 2021 +//@check-pass +#![warn(clippy::needless_pass_by_ref_mut)] + +struct Data { + value: T, +} + +// Unsafe functions should not warn. +unsafe fn get_mut_unchecked(ptr: &mut std::ptr::NonNull>) -> &mut T { + &mut (*ptr.as_ptr()).value +} diff --git a/tests/ui/neg_multiply.fixed b/tests/ui/neg_multiply.fixed index 995470493bfb..ff6e08300e29 100644 --- a/tests/ui/neg_multiply.fixed +++ b/tests/ui/neg_multiply.fixed @@ -53,3 +53,32 @@ fn main() { X * -1; // should be ok -1 * X; // should also be ok } + +fn float() { + let x = 0.0; + + -x; + //~^ neg_multiply + + -x; + //~^ neg_multiply + + 100.0 + -x; + //~^ neg_multiply + + -(100.0 + x); + //~^ neg_multiply + + -17.0; + //~^ neg_multiply + + 0.0 + -0.0; + //~^ neg_multiply + + -(3.0_f32 as f64); + //~^ neg_multiply + -(3.0_f32 as f64); + //~^ neg_multiply + + -1.0 * -1.0; // should be ok +} diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 95b94e29517f..b0f4e85c78e5 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -53,3 +53,32 @@ fn main() { X * -1; // should be ok -1 * X; // should also be ok } + +fn float() { + let x = 0.0; + + x * -1.0; + //~^ neg_multiply + + -1.0 * x; + //~^ neg_multiply + + 100.0 + x * -1.0; + //~^ neg_multiply + + (100.0 + x) * -1.0; + //~^ neg_multiply + + -1.0 * 17.0; + //~^ neg_multiply + + 0.0 + 0.0 * -1.0; + //~^ neg_multiply + + 3.0_f32 as f64 * -1.0; + //~^ neg_multiply + (3.0_f32 as f64) * -1.0; + //~^ neg_multiply + + -1.0 * -1.0; // should be ok +} diff --git a/tests/ui/neg_multiply.stderr b/tests/ui/neg_multiply.stderr index 9efa5d3ba1f1..2ef7e32ce05e 100644 --- a/tests/ui/neg_multiply.stderr +++ b/tests/ui/neg_multiply.stderr @@ -49,5 +49,53 @@ error: this multiplication by -1 can be written more succinctly LL | (3_usize as i32) * -1; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` -error: aborting due to 8 previous errors +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:60:5 + | +LL | x * -1.0; + | ^^^^^^^^ help: consider using: `-x` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:63:5 + | +LL | -1.0 * x; + | ^^^^^^^^ help: consider using: `-x` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:66:13 + | +LL | 100.0 + x * -1.0; + | ^^^^^^^^ help: consider using: `-x` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:69:5 + | +LL | (100.0 + x) * -1.0; + | ^^^^^^^^^^^^^^^^^^ help: consider using: `-(100.0 + x)` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:72:5 + | +LL | -1.0 * 17.0; + | ^^^^^^^^^^^ help: consider using: `-17.0` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:75:11 + | +LL | 0.0 + 0.0 * -1.0; + | ^^^^^^^^^^ help: consider using: `-0.0` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:78:5 + | +LL | 3.0_f32 as f64 * -1.0; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3.0_f32 as f64)` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:80:5 + | +LL | (3.0_f32 as f64) * -1.0; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3.0_f32 as f64)` + +error: aborting due to 16 previous errors diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs index 0d09b3ceecde..f4248ffc0f4d 100644 --- a/tests/ui/no_mangle_with_rust_abi.rs +++ b/tests/ui/no_mangle_with_rust_abi.rs @@ -43,7 +43,7 @@ extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} -extern "C" { +unsafe extern "C" { fn c_abi_in_block(arg_one: u32, arg_two: usize); } diff --git a/tests/ui/non_canonical_partial_ord_impl.fixed b/tests/ui/non_canonical_partial_ord_impl.fixed index 8774c666db11..23dbee5a0848 100644 --- a/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/tests/ui/non_canonical_partial_ord_impl.fixed @@ -162,3 +162,36 @@ impl PartialOrd for I { return Some(self.cmp(other)); } } + +// #13640, do not lint + +#[derive(Eq, PartialEq)] +struct J(u32); + +impl Ord for J { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for J { + fn partial_cmp(&self, other: &Self) -> Option { + self.cmp(other).into() + } +} + +// #13640, check that a simple `.into()` does not obliterate the lint + +#[derive(Eq, PartialEq)] +struct K(u32); + +impl Ord for K { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for K { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} diff --git a/tests/ui/non_canonical_partial_ord_impl.rs b/tests/ui/non_canonical_partial_ord_impl.rs index 568b97c8fff7..12f055a542b8 100644 --- a/tests/ui/non_canonical_partial_ord_impl.rs +++ b/tests/ui/non_canonical_partial_ord_impl.rs @@ -166,3 +166,38 @@ impl PartialOrd for I { return Some(self.cmp(other)); } } + +// #13640, do not lint + +#[derive(Eq, PartialEq)] +struct J(u32); + +impl Ord for J { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for J { + fn partial_cmp(&self, other: &Self) -> Option { + self.cmp(other).into() + } +} + +// #13640, check that a simple `.into()` does not obliterate the lint + +#[derive(Eq, PartialEq)] +struct K(u32); + +impl Ord for K { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for K { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option { + Ordering::Greater.into() + } +} diff --git a/tests/ui/non_canonical_partial_ord_impl.stderr b/tests/ui/non_canonical_partial_ord_impl.stderr index 86845df4ea90..c7de968588f8 100644 --- a/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/tests/ui/non_canonical_partial_ord_impl.stderr @@ -31,5 +31,18 @@ LL - fn partial_cmp(&self, _: &Self) -> Option { LL + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } | -error: aborting due to 2 previous errors +error: non-canonical implementation of `partial_cmp` on an `Ord` type + --> tests/ui/non_canonical_partial_ord_impl.rs:198:1 + | +LL | / impl PartialOrd for K { +LL | | +LL | | fn partial_cmp(&self, other: &Self) -> Option { + | | _____________________________________________________________- +LL | || Ordering::Greater.into() +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(other)) }` +LL | | } + | |__^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index b772c754f8b7..3f34dff563d2 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,5 +1,4 @@ -#![warn(clippy::all)] -#![allow(unused, clippy::println_empty_string, non_snake_case, clippy::let_unit_value)] +#![allow(clippy::println_empty_string, non_snake_case, clippy::let_unit_value)] #[derive(Clone, Debug)] enum MaybeInst { diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 3bd77a730fe7..11b12d2c5f10 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,5 +1,5 @@ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:28:9 + --> tests/ui/non_expressive_names.rs:27:9 | LL | let _1 = 1; | ^^ @@ -8,31 +8,31 @@ LL | let _1 = 1; = help: to override `-D warnings` add `#[allow(clippy::just_underscores_and_digits)]` error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:30:9 + --> tests/ui/non_expressive_names.rs:29:9 | LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:32:9 + --> tests/ui/non_expressive_names.rs:31:9 | LL | let __1___2 = 12; | ^^^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:54:13 + --> tests/ui/non_expressive_names.rs:53:13 | LL | let _1 = 1; | ^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:56:13 + --> tests/ui/non_expressive_names.rs:55:13 | LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:58:13 + --> tests/ui/non_expressive_names.rs:57:13 | LL | let __1___2 = 12; | ^^^^^^^ diff --git a/tests/ui/non_send_fields_in_send_ty.rs b/tests/ui/non_send_fields_in_send_ty.rs index 046ea70b08f1..31778f745098 100644 --- a/tests/ui/non_send_fields_in_send_ty.rs +++ b/tests/ui/non_send_fields_in_send_ty.rs @@ -35,7 +35,7 @@ unsafe impl Send for ArcGuard {} //~^ ERROR: some fields in `ArcGuard` are not safe to be sent to another thread // rusb / RUSTSEC-2020-0098 -extern "C" { +unsafe extern "C" { type libusb_device_handle; } @@ -90,7 +90,7 @@ unsafe impl Send for MultiParam {} //~^ ERROR: some fields in `MultiParam` are not safe to be sent to another thread // Tests for raw pointer heuristic -extern "C" { +unsafe extern "C" { type NonSend; } diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed index f7c56b6fffe8..2b30c8f984eb 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed @@ -9,16 +9,16 @@ use once_cell::sync::Lazy; fn main() {} static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); -//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +//~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| { - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library let x = "bar"; x.to_uppercase() }); static LAZY_BAZ: std::sync::LazyLock = { std::sync::LazyLock::new(|| "baz".to_uppercase()) }; -//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +//~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_QUX: std::sync::LazyLock = { - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library if "qux".len() == 3 { std::sync::LazyLock::new(|| "qux".to_uppercase()) } else if "qux".is_ascii() { @@ -39,11 +39,11 @@ mod once_cell_lazy_with_fns { use once_cell::sync::Lazy; static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "bar".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static mut LAZY_BAZ: std::sync::LazyLock = std::sync::LazyLock::new(|| "baz".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library fn calling_replaceable_fns() { let _ = std::sync::LazyLock::force(&LAZY_FOO); diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs index 90bc428137ce..c52338eee83c 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs @@ -9,16 +9,16 @@ use once_cell::sync::Lazy; fn main() {} static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); -//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +//~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_BAR: Lazy = Lazy::new(|| { - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library let x = "bar"; x.to_uppercase() }); static LAZY_BAZ: Lazy = { Lazy::new(|| "baz".to_uppercase()) }; -//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +//~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_QUX: Lazy = { - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library if "qux".len() == 3 { Lazy::new(|| "qux".to_uppercase()) } else if "qux".is_ascii() { @@ -39,11 +39,11 @@ mod once_cell_lazy_with_fns { use once_cell::sync::Lazy; static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library fn calling_replaceable_fns() { let _ = Lazy::force(&LAZY_FOO); diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr index 333052ae1c11..bb80cd11c719 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr @@ -1,4 +1,4 @@ -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:11:18 | LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); @@ -12,7 +12,7 @@ LL - static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); LL + static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:13:18 | LL | static LAZY_BAR: Lazy = Lazy::new(|| { @@ -24,7 +24,7 @@ LL - static LAZY_BAR: Lazy = Lazy::new(|| { LL + static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| { | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:18:18 | LL | static LAZY_BAZ: Lazy = { Lazy::new(|| "baz".to_uppercase()) }; @@ -36,7 +36,7 @@ LL - static LAZY_BAZ: Lazy = { Lazy::new(|| "baz".to_uppercase()) }; LL + static LAZY_BAZ: std::sync::LazyLock = { std::sync::LazyLock::new(|| "baz".to_uppercase()) }; | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:20:18 | LL | static LAZY_QUX: Lazy = { @@ -54,7 +54,7 @@ LL | } else { LL ~ std::sync::LazyLock::new(|| "qux".to_string()) | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:41:22 | LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); @@ -69,7 +69,7 @@ LL | fn calling_replaceable_fns() { LL ~ let _ = std::sync::LazyLock::force(&LAZY_FOO); | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:43:22 | LL | static LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); @@ -84,7 +84,7 @@ LL | let _ = Lazy::force(&LAZY_FOO); LL ~ let _ = std::sync::LazyLock::force(&LAZY_BAR); | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:45:26 | LL | static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs b/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs index 34f8dd1ccb2e..acc8c04678f5 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs @@ -9,11 +9,11 @@ mod once_cell_lazy { use once_cell::sync::Lazy; static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static mut LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); - //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + //~^ ERROR: this type has been superseded by `LazyLock` in the standard library fn calling_irreplaceable_fns() { let _ = Lazy::get(&LAZY_FOO); @@ -31,13 +31,13 @@ mod lazy_static_lazy_static { lazy_static! { static ref LAZY_FOO: String = "foo".to_uppercase(); } - //~^^^ ERROR: this macro has been superceded by `std::sync::LazyLock` + //~^^^ ERROR: this macro has been superseded by `std::sync::LazyLock` lazy_static! { static ref LAZY_BAR: String = "bar".to_uppercase(); static ref LAZY_BAZ: String = "baz".to_uppercase(); } - //~^^^^ ERROR: this macro has been superceded by `std::sync::LazyLock` - //~| ERROR: this macro has been superceded by `std::sync::LazyLock` + //~^^^^ ERROR: this macro has been superseded by `std::sync::LazyLock` + //~| ERROR: this macro has been superseded by `std::sync::LazyLock` } fn main() {} diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr b/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr index 216190ae4ca3..2c35cad6237a 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr @@ -1,4 +1,4 @@ -error: this macro has been superceded by `std::sync::LazyLock` +error: this macro has been superseded by `std::sync::LazyLock` --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:31:5 | LL | / lazy_static! { @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::non-std-lazy-statics` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::non_std_lazy_statics)]` -error: this macro has been superceded by `std::sync::LazyLock` +error: this macro has been superseded by `std::sync::LazyLock` --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5 | LL | / lazy_static! { @@ -18,7 +18,7 @@ LL | | static ref LAZY_BAZ: String = "baz".to_uppercase(); LL | | } | |_____^ -error: this macro has been superceded by `std::sync::LazyLock` +error: this macro has been superseded by `std::sync::LazyLock` --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5 | LL | / lazy_static! { @@ -29,7 +29,7 @@ LL | | } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:11:22 | LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); @@ -41,7 +41,7 @@ LL - static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); LL + static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:13:26 | LL | static mut LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); @@ -53,7 +53,7 @@ LL - static mut LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); LL + static mut LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "bar".to_uppercase()); | -error: this type has been superceded by `LazyLock` in the standard library +error: this type has been superseded by `LazyLock` in the standard library --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:15:26 | LL | static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index a155ff3508be..1eecc3dee3dc 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -216,3 +216,23 @@ fn issue14184(a: f32, b: bool) { println!("Hi"); } } + +mod issue14404 { + enum TyKind { + Ref(i32, i32, i32), + Other, + } + + struct Expr; + + fn is_mutable(expr: &Expr) -> bool { + todo!() + } + + fn should_not_give_macro(ty: TyKind, expr: Expr) { + if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) { + //~^ nonminimal_bool + todo!() + } + } +} diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr index 336cce40abf0..0e3e4cf7988e 100644 --- a/tests/ui/nonminimal_bool.stderr +++ b/tests/ui/nonminimal_bool.stderr @@ -227,7 +227,13 @@ error: this boolean expression can be simplified --> tests/ui/nonminimal_bool.rs:214:8 | LL | if !(a < 2.0 && !b) { - | ^^^^^^^^^^^^^^^^ help: try: `!(a < 2.0) || b` + | ^^^^^^^^^^^^^^^^ help: try: `a >= 2.0 || b` -error: aborting due to 30 previous errors +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool.rs:233:12 + | +LL | if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!matches!(ty, TyKind::Ref(_, _, _)) || is_mutable(&expr)` + +error: aborting due to 31 previous errors diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed index 66f5070787b0..70ae090626b9 100644 --- a/tests/ui/obfuscated_if_else.fixed +++ b/tests/ui/obfuscated_if_else.fixed @@ -46,6 +46,18 @@ fn main() { let partial = true.then_some(1); partial.unwrap_or_else(|| n * 2); // not lint + + if true { () } else { Default::default() }; + //~^ obfuscated_if_else + + if true { () } else { Default::default() }; + //~^ obfuscated_if_else + + if true { 1 } else { Default::default() }; + //~^ obfuscated_if_else + + if true { 1 } else { Default::default() }; + //~^ obfuscated_if_else } fn issue11141() { diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs index 4efd740eb60b..8e1f57ca2c02 100644 --- a/tests/ui/obfuscated_if_else.rs +++ b/tests/ui/obfuscated_if_else.rs @@ -46,6 +46,18 @@ fn main() { let partial = true.then_some(1); partial.unwrap_or_else(|| n * 2); // not lint + + true.then_some(()).unwrap_or_default(); + //~^ obfuscated_if_else + + true.then(|| ()).unwrap_or_default(); + //~^ obfuscated_if_else + + true.then_some(1).unwrap_or_default(); + //~^ obfuscated_if_else + + true.then(|| 1).unwrap_or_default(); + //~^ obfuscated_if_else } fn issue11141() { diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr index d676c2566957..0de7259d8bb8 100644 --- a/tests/ui/obfuscated_if_else.stderr +++ b/tests/ui/obfuscated_if_else.stderr @@ -68,52 +68,76 @@ LL | true.then_some(1).unwrap_or_else(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:53:13 + --> tests/ui/obfuscated_if_else.rs:50:5 + | +LL | true.then_some(()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { Default::default() }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:53:5 + | +LL | true.then(|| ()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { Default::default() }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:56:5 + | +LL | true.then_some(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:59:5 + | +LL | true.then(|| 1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:65:13 | LL | let _ = true.then_some(40).unwrap_or(17) | 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:57:13 + --> tests/ui/obfuscated_if_else.rs:69:13 | LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:57:48 + --> tests/ui/obfuscated_if_else.rs:69:48 | LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:57:81 + --> tests/ui/obfuscated_if_else.rs:69:81 | LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:63:17 + --> tests/ui/obfuscated_if_else.rs:75:17 | LL | let _ = 2 | true.then_some(40).unwrap_or(17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:67:13 + --> tests/ui/obfuscated_if_else.rs:79:13 | LL | let _ = true.then_some(42).unwrap_or(17) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:71:14 + --> tests/ui/obfuscated_if_else.rs:83:14 | LL | let _ = *true.then_some(&42).unwrap_or(&17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:75:14 + --> tests/ui/obfuscated_if_else.rs:87:14 | LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` -error: aborting due to 19 previous errors +error: aborting due to 23 previous errors diff --git a/tests/ui/op_ref.fixed b/tests/ui/op_ref.fixed index 46a59e419cce..f412190b9fd9 100644 --- a/tests/ui/op_ref.fixed +++ b/tests/ui/op_ref.fixed @@ -98,3 +98,15 @@ impl Mul for A { self * &rhs } } + +mod issue_2597 { + fn ex1() { + let a: &str = "abc"; + let b: String = "abc".to_owned(); + println!("{}", a > &b); + } + + pub fn ex2(array: &[T], val: &T, idx: usize) -> bool { + &array[idx] < val + } +} diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index e10840ff4b97..a4bbd86c7e95 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -98,3 +98,15 @@ impl Mul for A { self * &rhs } } + +mod issue_2597 { + fn ex1() { + let a: &str = "abc"; + let b: String = "abc".to_owned(); + println!("{}", a > &b); + } + + pub fn ex2(array: &[T], val: &T, idx: usize) -> bool { + &array[idx] < val + } +} diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index ee3098896017..fe3ac9e8f92c 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -288,3 +288,17 @@ mod issue13964 { }; } } + +mod issue11059 { + use std::fmt::Debug; + + fn box_coercion_unsize(o: Option) -> Box { + if let Some(o) = o { Box::new(o) } else { Box::new("foo") } + } + + static S: String = String::new(); + + fn deref_with_overload(o: Option<&str>) -> &str { + if let Some(o) = o { o } else { &S } + } +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 525a5df4371c..5b7498bc8e23 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -351,3 +351,17 @@ mod issue13964 { }; } } + +mod issue11059 { + use std::fmt::Debug; + + fn box_coercion_unsize(o: Option) -> Box { + if let Some(o) = o { Box::new(o) } else { Box::new("foo") } + } + + static S: String = String::new(); + + fn deref_with_overload(o: Option<&str>) -> &str { + if let Some(o) = o { o } else { &S } + } +} diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 1794ac57fe5b..a1119d75c231 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -179,16 +179,20 @@ fn f() -> Option<()> { mod issue6675 { unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T { - #[allow(unused)] - let x = vec![0; 1000]; // future-proofing, make this function expensive. - &*p + unsafe { + #[allow(unused)] + let x = vec![0; 1000]; // future-proofing, make this function expensive. + &*p + } } unsafe fn foo() { - let s = "test".to_owned(); - let s = &s as *const _; - None.unwrap_or_else(|| ptr_to_ref(s)); - //~^ or_fun_call + unsafe { + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or_else(|| ptr_to_ref(s)); + //~^ or_fun_call + } } fn bar() { diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 256db343c057..a7cd632bf166 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -179,16 +179,20 @@ fn f() -> Option<()> { mod issue6675 { unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T { - #[allow(unused)] - let x = vec![0; 1000]; // future-proofing, make this function expensive. - &*p + unsafe { + #[allow(unused)] + let x = vec![0; 1000]; // future-proofing, make this function expensive. + &*p + } } unsafe fn foo() { - let s = "test".to_owned(); - let s = &s as *const _; - None.unwrap_or(ptr_to_ref(s)); - //~^ or_fun_call + unsafe { + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or(ptr_to_ref(s)); + //~^ or_fun_call + } } fn bar() { diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 93c87b2f12cd..35bda7e4d331 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -125,91 +125,91 @@ LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:190:14 + --> tests/ui/or_fun_call.rs:193:18 | -LL | None.unwrap_or(ptr_to_ref(s)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` +LL | None.unwrap_or(ptr_to_ref(s)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:197:14 + --> tests/ui/or_fun_call.rs:201:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:200:14 + --> tests/ui/or_fun_call.rs:204:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:276:25 + --> tests/ui/or_fun_call.rs:280:25 | LL | let _ = Some(4).map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:278:25 + --> tests/ui/or_fun_call.rs:282:25 | LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:310:18 + --> tests/ui/or_fun_call.rs:314:18 | LL | with_new.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:314:28 + --> tests/ui/or_fun_call.rs:318:28 | LL | with_default_trait.unwrap_or_else(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:318:27 + --> tests/ui/or_fun_call.rs:322:27 | LL | with_default_type.unwrap_or_else(u64::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:322:22 + --> tests/ui/or_fun_call.rs:326:22 | LL | real_default.unwrap_or_else(::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:326:23 + --> tests/ui/or_fun_call.rs:330:23 | LL | map.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:330:25 + --> tests/ui/or_fun_call.rs:334:25 | LL | btree.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:334:25 + --> tests/ui/or_fun_call.rs:338:25 | LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:376:17 + --> tests/ui/or_fun_call.rs:380:17 | LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:381:17 + --> tests/ui/or_fun_call.rs:385:17 | LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:386:17 + --> tests/ui/or_fun_call.rs:390:17 | LL | let _ = opt.unwrap_or({ | _________________^ @@ -229,19 +229,19 @@ LL ~ }); | error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:392:17 + --> tests/ui/or_fun_call.rs:396:17 | LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:397:17 + --> tests/ui/or_fun_call.rs:401:17 | LL | let _ = opt.unwrap_or({ i32::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:404:21 + --> tests/ui/or_fun_call.rs:408:21 | LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` diff --git a/tests/ui/pattern_type_mismatch/mutability.rs b/tests/ui/pattern_type_mismatch/mutability.rs index bdac3764bf16..643d8fedda98 100644 --- a/tests/ui/pattern_type_mismatch/mutability.rs +++ b/tests/ui/pattern_type_mismatch/mutability.rs @@ -1,5 +1,5 @@ -#![allow(clippy::all)] #![warn(clippy::pattern_type_mismatch)] +#![allow(clippy::single_match)] fn main() {} diff --git a/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/tests/ui/pattern_type_mismatch/pattern_alternatives.rs index 3c789f570b03..a1c447d25834 100644 --- a/tests/ui/pattern_type_mismatch/pattern_alternatives.rs +++ b/tests/ui/pattern_type_mismatch/pattern_alternatives.rs @@ -1,4 +1,3 @@ -#![allow(clippy::all)] #![warn(clippy::pattern_type_mismatch)] fn main() {} diff --git a/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr index 763f688ea897..b3ae63ec031a 100644 --- a/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -1,5 +1,5 @@ error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:15:12 + --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:14:12 | LL | if let Value::B | Value::A(_) = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | if let Value::B | Value::A(_) = ref_value {} = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:18:34 + --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:17:34 | LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:21:32 + --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:20:32 | LL | if let Value::B | Value::A(Some(_)) = *ref_value {} | ^^^^^^^ diff --git a/tests/ui/pattern_type_mismatch/pattern_structs.rs b/tests/ui/pattern_type_mismatch/pattern_structs.rs index 7fc53d591a91..c5e395c4084f 100644 --- a/tests/ui/pattern_type_mismatch/pattern_structs.rs +++ b/tests/ui/pattern_type_mismatch/pattern_structs.rs @@ -1,4 +1,3 @@ -#![allow(clippy::all)] #![warn(clippy::pattern_type_mismatch)] fn main() {} diff --git a/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/tests/ui/pattern_type_mismatch/pattern_structs.stderr index 70f7bdc38906..e18a88c2bf51 100644 --- a/tests/ui/pattern_type_mismatch/pattern_structs.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -1,5 +1,5 @@ error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:13:9 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:12:9 | LL | let Struct { .. } = ref_value; | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let Struct { .. } = ref_value; = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:16:33 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:15:33 | LL | if let &Struct { ref_inner: Some(_) } = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &Struct { ref_inner: Some(_) } = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:19:32 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:18:32 | LL | if let Struct { ref_inner: Some(_) } = *ref_value {} | ^^^^^^^ @@ -25,7 +25,7 @@ LL | if let Struct { ref_inner: Some(_) } = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:37:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:36:12 | LL | if let StructEnum::Var { .. } = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let StructEnum::Var { .. } = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:40:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:39:12 | LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:43:42 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:42:42 | LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} | ^^^^^^^ @@ -49,7 +49,7 @@ LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:46:41 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:45:41 | LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} | ^^^^^^^ @@ -57,7 +57,7 @@ LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:49:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:48:12 | LL | if let StructEnum::Empty = ref_value {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/tests/ui/pattern_type_mismatch/pattern_tuples.rs index ecd95d9ae2b3..8bec5abc88f1 100644 --- a/tests/ui/pattern_type_mismatch/pattern_tuples.rs +++ b/tests/ui/pattern_type_mismatch/pattern_tuples.rs @@ -1,4 +1,3 @@ -#![allow(clippy::all)] #![warn(clippy::pattern_type_mismatch)] fn main() {} diff --git a/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr index d47c5d509c3f..ee307be63c1a 100644 --- a/tests/ui/pattern_type_mismatch/pattern_tuples.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -1,5 +1,5 @@ error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:11:9 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:10:9 | LL | let TupleStruct(_) = ref_value; | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let TupleStruct(_) = ref_value; = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:14:25 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:13:25 | LL | if let &TupleStruct(Some(_)) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &TupleStruct(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:17:24 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:16:24 | LL | if let TupleStruct(Some(_)) = *ref_value {} | ^^^^^^^ @@ -25,7 +25,7 @@ LL | if let TupleStruct(Some(_)) = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:35:12 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:34:12 | LL | if let TupleEnum::Var(_) = ref_value {} | ^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let TupleEnum::Var(_) = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:38:28 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:37:28 | LL | if let &TupleEnum::Var(Some(_)) = ref_value {} | ^^^^^^^ @@ -41,7 +41,7 @@ LL | if let &TupleEnum::Var(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:41:27 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:40:27 | LL | if let TupleEnum::Var(Some(_)) = *ref_value {} | ^^^^^^^ @@ -49,7 +49,7 @@ LL | if let TupleEnum::Var(Some(_)) = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:44:12 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:43:12 | LL | if let TupleEnum::Empty = ref_value {} | ^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | if let TupleEnum::Empty = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:60:9 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:59:9 | LL | let (_a, _b) = ref_value; | ^^^^^^^^ @@ -65,7 +65,7 @@ LL | let (_a, _b) = ref_value; = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:63:18 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:62:18 | LL | if let &(_a, Some(_)) = ref_value {} | ^^^^^^^ @@ -73,7 +73,7 @@ LL | if let &(_a, Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:66:17 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:65:17 | LL | if let (_a, Some(_)) = *ref_value {} | ^^^^^^^ diff --git a/tests/ui/pattern_type_mismatch/syntax.rs b/tests/ui/pattern_type_mismatch/syntax.rs index 0bbc26a0c27c..49ea1d3f7a67 100644 --- a/tests/ui/pattern_type_mismatch/syntax.rs +++ b/tests/ui/pattern_type_mismatch/syntax.rs @@ -1,5 +1,10 @@ -#![allow(clippy::all)] #![warn(clippy::pattern_type_mismatch)] +#![allow( + clippy::match_ref_pats, + clippy::never_loop, + clippy::redundant_pattern_matching, + clippy::single_match +)] fn main() {} diff --git a/tests/ui/pattern_type_mismatch/syntax.stderr b/tests/ui/pattern_type_mismatch/syntax.stderr index 3f6b5feb9b07..cd604d604c12 100644 --- a/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/tests/ui/pattern_type_mismatch/syntax.stderr @@ -1,5 +1,5 @@ error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:11:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:16:9 | LL | Some(_) => (), | ^^^^^^^ @@ -9,7 +9,7 @@ LL | Some(_) => (), = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:31:12 + --> tests/ui/pattern_type_mismatch/syntax.rs:36:12 | LL | if let Some(_) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let Some(_) = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:43:15 + --> tests/ui/pattern_type_mismatch/syntax.rs:48:15 | LL | while let Some(_) = ref_value { | ^^^^^^^ @@ -25,7 +25,7 @@ LL | while let Some(_) = ref_value { = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:63:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:68:9 | LL | for (_a, _b) in slice.iter() {} | ^^^^^^^^ @@ -33,7 +33,7 @@ LL | for (_a, _b) in slice.iter() {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:74:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:79:9 | LL | let (_n, _m) = ref_value; | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | let (_n, _m) = ref_value; = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:84:12 + --> tests/ui/pattern_type_mismatch/syntax.rs:89:12 | LL | fn foo((_a, _b): &(i32, i32)) {} | ^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn foo((_a, _b): &(i32, i32)) {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:99:10 + --> tests/ui/pattern_type_mismatch/syntax.rs:104:10 | LL | foo(|(_a, _b)| ()); | ^^^^^^^^ @@ -57,7 +57,7 @@ LL | foo(|(_a, _b)| ()); = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:116:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:121:9 | LL | Some(_) => (), | ^^^^^^^ @@ -65,7 +65,7 @@ LL | Some(_) => (), = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:137:17 + --> tests/ui/pattern_type_mismatch/syntax.rs:142:17 | LL | Some(_) => (), | ^^^^^^^ diff --git a/tests/ui/patterns.fixed b/tests/ui/patterns.fixed index bcb8ecfc38d2..a6dd5fd63a9f 100644 --- a/tests/ui/patterns.fixed +++ b/tests/ui/patterns.fixed @@ -1,6 +1,4 @@ //@aux-build:proc_macros.rs -#![warn(clippy::all)] -#![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::single_match)] #[macro_use] diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 19639ebd13d6..64bfbdecdac2 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,6 +1,4 @@ //@aux-build:proc_macros.rs -#![warn(clippy::all)] -#![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::single_match)] #[macro_use] diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index b9950fe181cc..ff5e1a8de90a 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,5 +1,5 @@ error: the `y @ _` pattern can be written as just `y` - --> tests/ui/patterns.rs:14:9 + --> tests/ui/patterns.rs:12:9 | LL | y @ _ => (), | ^^^^^ help: try: `y` @@ -8,13 +8,13 @@ LL | y @ _ => (), = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern)]` error: the `x @ _` pattern can be written as just `x` - --> tests/ui/patterns.rs:30:9 + --> tests/ui/patterns.rs:28:9 | LL | ref mut x @ _ => { | ^^^^^^^^^^^^^ help: try: `ref mut x` error: the `x @ _` pattern can be written as just `x` - --> tests/ui/patterns.rs:39:9 + --> tests/ui/patterns.rs:37:9 | LL | ref x @ _ => println!("vec: {:?}", x), | ^^^^^^^^^ help: try: `ref x` diff --git a/tests/ui/pointers_in_nomem_asm_block.rs b/tests/ui/pointers_in_nomem_asm_block.rs index 171716be2602..7f69c61b0289 100644 --- a/tests/ui/pointers_in_nomem_asm_block.rs +++ b/tests/ui/pointers_in_nomem_asm_block.rs @@ -6,29 +6,37 @@ use core::arch::asm; unsafe fn nomem_bad(p: &i32) { - asm!( - "asdf {p1}, {p2}, {p3}", - p1 = in(reg) p, - //~^ pointers_in_nomem_asm_block + unsafe { + asm!( + "asdf {p1}, {p2}, {p3}", + p1 = in(reg) p, + //~^ pointers_in_nomem_asm_block - p2 = in(reg) p as *const _ as usize, - p3 = in(reg) p, - options(nomem, nostack, preserves_flags) - ); + p2 = in(reg) p as *const _ as usize, + p3 = in(reg) p, + options(nomem, nostack, preserves_flags) + ); + } } unsafe fn nomem_good(p: &i32) { - asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags)); - let p = p as *const i32 as usize; - asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + unsafe { + asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags)); + let p = p as *const i32 as usize; + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + } } unsafe fn nomem_bad2(p: &mut i32) { - asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); - //~^ pointers_in_nomem_asm_block + unsafe { + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + //~^ pointers_in_nomem_asm_block + } } unsafe fn nomem_fn(p: extern "C" fn()) { - asm!("call {p}", p = in(reg) p, options(nomem)); - //~^ pointers_in_nomem_asm_block + unsafe { + asm!("call {p}", p = in(reg) p, options(nomem)); + //~^ pointers_in_nomem_asm_block + } } diff --git a/tests/ui/pointers_in_nomem_asm_block.stderr b/tests/ui/pointers_in_nomem_asm_block.stderr index ca24e34f63c0..eabac2444ecc 100644 --- a/tests/ui/pointers_in_nomem_asm_block.stderr +++ b/tests/ui/pointers_in_nomem_asm_block.stderr @@ -1,11 +1,11 @@ error: passing pointers to nomem asm block - --> tests/ui/pointers_in_nomem_asm_block.rs:11:9 + --> tests/ui/pointers_in_nomem_asm_block.rs:12:13 | -LL | p1 = in(reg) p, - | ^^^^^^^^^^^^^^ +LL | p1 = in(reg) p, + | ^^^^^^^^^^^^^^ ... -LL | p3 = in(reg) p, - | ^^^^^^^^^^^^^^ +LL | p3 = in(reg) p, + | ^^^^^^^^^^^^^^ | = note: `nomem` means that no memory write or read happens inside the asm! block = note: if this is intentional and no pointers are read or written to, consider allowing the lint @@ -13,19 +13,19 @@ LL | p3 = in(reg) p, = help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]` error: passing pointers to nomem asm block - --> tests/ui/pointers_in_nomem_asm_block.rs:27:22 + --> tests/ui/pointers_in_nomem_asm_block.rs:32:26 | -LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); - | ^^^^^^^^^^^^^ +LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + | ^^^^^^^^^^^^^ | = note: `nomem` means that no memory write or read happens inside the asm! block = note: if this is intentional and no pointers are read or written to, consider allowing the lint error: passing pointers to nomem asm block - --> tests/ui/pointers_in_nomem_asm_block.rs:32:22 + --> tests/ui/pointers_in_nomem_asm_block.rs:39:26 | -LL | asm!("call {p}", p = in(reg) p, options(nomem)); - | ^^^^^^^^^^^^^ +LL | asm!("call {p}", p = in(reg) p, options(nomem)); + | ^^^^^^^^^^^^^ | = note: `nomem` means that no memory write or read happens inside the asm! block = note: if this is intentional and no pointers are read or written to, consider allowing the lint diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index 6dded72d3e19..79bfae1f7ebb 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -12,11 +12,13 @@ extern crate proc_macros; use proc_macros::{external, inline_macros}; unsafe fn ptr_to_ref(p: *const T, om: *mut U) { - let _: &mut T = std::mem::transmute(p.cast_mut()); - //~^ ptr_cast_constness - let _ = &mut *p.cast_mut(); - //~^ ptr_cast_constness - let _: &T = &*(om as *const T); + unsafe { + let _: &mut T = std::mem::transmute(p.cast_mut()); + //~^ ptr_cast_constness + let _ = &mut *p.cast_mut(); + //~^ ptr_cast_constness + let _: &T = &*(om as *const T); + } } #[inline_macros] @@ -98,3 +100,9 @@ fn null_pointers() { let _ = external!(ptr::null::() as *mut u32); let _ = external!(ptr::null::().cast_mut()); } + +fn issue14621() { + let mut local = 4; + let _ = std::ptr::addr_of_mut!(local).cast_const(); + //~^ ptr_cast_constness +} diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index e9629f5290ec..f6590dabd5b8 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -12,11 +12,13 @@ extern crate proc_macros; use proc_macros::{external, inline_macros}; unsafe fn ptr_to_ref(p: *const T, om: *mut U) { - let _: &mut T = std::mem::transmute(p as *mut T); - //~^ ptr_cast_constness - let _ = &mut *(p as *mut T); - //~^ ptr_cast_constness - let _: &T = &*(om as *const T); + unsafe { + let _: &mut T = std::mem::transmute(p as *mut T); + //~^ ptr_cast_constness + let _ = &mut *(p as *mut T); + //~^ ptr_cast_constness + let _: &T = &*(om as *const T); + } } #[inline_macros] @@ -98,3 +100,9 @@ fn null_pointers() { let _ = external!(ptr::null::() as *mut u32); let _ = external!(ptr::null::().cast_mut()); } + +fn issue14621() { + let mut local = 4; + let _ = std::ptr::addr_of_mut!(local) as *const _; + //~^ ptr_cast_constness +} diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 1eeeef747013..0b1644168ff5 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -1,74 +1,74 @@ error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:15:41 + --> tests/ui/ptr_cast_constness.rs:16:45 | -LL | let _: &mut T = std::mem::transmute(p as *mut T); - | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` +LL | let _: &mut T = std::mem::transmute(p as *mut T); + | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` | = note: `-D clippy::ptr-cast-constness` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_cast_constness)]` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:17:19 + --> tests/ui/ptr_cast_constness.rs:18:23 | -LL | let _ = &mut *(p as *mut T); - | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` +LL | let _ = &mut *(p as *mut T); + | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:33:17 + --> tests/ui/ptr_cast_constness.rs:35:17 | LL | let _ = *ptr_ptr as *mut u32; | ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:37:13 + --> tests/ui/ptr_cast_constness.rs:39:13 | LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:39:13 + --> tests/ui/ptr_cast_constness.rs:41:13 | LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:73:13 + --> tests/ui/ptr_cast_constness.rs:75:13 | LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:75:13 + --> tests/ui/ptr_cast_constness.rs:77:13 | LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` error: `as` casting to make a const null pointer into a mutable null pointer - --> tests/ui/ptr_cast_constness.rs:82:13 + --> tests/ui/ptr_cast_constness.rs:84:13 | LL | let _ = ptr::null::() as *mut String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` error: `as` casting to make a mutable null pointer into a const null pointer - --> tests/ui/ptr_cast_constness.rs:84:13 + --> tests/ui/ptr_cast_constness.rs:86:13 | LL | let _ = ptr::null_mut::() as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:86:13 + --> tests/ui/ptr_cast_constness.rs:88:13 | LL | let _ = ptr::null::().cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:88:13 + --> tests/ui/ptr_cast_constness.rs:90:13 | LL | let _ = ptr::null_mut::().cast_const(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` error: `as` casting to make a const null pointer into a mutable null pointer - --> tests/ui/ptr_cast_constness.rs:92:21 + --> tests/ui/ptr_cast_constness.rs:94:21 | LL | let _ = inline!(ptr::null::() as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` @@ -76,12 +76,18 @@ LL | let _ = inline!(ptr::null::() as *mut u32); = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:94:21 + --> tests/ui/ptr_cast_constness.rs:96:21 | LL | let _ = inline!(ptr::null::().cast_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` | = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 13 previous errors +error: `as` casting between raw pointers while changing only its constness + --> tests/ui/ptr_cast_constness.rs:106:13 + | +LL | let _ = std::ptr::addr_of_mut!(local) as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `std::ptr::addr_of_mut!(local).cast_const()` + +error: aborting due to 14 previous errors diff --git a/tests/ui/ptr_eq.fixed b/tests/ui/ptr_eq.fixed index df6305ed497e..484ff3073239 100644 --- a/tests/ui/ptr_eq.fixed +++ b/tests/ui/ptr_eq.fixed @@ -4,6 +4,9 @@ macro_rules! mac { ($a:expr, $b:expr) => { $a as *const _ as usize == $b as *const _ as usize }; + (cast $a:expr) => { + $a as *const [i32; 3] + }; } macro_rules! another_mac { @@ -51,4 +54,8 @@ fn main() { #[allow(clippy::eq_op)] let _issue14337 = std::ptr::eq(main as *const (), main as *const ()); //~^ ptr_eq + + // Do not peel the content of macros + let _ = std::ptr::eq(mac!(cast a), mac!(cast b)); + //~^ ptr_eq } diff --git a/tests/ui/ptr_eq.rs b/tests/ui/ptr_eq.rs index 0ed0ff0d1371..f28707cc3e92 100644 --- a/tests/ui/ptr_eq.rs +++ b/tests/ui/ptr_eq.rs @@ -4,6 +4,9 @@ macro_rules! mac { ($a:expr, $b:expr) => { $a as *const _ as usize == $b as *const _ as usize }; + (cast $a:expr) => { + $a as *const [i32; 3] + }; } macro_rules! another_mac { @@ -51,4 +54,8 @@ fn main() { #[allow(clippy::eq_op)] let _issue14337 = main as *const () == main as *const (); //~^ ptr_eq + + // Do not peel the content of macros + let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; + //~^ ptr_eq } diff --git a/tests/ui/ptr_eq.stderr b/tests/ui/ptr_eq.stderr index 33190df284a3..906831b9e031 100644 --- a/tests/ui/ptr_eq.stderr +++ b/tests/ui/ptr_eq.stderr @@ -1,5 +1,5 @@ error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:19:13 + --> tests/ui/ptr_eq.rs:22:13 | LL | let _ = a as *const _ as usize == b as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` @@ -8,52 +8,58 @@ LL | let _ = a as *const _ as usize == b as *const _ as usize; = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:21:13 + --> tests/ui/ptr_eq.rs:24:13 | LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:23:13 + --> tests/ui/ptr_eq.rs:26:13 | LL | let _ = a.as_ptr() == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:25:13 + --> tests/ui/ptr_eq.rs:28:13 | LL | let _ = a.as_ptr() == b.as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:36:13 + --> tests/ui/ptr_eq.rs:39:13 | LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:38:13 + --> tests/ui/ptr_eq.rs:41:13 | LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:45:13 + --> tests/ui/ptr_eq.rs:48:13 | LL | let _ = x as *const u32 == y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:48:13 + --> tests/ui/ptr_eq.rs:51:13 | LL | let _ = x as *const u32 != y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:52:23 + --> tests/ui/ptr_eq.rs:55:23 | LL | let _issue14337 = main as *const () == main as *const (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())` -error: aborting due to 9 previous errors +error: use `std::ptr::eq` when comparing raw pointers + --> tests/ui/ptr_eq.rs:59:13 + | +LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` + +error: aborting due to 10 previous errors diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index fff41f578284..6bd071d07f52 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -3,6 +3,8 @@ #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] +use std::sync::MutexGuard; + fn some_func(a: Option) -> Option { a?; @@ -430,3 +432,9 @@ fn msrv_1_13(arg: Option) -> Option { println!("{}", val); Some(val) } + +fn issue_14615(a: MutexGuard>) -> Option { + let a = (*a)?; + //~^^^ question_mark + Some(format!("{a}")) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index c71c8ee984ed..dd093c9bf480 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -3,6 +3,8 @@ #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] +use std::sync::MutexGuard; + fn some_func(a: Option) -> Option { if a.is_none() { //~^ question_mark @@ -524,3 +526,11 @@ fn msrv_1_13(arg: Option) -> Option { println!("{}", val); Some(val) } + +fn issue_14615(a: MutexGuard>) -> Option { + let Some(a) = *a else { + return None; + }; + //~^^^ question_mark + Some(format!("{a}")) +} diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 183b8866a748..8fe04b895cea 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:7:5 + --> tests/ui/question_mark.rs:9:5 | LL | / if a.is_none() { LL | | @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::question_mark)]` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:53:9 + --> tests/ui/question_mark.rs:55:9 | LL | / if (self.opt).is_none() { LL | | @@ -20,7 +20,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:58:9 + --> tests/ui/question_mark.rs:60:9 | LL | / if self.opt.is_none() { LL | | @@ -29,7 +29,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:63:17 + --> tests/ui/question_mark.rs:65:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -41,7 +41,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:70:17 + --> tests/ui/question_mark.rs:72:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -53,7 +53,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:88:9 + --> tests/ui/question_mark.rs:90:9 | LL | / if self.opt.is_none() { LL | | @@ -62,7 +62,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:97:9 + --> tests/ui/question_mark.rs:99:9 | LL | / if self.opt.is_none() { LL | | @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:106:9 + --> tests/ui/question_mark.rs:108:9 | LL | / if self.opt.is_none() { LL | | @@ -80,7 +80,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:114:26 + --> tests/ui/question_mark.rs:116:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -92,7 +92,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:125:17 + --> tests/ui/question_mark.rs:127:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -104,7 +104,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:147:5 + --> tests/ui/question_mark.rs:149:5 | LL | / if f().is_none() { LL | | @@ -113,7 +113,7 @@ LL | | } | |_____^ help: replace it with: `f()?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:152:16 + --> tests/ui/question_mark.rs:154:16 | LL | let _val = match f() { | ________________^ @@ -124,7 +124,7 @@ LL | | }; | |_____^ help: try instead: `f()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:163:5 + --> tests/ui/question_mark.rs:165:5 | LL | / match f() { LL | | @@ -134,7 +134,7 @@ LL | | }; | |_____^ help: try instead: `f()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:169:5 + --> tests/ui/question_mark.rs:171:5 | LL | / match opt_none!() { LL | | @@ -144,13 +144,13 @@ LL | | }; | |_____^ help: try instead: `opt_none!()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:196:13 + --> tests/ui/question_mark.rs:198:13 | LL | let _ = if let Ok(x) = x { x } else { return x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:199:5 + --> tests/ui/question_mark.rs:201:5 | LL | / if x.is_err() { LL | | @@ -159,7 +159,7 @@ LL | | } | |_____^ help: replace it with: `x?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:204:16 + --> tests/ui/question_mark.rs:206:16 | LL | let _val = match func_returning_result() { | ________________^ @@ -170,7 +170,7 @@ LL | | }; | |_____^ help: try instead: `func_returning_result()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:210:5 + --> tests/ui/question_mark.rs:212:5 | LL | / match func_returning_result() { LL | | @@ -180,7 +180,7 @@ LL | | }; | |_____^ help: try instead: `func_returning_result()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:302:5 + --> tests/ui/question_mark.rs:304:5 | LL | / if let Err(err) = func_returning_result() { LL | | @@ -189,7 +189,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:310:5 + --> tests/ui/question_mark.rs:312:5 | LL | / if let Err(err) = func_returning_result() { LL | | @@ -198,7 +198,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:388:13 + --> tests/ui/question_mark.rs:390:13 | LL | / if a.is_none() { LL | | @@ -208,7 +208,7 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:449:5 + --> tests/ui/question_mark.rs:451:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; @@ -216,7 +216,7 @@ LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:464:5 + --> tests/ui/question_mark.rs:466:5 | LL | / let Some(ref x) = foo.opt_x else { LL | | return None; @@ -224,7 +224,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:474:5 + --> tests/ui/question_mark.rs:476:5 | LL | / let Some(ref mut x) = foo.opt_x else { LL | | return None; @@ -232,7 +232,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:485:5 + --> tests/ui/question_mark.rs:487:5 | LL | / let Some(ref x @ ref y) = foo.opt_x else { LL | | return None; @@ -240,7 +240,7 @@ LL | | }; | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:489:5 + --> tests/ui/question_mark.rs:491:5 | LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -248,7 +248,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:493:5 + --> tests/ui/question_mark.rs:495:5 | LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -256,7 +256,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:515:5 + --> tests/ui/question_mark.rs:517:5 | LL | / if arg.is_none() { LL | | @@ -265,7 +265,7 @@ LL | | } | |_____^ help: replace it with: `arg?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:519:15 + --> tests/ui/question_mark.rs:521:15 | LL | let val = match arg { | _______________^ @@ -275,5 +275,13 @@ LL | | None => return None, LL | | }; | |_____^ help: try instead: `arg?` -error: aborting due to 29 previous errors +error: this `let...else` may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:531:5 + | +LL | / let Some(a) = *a else { +LL | | return None; +LL | | }; + | |______^ help: replace it with: `let a = (*a)?;` + +error: aborting due to 30 previous errors diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index 0562f7dcc761..832f147c6ed5 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::disallowed_names)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index 44d30f95d7bc..886ed2088c67 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -1,5 +1,5 @@ error: usage of `Box>` - --> tests/ui/redundant_allocation.rs:16:30 + --> tests/ui/redundant_allocation.rs:15:30 | LL | pub fn box_test6(foo: Box>) {} | ^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | pub fn box_test6(foo: Box>) {} = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box>` - --> tests/ui/redundant_allocation.rs:19:30 + --> tests/ui/redundant_allocation.rs:18:30 | LL | pub fn box_test7(foo: Box>) {} | ^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | pub fn box_test7(foo: Box>) {} = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> tests/ui/redundant_allocation.rs:22:27 + --> tests/ui/redundant_allocation.rs:21:27 | LL | pub fn box_test8() -> Box>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | pub fn box_test8() -> Box>> { = help: consider using just `Box>` or `Rc>` error: usage of `Box>` - --> tests/ui/redundant_allocation.rs:28:30 + --> tests/ui/redundant_allocation.rs:27:30 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> tests/ui/redundant_allocation.rs:28:46 + --> tests/ui/redundant_allocation.rs:27:46 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box>` or `Arc>` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:42:24 + --> tests/ui/redundant_allocation.rs:41:24 | LL | pub fn rc_test5(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | pub fn rc_test5(a: Rc>) {} = help: consider using just `Rc` or `Box` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:45:24 + --> tests/ui/redundant_allocation.rs:44:24 | LL | pub fn rc_test7(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | pub fn rc_test7(a: Rc>) {} = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:48:26 + --> tests/ui/redundant_allocation.rs:47:26 | LL | pub fn rc_test8() -> Rc>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | pub fn rc_test8() -> Rc>> { = help: consider using just `Rc>` or `Box>` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:54:29 + --> tests/ui/redundant_allocation.rs:53:29 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:54:44 + --> tests/ui/redundant_allocation.rs:53:44 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc>` or `Arc>` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:68:25 + --> tests/ui/redundant_allocation.rs:67:25 | LL | pub fn arc_test5(a: Arc>) {} | ^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | pub fn arc_test5(a: Arc>) {} = help: consider using just `Arc` or `Box` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:71:25 + --> tests/ui/redundant_allocation.rs:70:25 | LL | pub fn arc_test6(a: Arc>) {} | ^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | pub fn arc_test6(a: Arc>) {} = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> tests/ui/redundant_allocation.rs:74:27 + --> tests/ui/redundant_allocation.rs:73:27 | LL | pub fn arc_test8() -> Arc>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | pub fn arc_test8() -> Arc>> { = help: consider using just `Arc>` or `Box>` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:80:30 + --> tests/ui/redundant_allocation.rs:79:30 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> tests/ui/redundant_allocation.rs:80:45 + --> tests/ui/redundant_allocation.rs:79:45 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc>` or `Rc>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:105:27 + --> tests/ui/redundant_allocation.rs:104:27 | LL | pub fn test_rc_box(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | pub fn test_rc_box(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:138:31 + --> tests/ui/redundant_allocation.rs:137:31 | LL | pub fn test_rc_box_str(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | pub fn test_rc_box_str(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:141:33 + --> tests/ui/redundant_allocation.rs:140:33 | LL | pub fn test_rc_box_slice(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | pub fn test_rc_box_slice(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:144:32 + --> tests/ui/redundant_allocation.rs:143:32 | LL | pub fn test_rc_box_path(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | pub fn test_rc_box_path(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:147:34 + --> tests/ui/redundant_allocation.rs:146:34 | LL | pub fn test_rc_box_custom(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index 7773ba11f973..dbc6c0794d1a 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,7 +1,5 @@ -#![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_names, unused_variables, dead_code)] -#![allow(unused_imports)] +#![allow(clippy::disallowed_names)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index fb86ed2b3cfd..05b6429492ce 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,7 +1,5 @@ -#![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_names, unused_variables, dead_code)] -#![allow(unused_imports)] +#![allow(clippy::disallowed_names)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.stderr b/tests/ui/redundant_allocation_fixable.stderr index ed8282cc82ce..407376688717 100644 --- a/tests/ui/redundant_allocation_fixable.stderr +++ b/tests/ui/redundant_allocation_fixable.stderr @@ -1,5 +1,5 @@ error: usage of `Box<&T>` - --> tests/ui/redundant_allocation_fixable.rs:23:30 + --> tests/ui/redundant_allocation_fixable.rs:21:30 | LL | pub fn box_test1(foo: Box<&T>) {} | ^^^^^^^ help: try: `&T` @@ -9,7 +9,7 @@ LL | pub fn box_test1(foo: Box<&T>) {} = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:26:27 + --> tests/ui/redundant_allocation_fixable.rs:24:27 | LL | pub fn box_test2(foo: Box<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -17,7 +17,7 @@ LL | pub fn box_test2(foo: Box<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap error: usage of `Box<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:29:27 + --> tests/ui/redundant_allocation_fixable.rs:27:27 | LL | pub fn box_test3(foo: Box<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -25,7 +25,7 @@ LL | pub fn box_test3(foo: Box<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap error: usage of `Box>` - --> tests/ui/redundant_allocation_fixable.rs:34:30 + --> tests/ui/redundant_allocation_fixable.rs:32:30 | LL | pub fn box_test5(foo: Box>) {} | ^^^^^^^^^^^ help: try: `Box` @@ -33,7 +33,7 @@ LL | pub fn box_test5(foo: Box>) {} = note: `Box` is already on the heap, `Box>` makes an extra allocation error: usage of `Rc<&T>` - --> tests/ui/redundant_allocation_fixable.rs:44:29 + --> tests/ui/redundant_allocation_fixable.rs:42:29 | LL | pub fn rc_test1(foo: Rc<&T>) {} | ^^^^^^ help: try: `&T` @@ -41,7 +41,7 @@ LL | pub fn rc_test1(foo: Rc<&T>) {} = note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap error: usage of `Rc<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:47:26 + --> tests/ui/redundant_allocation_fixable.rs:45:26 | LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} | ^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -49,7 +49,7 @@ LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap error: usage of `Rc<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:50:26 + --> tests/ui/redundant_allocation_fixable.rs:48:26 | LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} | ^^^^^^^^^^^ help: try: `&MyEnum` @@ -57,7 +57,7 @@ LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap error: usage of `Rc>` - --> tests/ui/redundant_allocation_fixable.rs:55:24 + --> tests/ui/redundant_allocation_fixable.rs:53:24 | LL | pub fn rc_test6(a: Rc>) {} | ^^^^^^^^^^^^ help: try: `Rc` @@ -65,7 +65,7 @@ LL | pub fn rc_test6(a: Rc>) {} = note: `Rc` is already on the heap, `Rc>` makes an extra allocation error: usage of `Arc<&T>` - --> tests/ui/redundant_allocation_fixable.rs:65:30 + --> tests/ui/redundant_allocation_fixable.rs:63:30 | LL | pub fn arc_test1(foo: Arc<&T>) {} | ^^^^^^^ help: try: `&T` @@ -73,7 +73,7 @@ LL | pub fn arc_test1(foo: Arc<&T>) {} = note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap error: usage of `Arc<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:68:27 + --> tests/ui/redundant_allocation_fixable.rs:66:27 | LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -81,7 +81,7 @@ LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap error: usage of `Arc<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:71:27 + --> tests/ui/redundant_allocation_fixable.rs:69:27 | LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -89,7 +89,7 @@ LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap error: usage of `Arc>` - --> tests/ui/redundant_allocation_fixable.rs:76:25 + --> tests/ui/redundant_allocation_fixable.rs:74:25 | LL | pub fn arc_test7(a: Arc>) {} | ^^^^^^^^^^^^^^ help: try: `Arc` diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 23c00b34a00a..c1c389f7c4ed 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -259,3 +259,35 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +mod issue10074 { + #[derive(Debug, Clone)] + enum MyEnum { + A = 1, + } + + fn false_positive_on_as() { + let e = MyEnum::A; + let v = e.clone() as u16; + + println!("{e:?}"); + println!("{v}"); + } +} + +mod issue13900 { + use std::fmt::Display; + + fn do_something(f: impl Display + Clone) -> String { + let g = f.clone(); + format!("{} + {}", f, g) + } + + fn regression() { + let mut a = String::new(); + let mut b = String::new(); + for _ in 1..10 { + b = a.clone(); + } + } +} diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index f9fe8ba0236d..78d98762efc8 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -259,3 +259,35 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +mod issue10074 { + #[derive(Debug, Clone)] + enum MyEnum { + A = 1, + } + + fn false_positive_on_as() { + let e = MyEnum::A; + let v = e.clone() as u16; + + println!("{e:?}"); + println!("{v}"); + } +} + +mod issue13900 { + use std::fmt::Display; + + fn do_something(f: impl Display + Clone) -> String { + let g = f.clone(); + format!("{} + {}", f, g) + } + + fn regression() { + let mut a = String::new(); + let mut b = String::new(); + for _ in 1..10 { + b = a.clone(); + } + } +} diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index 549c97d9534a..1cec19ab8c99 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -1,5 +1,4 @@ -#![warn(clippy::all, clippy::redundant_pattern_matching)] -#![allow(unused_must_use)] +#![warn(clippy::redundant_pattern_matching)] #![allow( clippy::match_like_matches_macro, clippy::needless_bool, diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index decb1396d56d..123573a8602b 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -1,5 +1,4 @@ -#![warn(clippy::all, clippy::redundant_pattern_matching)] -#![allow(unused_must_use)] +#![warn(clippy::redundant_pattern_matching)] #![allow( clippy::match_like_matches_macro, clippy::needless_bool, diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index 66d2cecdc0c9..3be7cf81afe9 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:15:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:14:12 | LL | if let V4(_) = &ipaddr {} | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` @@ -8,43 +8,43 @@ LL | if let V4(_) = &ipaddr {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:18:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:17:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:21:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:25:8 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:24:8 | LL | if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:29:8 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:28:8 | LL | if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:32:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:31:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:35:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:34:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:46:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:45:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | @@ -54,7 +54,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:52:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:51:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | @@ -64,7 +64,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:58:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:57:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | @@ -74,7 +74,7 @@ LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:64:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:63:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | @@ -84,49 +84,49 @@ LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:70:20 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:69:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:79:20 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:78:20 | LL | let _ = if let V4(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:82:19 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:81:19 | LL | } else if let V6(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:95:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:94:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:98:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:97:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:101:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:100:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:104:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:103:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:107:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:106:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | @@ -136,7 +136,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:113:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:112:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 5585006dc362..33a5308bd357 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -1,14 +1,12 @@ -#![warn(clippy::all)] +#![feature(let_chains, if_let_guard)] #![warn(clippy::redundant_pattern_matching)] #![allow( - unused_must_use, clippy::needless_bool, clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else )] -#![feature(let_chains, if_let_guard)] fn issue_11174(boolean: bool, maybe_some: Option) -> bool { maybe_some.is_none() && (!boolean) diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 581a432f38e1..60bce2994ea3 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -1,14 +1,12 @@ -#![warn(clippy::all)] +#![feature(let_chains, if_let_guard)] #![warn(clippy::redundant_pattern_matching)] #![allow( - unused_must_use, clippy::needless_bool, clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else )] -#![feature(let_chains, if_let_guard)] fn issue_11174(boolean: bool, maybe_some: Option) -> bool { matches!(maybe_some, None if !boolean) diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 681602567d2f..e5a6598898aa 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:14:5 + --> tests/ui/redundant_pattern_matching_option.rs:12:5 | LL | matches!(maybe_some, None if !boolean) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)` @@ -8,55 +8,55 @@ LL | matches!(maybe_some, None if !boolean) = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:19:13 + --> tests/ui/redundant_pattern_matching_option.rs:17:13 | LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:35:12 + --> tests/ui/redundant_pattern_matching_option.rs:33:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:38:12 + --> tests/ui/redundant_pattern_matching_option.rs:36:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:41:12 + --> tests/ui/redundant_pattern_matching_option.rs:39:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:48:15 + --> tests/ui/redundant_pattern_matching_option.rs:46:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:51:15 + --> tests/ui/redundant_pattern_matching_option.rs:49:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:54:15 + --> tests/ui/redundant_pattern_matching_option.rs:52:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:58:15 + --> tests/ui/redundant_pattern_matching_option.rs:56:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:67:5 + --> tests/ui/redundant_pattern_matching_option.rs:65:5 | LL | / match Some(42) { LL | | @@ -66,7 +66,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:73:5 + --> tests/ui/redundant_pattern_matching_option.rs:71:5 | LL | / match None::<()> { LL | | @@ -76,7 +76,7 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:79:13 + --> tests/ui/redundant_pattern_matching_option.rs:77:13 | LL | let _ = match None::<()> { | _____________^ @@ -87,55 +87,55 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:86:20 + --> tests/ui/redundant_pattern_matching_option.rs:84:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:93:20 + --> tests/ui/redundant_pattern_matching_option.rs:91:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:96:19 + --> tests/ui/redundant_pattern_matching_option.rs:94:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:103:12 + --> tests/ui/redundant_pattern_matching_option.rs:101:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:119:12 + --> tests/ui/redundant_pattern_matching_option.rs:117:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:122:12 + --> tests/ui/redundant_pattern_matching_option.rs:120:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:125:15 + --> tests/ui/redundant_pattern_matching_option.rs:123:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:128:15 + --> tests/ui/redundant_pattern_matching_option.rs:126:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:131:5 + --> tests/ui/redundant_pattern_matching_option.rs:129:5 | LL | / match Some(42) { LL | | @@ -145,7 +145,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:137:5 + --> tests/ui/redundant_pattern_matching_option.rs:135:5 | LL | / match None::<()> { LL | | @@ -155,19 +155,19 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:146:12 + --> tests/ui/redundant_pattern_matching_option.rs:144:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:148:12 + --> tests/ui/redundant_pattern_matching_option.rs:146:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:155:5 + --> tests/ui/redundant_pattern_matching_option.rs:153:5 | LL | / match x { LL | | @@ -177,7 +177,7 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:161:5 + --> tests/ui/redundant_pattern_matching_option.rs:159:5 | LL | / match x { LL | | @@ -187,7 +187,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:167:5 + --> tests/ui/redundant_pattern_matching_option.rs:165:5 | LL | / match x { LL | | @@ -197,7 +197,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:173:5 + --> tests/ui/redundant_pattern_matching_option.rs:171:5 | LL | / match x { LL | | @@ -207,19 +207,19 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:189:13 + --> tests/ui/redundant_pattern_matching_option.rs:187:13 | LL | let _ = matches!(x, Some(_)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:192:13 + --> tests/ui/redundant_pattern_matching_option.rs:190:13 | LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:203:17 + --> tests/ui/redundant_pattern_matching_option.rs:201:17 | LL | let _ = matches!(*p, None); | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index c8e18e8676f2..800889b5fda0 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -1,7 +1,5 @@ -#![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - unused_must_use, clippy::needless_bool, clippy::needless_if, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 727503d21a54..1668c2ff2bba 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -1,7 +1,5 @@ -#![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - unused_must_use, clippy::needless_bool, clippy::needless_if, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 5f659184f7b3..5cd9d9636e46 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:15:12 + --> tests/ui/redundant_pattern_matching_poll.rs:13:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` @@ -8,49 +8,49 @@ LL | if let Pending = Pending::<()> {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:18:12 + --> tests/ui/redundant_pattern_matching_poll.rs:16:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:21:12 + --> tests/ui/redundant_pattern_matching_poll.rs:19:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:29:8 + --> tests/ui/redundant_pattern_matching_poll.rs:27:8 | LL | if matches!(Ready(42), Ready(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:33:8 + --> tests/ui/redundant_pattern_matching_poll.rs:31:8 | LL | if matches!(Pending::<()>, Pending) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:36:15 + --> tests/ui/redundant_pattern_matching_poll.rs:34:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:39:15 + --> tests/ui/redundant_pattern_matching_poll.rs:37:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:42:15 + --> tests/ui/redundant_pattern_matching_poll.rs:40:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:49:5 + --> tests/ui/redundant_pattern_matching_poll.rs:47:5 | LL | / match Ready(42) { LL | | @@ -60,7 +60,7 @@ LL | | }; | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:55:5 + --> tests/ui/redundant_pattern_matching_poll.rs:53:5 | LL | / match Pending::<()> { LL | | @@ -70,7 +70,7 @@ LL | | }; | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:61:13 + --> tests/ui/redundant_pattern_matching_poll.rs:59:13 | LL | let _ = match Pending::<()> { | _____________^ @@ -81,49 +81,49 @@ LL | | }; | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:68:20 + --> tests/ui/redundant_pattern_matching_poll.rs:66:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:73:20 + --> tests/ui/redundant_pattern_matching_poll.rs:71:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:76:19 + --> tests/ui/redundant_pattern_matching_poll.rs:74:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:93:12 + --> tests/ui/redundant_pattern_matching_poll.rs:91:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:96:12 + --> tests/ui/redundant_pattern_matching_poll.rs:94:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:99:15 + --> tests/ui/redundant_pattern_matching_poll.rs:97:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:102:15 + --> tests/ui/redundant_pattern_matching_poll.rs:100:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:105:5 + --> tests/ui/redundant_pattern_matching_poll.rs:103:5 | LL | / match Ready(42) { LL | | @@ -133,7 +133,7 @@ LL | | }; | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:111:5 + --> tests/ui/redundant_pattern_matching_poll.rs:109:5 | LL | / match Pending::<()> { LL | | diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 115879608314..dab816716d59 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -1,6 +1,5 @@ -#![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(deprecated, unused_must_use)] +#![allow(deprecated)] #![allow( clippy::if_same_then_else, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 35f8f91b3152..3fd70515d084 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -1,6 +1,5 @@ -#![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(deprecated, unused_must_use)] +#![allow(deprecated)] #![allow( clippy::if_same_then_else, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index 4f78b95356c2..7e7d27d07a7f 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:15:12 + --> tests/ui/redundant_pattern_matching_result.rs:14:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try: `if result.is_ok()` @@ -8,31 +8,31 @@ LL | if let Ok(_) = &result {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:18:12 + --> tests/ui/redundant_pattern_matching_result.rs:17:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:21:12 + --> tests/ui/redundant_pattern_matching_result.rs:20:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:24:15 + --> tests/ui/redundant_pattern_matching_result.rs:23:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:27:15 + --> tests/ui/redundant_pattern_matching_result.rs:26:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:38:5 + --> tests/ui/redundant_pattern_matching_result.rs:37:5 | LL | / match Ok::(42) { LL | | @@ -42,7 +42,7 @@ LL | | }; | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:44:5 + --> tests/ui/redundant_pattern_matching_result.rs:43:5 | LL | / match Ok::(42) { LL | | @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:50:5 + --> tests/ui/redundant_pattern_matching_result.rs:49:5 | LL | / match Err::(42) { LL | | @@ -62,7 +62,7 @@ LL | | }; | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:56:5 + --> tests/ui/redundant_pattern_matching_result.rs:55:5 | LL | / match Err::(42) { LL | | @@ -72,73 +72,73 @@ LL | | }; | |_____^ help: try: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:62:20 + --> tests/ui/redundant_pattern_matching_result.rs:61:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:71:20 + --> tests/ui/redundant_pattern_matching_result.rs:70:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:74:19 + --> tests/ui/redundant_pattern_matching_result.rs:73:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:98:19 + --> tests/ui/redundant_pattern_matching_result.rs:97:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:100:16 + --> tests/ui/redundant_pattern_matching_result.rs:99:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:107:12 + --> tests/ui/redundant_pattern_matching_result.rs:106:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:109:15 + --> tests/ui/redundant_pattern_matching_result.rs:108:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:128:12 + --> tests/ui/redundant_pattern_matching_result.rs:127:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:131:12 + --> tests/ui/redundant_pattern_matching_result.rs:130:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:134:15 + --> tests/ui/redundant_pattern_matching_result.rs:133:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:137:15 + --> tests/ui/redundant_pattern_matching_result.rs:136:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:140:5 + --> tests/ui/redundant_pattern_matching_result.rs:139:5 | LL | / match Ok::(42) { LL | | @@ -148,7 +148,7 @@ LL | | }; | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:146:5 + --> tests/ui/redundant_pattern_matching_result.rs:145:5 | LL | / match Err::(42) { LL | | @@ -158,7 +158,7 @@ LL | | }; | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:157:5 + --> tests/ui/redundant_pattern_matching_result.rs:156:5 | LL | / match x { LL | | @@ -168,7 +168,7 @@ LL | | }; | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:163:5 + --> tests/ui/redundant_pattern_matching_result.rs:162:5 | LL | / match x { LL | | @@ -178,7 +178,7 @@ LL | | }; | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:169:5 + --> tests/ui/redundant_pattern_matching_result.rs:168:5 | LL | / match x { LL | | @@ -188,7 +188,7 @@ LL | | }; | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:175:5 + --> tests/ui/redundant_pattern_matching_result.rs:174:5 | LL | / match x { LL | | @@ -198,13 +198,13 @@ LL | | }; | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:197:13 + --> tests/ui/redundant_pattern_matching_result.rs:196:13 | LL | let _ = matches!(x, Ok(_)); | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:200:13 + --> tests/ui/redundant_pattern_matching_result.rs:199:13 | LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` diff --git a/tests/ui/redundant_pub_crate.fixed b/tests/ui/redundant_pub_crate.fixed index a6450123f4c9..8a30fedede4a 100644 --- a/tests/ui/redundant_pub_crate.fixed +++ b/tests/ui/redundant_pub_crate.fixed @@ -131,6 +131,14 @@ mod m4 { } } +mod m5 { + pub mod m5_1 {} + // Test that the primary span isn't butchered for item kinds that don't have an ident. + pub use m5_1::*; //~ redundant_pub_crate + #[rustfmt::skip] + pub use m5_1::{*}; //~ redundant_pub_crate +} + pub use m4::*; mod issue_8732 { diff --git a/tests/ui/redundant_pub_crate.rs b/tests/ui/redundant_pub_crate.rs index 7415d34d50cc..45ba13a63b2e 100644 --- a/tests/ui/redundant_pub_crate.rs +++ b/tests/ui/redundant_pub_crate.rs @@ -131,6 +131,14 @@ mod m4 { } } +mod m5 { + pub mod m5_1 {} + // Test that the primary span isn't butchered for item kinds that don't have an ident. + pub(crate) use m5_1::*; //~ redundant_pub_crate + #[rustfmt::skip] + pub(crate) use m5_1::{*}; //~ redundant_pub_crate +} + pub use m4::*; mod issue_8732 { diff --git a/tests/ui/redundant_pub_crate.stderr b/tests/ui/redundant_pub_crate.stderr index 95909ea8b066..4a47a321028d 100644 --- a/tests/ui/redundant_pub_crate.stderr +++ b/tests/ui/redundant_pub_crate.stderr @@ -129,5 +129,21 @@ LL | pub(crate) fn g() {} // private due to m4_2 | | | help: consider using: `pub` -error: aborting due to 16 previous errors +error: pub(crate) import inside private module + --> tests/ui/redundant_pub_crate.rs:137:5 + | +LL | pub(crate) use m5_1::*; + | ----------^^^^^^^^^^^^^ + | | + | help: consider using: `pub` + +error: pub(crate) import inside private module + --> tests/ui/redundant_pub_crate.rs:139:27 + | +LL | pub(crate) use m5_1::{*}; + | ---------- ^ + | | + | help: consider using: `pub` + +error: aborting due to 18 previous errors diff --git a/tests/ui/redundant_test_prefix.fixed b/tests/ui/redundant_test_prefix.fixed new file mode 100644 index 000000000000..b99771f0640c --- /dev/null +++ b/tests/ui/redundant_test_prefix.fixed @@ -0,0 +1,158 @@ +#![allow(dead_code)] +#![warn(clippy::redundant_test_prefix)] + +fn main() { + // Normal function, no redundant prefix. +} + +fn f1() { + // Normal function, no redundant prefix. +} + +fn test_f2() { + // Has prefix, but no `#[test]` attribute, ignore. +} + +#[test] +fn f3() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +#[cfg(test)] +#[test] +fn f4() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +mod m1 { + pub fn f5() {} +} + +#[cfg(test)] +#[test] +fn f6() { + //~^ redundant_test_prefix + + use m1::f5; + + f5(); + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision, has function call, but it will not result in recursion. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn foo() { + //~^ redundant_test_prefix + } + + #[test] + fn foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn f1() { + //~^ redundant_test_prefix + } + + #[test] + fn f2() { + //~^ redundant_test_prefix + } + + #[test] + fn f3() { + //~^ redundant_test_prefix + } + + #[test] + fn f4() { + //~^ redundant_test_prefix + } + + #[test] + fn f5() { + //~^ redundant_test_prefix + } + + #[test] + fn f6() { + //~^ redundant_test_prefix + } +} + +mod tests_no_annotations { + use super::*; + + #[test] + fn foo() { + //~^ redundant_test_prefix + } + + #[test] + fn foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn f1() { + //~^ redundant_test_prefix + } + + #[test] + fn f2() { + //~^ redundant_test_prefix + } + + #[test] + fn f3() { + //~^ redundant_test_prefix + } + + #[test] + fn f4() { + //~^ redundant_test_prefix + } + + #[test] + fn f5() { + //~^ redundant_test_prefix + } + + #[test] + fn f6() { + //~^ redundant_test_prefix + } +} + +// This test is inspired by real test in `clippy_utils/src/sugg.rs`. +// The `is_in_test_function()` checks whether any identifier within a given node's parents is +// marked with `#[test]` attribute. Thus flagging false positives when nested functions are +// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`, +// allowing to select only functions that are immediately marked with `#[test]` annotation. +// +// This test case ensures that for such nested functions no error is emitted. +#[test] +fn not_op() { + fn test_not(foo: bool) { + assert!(foo); + } + + // Use helper function + test_not(true); + test_not(false); +} diff --git a/tests/ui/redundant_test_prefix.rs b/tests/ui/redundant_test_prefix.rs new file mode 100644 index 000000000000..3aec577cffa1 --- /dev/null +++ b/tests/ui/redundant_test_prefix.rs @@ -0,0 +1,158 @@ +#![allow(dead_code)] +#![warn(clippy::redundant_test_prefix)] + +fn main() { + // Normal function, no redundant prefix. +} + +fn f1() { + // Normal function, no redundant prefix. +} + +fn test_f2() { + // Has prefix, but no `#[test]` attribute, ignore. +} + +#[test] +fn test_f3() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +#[cfg(test)] +#[test] +fn test_f4() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +mod m1 { + pub fn f5() {} +} + +#[cfg(test)] +#[test] +fn test_f6() { + //~^ redundant_test_prefix + + use m1::f5; + + f5(); + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision, has function call, but it will not result in recursion. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_foo() { + //~^ redundant_test_prefix + } + + #[test] + fn test_foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn test_f1() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f2() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f3() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f4() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f5() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f6() { + //~^ redundant_test_prefix + } +} + +mod tests_no_annotations { + use super::*; + + #[test] + fn test_foo() { + //~^ redundant_test_prefix + } + + #[test] + fn test_foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn test_f1() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f2() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f3() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f4() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f5() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f6() { + //~^ redundant_test_prefix + } +} + +// This test is inspired by real test in `clippy_utils/src/sugg.rs`. +// The `is_in_test_function()` checks whether any identifier within a given node's parents is +// marked with `#[test]` attribute. Thus flagging false positives when nested functions are +// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`, +// allowing to select only functions that are immediately marked with `#[test]` annotation. +// +// This test case ensures that for such nested functions no error is emitted. +#[test] +fn not_op() { + fn test_not(foo: bool) { + assert!(foo); + } + + // Use helper function + test_not(true); + test_not(false); +} diff --git a/tests/ui/redundant_test_prefix.stderr b/tests/ui/redundant_test_prefix.stderr new file mode 100644 index 000000000000..d156af586df3 --- /dev/null +++ b/tests/ui/redundant_test_prefix.stderr @@ -0,0 +1,119 @@ +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:17:4 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + | + = note: `-D clippy::redundant-test-prefix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_test_prefix)]` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:26:4 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:39:4 + | +LL | fn test_f6() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f6` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:54:8 + | +LL | fn test_foo() { + | ^^^^^^^^ help: consider removing the `test_` prefix: `foo` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:59:8 + | +LL | fn test_foo_with_call() { + | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:66:8 + | +LL | fn test_f1() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f1` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:71:8 + | +LL | fn test_f2() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f2` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:76:8 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:81:8 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:86:8 + | +LL | fn test_f5() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f5` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:91:8 + | +LL | fn test_f6() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f6` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:100:8 + | +LL | fn test_foo() { + | ^^^^^^^^ help: consider removing the `test_` prefix: `foo` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:105:8 + | +LL | fn test_foo_with_call() { + | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:112:8 + | +LL | fn test_f1() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f1` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:117:8 + | +LL | fn test_f2() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f2` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:122:8 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:127:8 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:132:8 + | +LL | fn test_f5() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f5` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix.rs:137:8 + | +LL | fn test_f6() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f6` + +error: aborting due to 19 previous errors + diff --git a/tests/ui/redundant_test_prefix_noautofix.rs b/tests/ui/redundant_test_prefix_noautofix.rs new file mode 100644 index 000000000000..6ad5d011d8b7 --- /dev/null +++ b/tests/ui/redundant_test_prefix_noautofix.rs @@ -0,0 +1,288 @@ +//@no-rustfix: name conflicts + +#![allow(dead_code)] +#![warn(clippy::redundant_test_prefix)] + +fn main() { + // Normal function, no redundant prefix. +} + +fn f1() { + // Normal function, no redundant prefix. +} + +fn test_f2() { + // Has prefix, but no `#[test]` attribute, ignore. +} + +#[test] +fn test_f3() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +#[cfg(test)] +#[test] +fn test_f4() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. +} + +fn f5() {} + +#[cfg(test)] +#[test] +fn test_f5() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // Collision with existing function. +} + +mod m1 { + pub fn f6() {} + pub fn f7() {} +} + +#[cfg(test)] +#[test] +fn test_f6() { + //~^ redundant_test_prefix + + use m1::f6; + + f6(); + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision, but has a function call that will result in recursion. +} + +#[cfg(test)] +#[test] +fn test_f8() { + //~^ redundant_test_prefix + + use m1::f7; + + f7(); + // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`. + // No collision, has function call, but it will not result in recursion. +} + +// Although there's no direct call of `f` in the test, name collision still exists, +// since all `m3` functions are imported and then `map` is used to call `f`. +mod m2 { + mod m3 { + pub fn f(_: i32) -> i32 { + 0 + } + } + + use m3::*; + + #[cfg(test)] + #[test] + fn test_f() { + //~^ redundant_test_prefix + let a = Some(3); + let _ = a.map(f); + } +} + +mod m3 { + fn test_m3_1() { + // Has prefix, but no `#[test]` attribute, ignore. + } + + #[test] + fn test_m3_2() { + //~^ redundant_test_prefix + + // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`. + // No collision with other functions, should emit warning. + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_foo() { + //~^ redundant_test_prefix + } + + #[test] + fn test_foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn test_f1() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f2() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f3() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f4() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f5() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f6() { + //~^ redundant_test_prefix + } + + #[test] + fn test_1() { + //~^ redundant_test_prefix + + // `1` is invalid function name, so suggestion to rename is emitted + } + + #[test] + fn test_const() { + //~^ redundant_test_prefix + + // `const` is reserved keyword, so suggestion to rename is emitted + } + + #[test] + fn test_async() { + //~^ redundant_test_prefix + + // `async` is reserved keyword, so suggestion to rename is emitted + } + + #[test] + fn test_yield() { + //~^ redundant_test_prefix + + // `yield` is reserved keyword for future use, so suggestion to rename is emitted + } + + #[test] + fn test_() { + //~^ redundant_test_prefix + + // `` is invalid function name, so suggestion to rename is emitted + } +} + +mod tests_no_annotations { + use super::*; + + #[test] + fn test_foo() { + //~^ redundant_test_prefix + } + + #[test] + fn test_foo_with_call() { + //~^ redundant_test_prefix + + main(); + } + + #[test] + fn test_f1() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f2() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f3() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f4() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f5() { + //~^ redundant_test_prefix + } + + #[test] + fn test_f6() { + //~^ redundant_test_prefix + } + + #[test] + fn test_1() { + //~^ redundant_test_prefix + + // `1` is invalid function name, so suggestion to rename is emitted + } + + #[test] + fn test_const() { + //~^ redundant_test_prefix + + // `const` is reserved keyword, so suggestion to rename is emitted + } + + #[test] + fn test_async() { + //~^ redundant_test_prefix + + // `async` is reserved keyword, so suggestion to rename is emitted + } + + #[test] + fn test_yield() { + //~^ redundant_test_prefix + + // `yield` is reserved keyword for future use, so suggestion to rename is emitted + } + + #[test] + fn test_() { + //~^ redundant_test_prefix + + // `` is invalid function name, so suggestion to rename is emitted + } +} + +// This test is inspired by real test in `clippy_utils/src/sugg.rs`. +// The `is_in_test_function()` checks whether any identifier within a given node's parents is +// marked with `#[test]` attribute. Thus flagging false positives when nested functions are +// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`, +// allowing to select only functions that are immediately marked with `#[test]` annotation. +// +// This test case ensures that for such nested functions no error is emitted. +#[test] +fn not_op() { + fn test_not(foo: bool) { + assert!(foo); + } + + // Use helper function + test_not(true); + test_not(false); +} diff --git a/tests/ui/redundant_test_prefix_noautofix.stderr b/tests/ui/redundant_test_prefix_noautofix.stderr new file mode 100644 index 000000000000..6440faf1b3c8 --- /dev/null +++ b/tests/ui/redundant_test_prefix_noautofix.stderr @@ -0,0 +1,241 @@ +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:19:4 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + | + = note: `-D clippy::redundant-test-prefix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_test_prefix)]` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:28:4 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:39:4 + | +LL | fn test_f5() { + | ^^^^^^^ + | +help: consider function renaming (just removing `test_` prefix will cause a name conflict) + | +LL - fn test_f5() { +LL + fn f5_works() { + | + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:53:4 + | +LL | fn test_f6() { + | ^^^^^^^ + | +help: consider function renaming (just removing `test_` prefix will cause a name conflict) + | +LL - fn test_f6() { +LL + fn f6_works() { + | + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:65:4 + | +LL | fn test_f8() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f8` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:88:8 + | +LL | fn test_f() { + | ^^^^^^ + | +help: consider function renaming (just removing `test_` prefix will cause a name conflict) + | +LL - fn test_f() { +LL + fn f_works() { + | + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:101:8 + | +LL | fn test_m3_2() { + | ^^^^^^^^^ help: consider removing the `test_` prefix: `m3_2` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:114:8 + | +LL | fn test_foo() { + | ^^^^^^^^ help: consider removing the `test_` prefix: `foo` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:119:8 + | +LL | fn test_foo_with_call() { + | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:126:8 + | +LL | fn test_f1() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f1` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:131:8 + | +LL | fn test_f2() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f2` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:136:8 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:141:8 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:146:8 + | +LL | fn test_f5() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f5` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:151:8 + | +LL | fn test_f6() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f6` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:156:8 + | +LL | fn test_1() { + | ^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:163:8 + | +LL | fn test_const() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:170:8 + | +LL | fn test_async() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:177:8 + | +LL | fn test_yield() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:184:8 + | +LL | fn test_() { + | ^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:195:8 + | +LL | fn test_foo() { + | ^^^^^^^^ help: consider removing the `test_` prefix: `foo` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:200:8 + | +LL | fn test_foo_with_call() { + | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:207:8 + | +LL | fn test_f1() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f1` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:212:8 + | +LL | fn test_f2() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f2` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:217:8 + | +LL | fn test_f3() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f3` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:222:8 + | +LL | fn test_f4() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f4` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:227:8 + | +LL | fn test_f5() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f5` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:232:8 + | +LL | fn test_f6() { + | ^^^^^^^ help: consider removing the `test_` prefix: `f6` + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:237:8 + | +LL | fn test_1() { + | ^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:244:8 + | +LL | fn test_const() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:251:8 + | +LL | fn test_async() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:258:8 + | +LL | fn test_yield() { + | ^^^^^^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: redundant `test_` prefix in test function name + --> tests/ui/redundant_test_prefix_noautofix.rs:265:8 + | +LL | fn test_() { + | ^^^^^ + | + = help: consider function renaming (just removing `test_` prefix will produce invalid function name) + +error: aborting due to 33 previous errors + diff --git a/tests/ui/ref_option/ref_option_traits.all.stderr b/tests/ui/ref_option/ref_option_traits.all.stderr index 030a9a28ec68..886bf2b03498 100644 --- a/tests/ui/ref_option/ref_option_traits.all.stderr +++ b/tests/ui/ref_option/ref_option_traits.all.stderr @@ -1,5 +1,5 @@ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:10:5 + --> tests/ui/ref_option/ref_option_traits.rs:9:5 | LL | fn pub_trait_opt(&self, a: &Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^ @@ -10,7 +10,7 @@ LL | fn pub_trait_opt(&self, a: &Option>); = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:12:5 + --> tests/ui/ref_option/ref_option_traits.rs:11:5 | LL | fn pub_trait_ret(&self) -> &Option>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^ @@ -18,7 +18,7 @@ LL | fn pub_trait_ret(&self) -> &Option>; | help: change this to: `Option<&Vec>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:17:5 + --> tests/ui/ref_option/ref_option_traits.rs:16:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -26,7 +26,7 @@ LL | fn trait_opt(&self, a: &Option); | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:19:5 + --> tests/ui/ref_option/ref_option_traits.rs:18:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ diff --git a/tests/ui/ref_option/ref_option_traits.private.stderr b/tests/ui/ref_option/ref_option_traits.private.stderr index 2837ee80fb2e..cfab7fa5734c 100644 --- a/tests/ui/ref_option/ref_option_traits.private.stderr +++ b/tests/ui/ref_option/ref_option_traits.private.stderr @@ -1,5 +1,5 @@ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:17:5 + --> tests/ui/ref_option/ref_option_traits.rs:16:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -10,7 +10,7 @@ LL | fn trait_opt(&self, a: &Option); = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:19:5 + --> tests/ui/ref_option/ref_option_traits.rs:18:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ diff --git a/tests/ui/ref_option/ref_option_traits.rs b/tests/ui/ref_option/ref_option_traits.rs index 811da2eb4d50..4c773e84f8da 100644 --- a/tests/ui/ref_option/ref_option_traits.rs +++ b/tests/ui/ref_option/ref_option_traits.rs @@ -3,7 +3,6 @@ //@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private //@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all -#![allow(unused, clippy::all)] #![warn(clippy::ref_option)] pub trait PubTrait { diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 796404706968..acf7914d2536 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -13,8 +13,9 @@ #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_filter_map)] #![allow(clippy::manual_find_map)] +#![allow(clippy::manual_filter_map)] +#![allow(unpredictable_function_pointer_comparisons)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] @@ -29,7 +30,6 @@ #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] -#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::missing_const_for_thread_local)] @@ -39,11 +39,11 @@ #![allow(invalid_reference_casting)] #![allow(suspicious_double_ref_op)] #![allow(invalid_nan_comparisons)] +#![allow(invalid_null_arguments)] #![allow(double_negations)] #![allow(drop_bounds)] #![allow(dropping_copy_types)] #![allow(dropping_references)] -#![allow(unpredictable_function_pointer_comparisons)] #![allow(useless_ptr_null_checks)] #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] @@ -62,6 +62,7 @@ #![allow(unknown_lints)] #![allow(unused_labels)] #![allow(ambiguous_wide_pointer_comparisons)] +#![allow(clippy::reversed_empty_ranges)] #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr` @@ -74,8 +75,9 @@ #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type` #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map` #![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map` +#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result` @@ -94,7 +96,6 @@ #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` -#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter` #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` @@ -104,11 +105,11 @@ #![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut` #![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref` #![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan` +#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(double_negations)] //~ ERROR: lint `clippy::double_neg` #![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` #![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy` #![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref` -#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` #![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check` #![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option` #![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result` @@ -119,7 +120,6 @@ #![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` #![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` #![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` #![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` @@ -131,5 +131,6 @@ #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` +#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` fn main() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index aa7b905b4b81..32641a684a44 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -13,8 +13,9 @@ #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_filter_map)] #![allow(clippy::manual_find_map)] +#![allow(clippy::manual_filter_map)] +#![allow(unpredictable_function_pointer_comparisons)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] @@ -29,7 +30,6 @@ #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] -#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::missing_const_for_thread_local)] @@ -39,11 +39,11 @@ #![allow(invalid_reference_casting)] #![allow(suspicious_double_ref_op)] #![allow(invalid_nan_comparisons)] +#![allow(invalid_null_arguments)] #![allow(double_negations)] #![allow(drop_bounds)] #![allow(dropping_copy_types)] #![allow(dropping_references)] -#![allow(unpredictable_function_pointer_comparisons)] #![allow(useless_ptr_null_checks)] #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] @@ -62,6 +62,7 @@ #![allow(unknown_lints)] #![allow(unused_labels)] #![allow(ambiguous_wide_pointer_comparisons)] +#![allow(clippy::reversed_empty_ranges)] #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr` @@ -74,8 +75,9 @@ #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type` #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map` #![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map` +#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result` @@ -94,7 +96,6 @@ #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` -#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter` #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` @@ -104,11 +105,11 @@ #![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut` #![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref` #![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan` +#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg` #![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` #![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy` #![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref` -#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` #![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check` #![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option` #![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result` @@ -119,7 +120,6 @@ #![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` #![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` #![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` #![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` @@ -131,5 +131,6 @@ #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label` #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` +#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index b3c88167c111..e9d2debff91a 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> tests/ui/rename.rs:65:9 + --> tests/ui/rename.rs:66:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,347 +8,341 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:67:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:73:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:74:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:75:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:76:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` -error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` - --> tests/ui/rename.rs:77:9 - | -LL | #![warn(clippy::filter_map)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` - error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::find_map)] | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` -error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` +error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` --> tests/ui/rename.rs:79:9 | +LL | #![warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` + +error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` + --> tests/ui/rename.rs:80:9 + | +LL | #![warn(clippy::fn_address_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` + +error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` + --> tests/ui/rename.rs:81:9 + | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:82:9 | LL | #![warn(clippy::if_let_redundant_pattern_matching)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:83:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:85:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:89:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::overflow_check_conditional)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:97:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` -error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` - --> tests/ui/rename.rs:97:9 - | -LL | #![warn(clippy::reverse_range_loop)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` - error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:101:9 | LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:102:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:105:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` +error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` + --> tests/ui/rename.rs:108:9 + | +LL | #![warn(clippy::invalid_null_ptr_usage)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` + error: lint `clippy::double_neg` has been renamed to `double_negations` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::double_neg)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` -error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` - --> tests/ui/rename.rs:111:9 - | -LL | #![warn(clippy::fn_address_comparisons)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` - error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:114:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:115:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:116:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:117:9 + --> tests/ui/rename.rs:118:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:118:9 + --> tests/ui/rename.rs:119:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> tests/ui/rename.rs:119:9 + --> tests/ui/rename.rs:120:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> tests/ui/rename.rs:120:9 + --> tests/ui/rename.rs:121:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:121:9 + --> tests/ui/rename.rs:122:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` -error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` - --> tests/ui/rename.rs:122:9 - | -LL | #![warn(clippy::invalid_null_ptr_usage)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` - error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` --> tests/ui/rename.rs:123:9 | @@ -415,5 +409,11 @@ error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_ LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` +error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` + --> tests/ui/rename.rs:134:9 + | +LL | #![warn(clippy::reverse_range_loop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` + error: aborting due to 69 previous errors diff --git a/tests/ui/repr_packed_without_abi.stderr b/tests/ui/repr_packed_without_abi.stderr index d1078b3e8e48..f688e4bc744a 100644 --- a/tests/ui/repr_packed_without_abi.stderr +++ b/tests/ui/repr_packed_without_abi.stderr @@ -11,7 +11,7 @@ LL | | } | |_^ | = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI - = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` + = help: qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` note: the lint level is defined here --> tests/ui/repr_packed_without_abi.rs:1:9 | @@ -31,7 +31,7 @@ LL | | } | |_^ | = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI - = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` + = help: qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` error: aborting due to 2 previous errors diff --git a/tests/ui/result_unit_error_no_std.rs b/tests/ui/result_unit_error_no_std.rs index 8a1849b8490a..a64e8414d78f 100644 --- a/tests/ui/result_unit_error_no_std.rs +++ b/tests/ui/result_unit_error_no_std.rs @@ -14,7 +14,7 @@ pub fn returns_unit_error_lint() -> Result { Err(()) } -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { 0 } diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 847e5140d3e6..cc4dbc919d81 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -214,10 +214,9 @@ mod issue7392 { } fn ref_bindings() { - let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); - //~^ search_is_some - let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); - //~^ search_is_some + let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)] + //~^ search_is_some + .iter().any(|&&(&x, ref y)| x == *y); } fn test_string_1(s: &str) -> bool { diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index e976d12600cc..fa31a9ddedc6 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -221,10 +221,11 @@ mod issue7392 { } fn ref_bindings() { - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); - //~^ search_is_some - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); - //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + //~^ search_is_some + .iter() + .find(|&&&(&x, ref y)| x == *y) + .is_none(); } fn test_string_1(s: &str) -> bool { diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index ccc17025222d..b079cf7ea361 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -248,116 +248,122 @@ LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); error: called `is_none()` after searching an `Iterator` with `find` --> tests/ui/search_is_some_fixable_none.rs:224:17 | -LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` - -error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:226:17 +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + | _________________^ +LL | | +LL | | .iter() +LL | | .find(|&&&(&x, ref y)| x == *y) +LL | | .is_none(); + | |______________________^ + | +help: consider using + | +LL ~ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)] +LL + +LL ~ .iter().any(|&&(&x, ref y)| x == *y); | -LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:246:17 + --> tests/ui/search_is_some_fixable_none.rs:247:17 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| s[0].is_empty())` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:248:17 + --> tests/ui/search_is_some_fixable_none.rs:249:17 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| test_string_1(&s[0]))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:258:17 + --> tests/ui/search_is_some_fixable_none.rs:259:17 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| fp.field.is_power_of_two())` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:260:17 + --> tests/ui/search_is_some_fixable_none.rs:261:17 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_1(fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:262:17 + --> tests/ui/search_is_some_fixable_none.rs:263:17 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:279:17 + --> tests/ui/search_is_some_fixable_none.rs:280:17 | LL | let _ = v.iter().find(|x| **x == 42).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:281:17 + --> tests/ui/search_is_some_fixable_none.rs:282:17 | LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:287:9 + --> tests/ui/search_is_some_fixable_none.rs:288:9 | LL | v.iter().find(|x| **x == 42).is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:293:9 + --> tests/ui/search_is_some_fixable_none.rs:294:9 | LL | v.iter().find(|x| **x == 42).is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:299:17 + --> tests/ui/search_is_some_fixable_none.rs:300:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:301:17 + --> tests/ui/search_is_some_fixable_none.rs:302:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:304:17 + --> tests/ui/search_is_some_fixable_none.rs:305:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:306:17 + --> tests/ui/search_is_some_fixable_none.rs:307:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:312:17 + --> tests/ui/search_is_some_fixable_none.rs:313:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:315:17 + --> tests/ui/search_is_some_fixable_none.rs:316:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:321:17 + --> tests/ui/search_is_some_fixable_none.rs:322:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:324:17 + --> tests/ui/search_is_some_fixable_none.rs:325:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` -error: aborting due to 55 previous errors +error: aborting due to 54 previous errors diff --git a/tests/ui/search_is_some_fixable_none_2021.fixed b/tests/ui/search_is_some_fixable_none_2021.fixed new file mode 100644 index 000000000000..6e15244901c2 --- /dev/null +++ b/tests/ui/search_is_some_fixable_none_2021.fixed @@ -0,0 +1,14 @@ +//@edition: 2021 +#![warn(clippy::search_is_some)] + +fn main() { + fn ref_bindings() { + let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some + let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some + let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)] + //~^ search_is_some + .iter().any(|&&(&x, ref y)| x == *y); + } +} diff --git a/tests/ui/search_is_some_fixable_none_2021.rs b/tests/ui/search_is_some_fixable_none_2021.rs new file mode 100644 index 000000000000..4b1db3f9fc32 --- /dev/null +++ b/tests/ui/search_is_some_fixable_none_2021.rs @@ -0,0 +1,16 @@ +//@edition: 2021 +#![warn(clippy::search_is_some)] + +fn main() { + fn ref_bindings() { + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); + //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); + //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + //~^ search_is_some + .iter() + .find(|&&&(&x, ref y)| x == *y) + .is_none(); + } +} diff --git a/tests/ui/search_is_some_fixable_none_2021.stderr b/tests/ui/search_is_some_fixable_none_2021.stderr new file mode 100644 index 000000000000..af93be1a7071 --- /dev/null +++ b/tests/ui/search_is_some_fixable_none_2021.stderr @@ -0,0 +1,35 @@ +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none_2021.rs:6:17 + | +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none_2021.rs:8:17 + | +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none_2021.rs:10:17 + | +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + | _________________^ +LL | | +LL | | .iter() +LL | | .find(|&&&(&x, ref y)| x == *y) +LL | | .is_none(); + | |______________________^ + | +help: consider using + | +LL ~ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)] +LL + +LL ~ .iter().any(|&&(&x, ref y)| x == *y); + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 05e88b8528f1..42b39b33b575 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -214,10 +214,9 @@ mod issue7392 { } fn ref_bindings() { - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); - //~^ search_is_some - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); - //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + .iter() + .any(|&&(&x, ref y)| x == *y); } fn test_string_1(s: &str) -> bool { diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index caab816f2436..ca4f4d941cb2 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -220,10 +220,11 @@ mod issue7392 { } fn ref_bindings() { - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); - //~^ search_is_some - let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); - //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)] + .iter() + .find(|&&&(&x, ref y)| x == *y) + //~^ search_is_some + .is_some(); } fn test_string_1(s: &str) -> bool { diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index af719b78831a..8291f48d43c4 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -227,70 +227,67 @@ LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.by_ref(&v.bar))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:223:55 + --> tests/ui/search_is_some_fixable_some.rs:225:14 | -LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` +LL | .find(|&&&(&x, ref y)| x == *y) + | ______________^ +LL | | +LL | | .is_some(); + | |______________________^ help: consider using: `any(|&&(&x, ref y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:225:55 - | -LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` - -error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:245:26 + --> tests/ui/search_is_some_fixable_some.rs:246:26 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s[0].is_empty())` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:247:26 + --> tests/ui/search_is_some_fixable_some.rs:248:26 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| test_string_1(&s[0]))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:257:26 + --> tests/ui/search_is_some_fixable_some.rs:258:26 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| fp.field.is_power_of_two())` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:259:26 + --> tests/ui/search_is_some_fixable_some.rs:260:26 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_1(fp.field))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:261:26 + --> tests/ui/search_is_some_fixable_some.rs:262:26 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_2(*fp.field))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:277:18 + --> tests/ui/search_is_some_fixable_some.rs:278:18 | LL | v.iter().find(|x: &&u32| func(x)).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| func(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:287:26 + --> tests/ui/search_is_some_fixable_some.rs:288:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_impl(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:291:26 + --> tests/ui/search_is_some_fixable_some.rs:292:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_dyn(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:295:26 + --> tests/ui/search_is_some_fixable_some.rs:296:26 | LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` -error: aborting due to 47 previous errors +error: aborting due to 46 previous errors diff --git a/tests/ui/search_is_some_fixable_some_2021.fixed b/tests/ui/search_is_some_fixable_some_2021.fixed new file mode 100644 index 000000000000..d2b05db562a0 --- /dev/null +++ b/tests/ui/search_is_some_fixable_some_2021.fixed @@ -0,0 +1,11 @@ +//@edition: 2021 +#![warn(clippy::search_is_some)] + +fn main() { + fn ref_bindings() { + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some + } +} diff --git a/tests/ui/search_is_some_fixable_some_2021.rs b/tests/ui/search_is_some_fixable_some_2021.rs new file mode 100644 index 000000000000..c3f5ef769dab --- /dev/null +++ b/tests/ui/search_is_some_fixable_some_2021.rs @@ -0,0 +1,11 @@ +//@edition: 2021 +#![warn(clippy::search_is_some)] + +fn main() { + fn ref_bindings() { + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); + //~^ search_is_some + let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); + //~^ search_is_some + } +} diff --git a/tests/ui/search_is_some_fixable_some_2021.stderr b/tests/ui/search_is_some_fixable_some_2021.stderr new file mode 100644 index 000000000000..91d9540e6fcf --- /dev/null +++ b/tests/ui/search_is_some_fixable_some_2021.stderr @@ -0,0 +1,17 @@ +error: called `is_some()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_some_2021.rs:6:55 + | +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` + +error: called `is_some()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_some_2021.rs:8:55 + | +LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 7d503a1cf6c1..05009b2ddd41 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -167,4 +167,19 @@ fn issue13795(value: Issue13795) { //~^ shadow_same } +fn issue14377() { + let a; + let b; + (a, b) = (0, 1); + + struct S { + c: i32, + d: i32, + } + + let c; + let d; + S { c, d } = S { c: 1, d: 2 }; +} + fn main() {} diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs index 4ec0f02d6645..53704f59cb99 100644 --- a/tests/ui/should_impl_trait/corner_cases.rs +++ b/tests/ui/should_impl_trait/corner_cases.rs @@ -1,6 +1,5 @@ //@ check-pass -#![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, clippy::needless_pass_by_value, diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs index 87b3a7d2fa0c..e8de0e04c0c4 100644 --- a/tests/ui/should_impl_trait/method_list_1.rs +++ b/tests/ui/should_impl_trait/method_list_1.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, clippy::needless_pass_by_value, diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 8738b61192a3..5609d6a21a36 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -1,5 +1,5 @@ error: method `add` can be confused for the standard trait method `std::ops::Add::add` - --> tests/ui/should_impl_trait/method_list_1.rs:25:5 + --> tests/ui/should_impl_trait/method_list_1.rs:24:5 | LL | / pub fn add(self, other: T) -> T { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:31:5 + --> tests/ui/should_impl_trait/method_list_1.rs:30:5 | LL | / pub fn as_mut(&mut self) -> &mut T { LL | | @@ -25,7 +25,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` - --> tests/ui/should_impl_trait/method_list_1.rs:37:5 + --> tests/ui/should_impl_trait/method_list_1.rs:36:5 | LL | / pub fn as_ref(&self) -> &T { LL | | @@ -37,7 +37,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` - --> tests/ui/should_impl_trait/method_list_1.rs:43:5 + --> tests/ui/should_impl_trait/method_list_1.rs:42:5 | LL | / pub fn bitand(self, rhs: T) -> T { LL | | @@ -49,7 +49,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` - --> tests/ui/should_impl_trait/method_list_1.rs:49:5 + --> tests/ui/should_impl_trait/method_list_1.rs:48:5 | LL | / pub fn bitor(self, rhs: Self) -> Self { LL | | @@ -61,7 +61,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` - --> tests/ui/should_impl_trait/method_list_1.rs:55:5 + --> tests/ui/should_impl_trait/method_list_1.rs:54:5 | LL | / pub fn bitxor(self, rhs: Self) -> Self { LL | | @@ -73,7 +73,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` - --> tests/ui/should_impl_trait/method_list_1.rs:61:5 + --> tests/ui/should_impl_trait/method_list_1.rs:60:5 | LL | / pub fn borrow(&self) -> &str { LL | | @@ -85,7 +85,7 @@ LL | | } = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:67:5 + --> tests/ui/should_impl_trait/method_list_1.rs:66:5 | LL | / pub fn borrow_mut(&mut self) -> &mut str { LL | | @@ -97,7 +97,7 @@ LL | | } = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` - --> tests/ui/should_impl_trait/method_list_1.rs:73:5 + --> tests/ui/should_impl_trait/method_list_1.rs:72:5 | LL | / pub fn clone(&self) -> Self { LL | | @@ -109,7 +109,7 @@ LL | | } = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` - --> tests/ui/should_impl_trait/method_list_1.rs:79:5 + --> tests/ui/should_impl_trait/method_list_1.rs:78:5 | LL | / pub fn cmp(&self, other: &Self) -> Self { LL | | @@ -121,7 +121,7 @@ LL | | } = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name error: method `default` can be confused for the standard trait method `std::default::Default::default` - --> tests/ui/should_impl_trait/method_list_1.rs:85:5 + --> tests/ui/should_impl_trait/method_list_1.rs:84:5 | LL | / pub fn default() -> Self { LL | | @@ -133,7 +133,7 @@ LL | | } = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` - --> tests/ui/should_impl_trait/method_list_1.rs:91:5 + --> tests/ui/should_impl_trait/method_list_1.rs:90:5 | LL | / pub fn deref(&self) -> &Self { LL | | @@ -145,7 +145,7 @@ LL | | } = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:97:5 + --> tests/ui/should_impl_trait/method_list_1.rs:96:5 | LL | / pub fn deref_mut(&mut self) -> &mut Self { LL | | @@ -157,7 +157,7 @@ LL | | } = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name error: method `div` can be confused for the standard trait method `std::ops::Div::div` - --> tests/ui/should_impl_trait/method_list_1.rs:103:5 + --> tests/ui/should_impl_trait/method_list_1.rs:102:5 | LL | / pub fn div(self, rhs: Self) -> Self { LL | | @@ -169,7 +169,7 @@ LL | | } = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` - --> tests/ui/should_impl_trait/method_list_1.rs:109:5 + --> tests/ui/should_impl_trait/method_list_1.rs:108:5 | LL | / pub fn drop(&mut self) { LL | | diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs index f0c4d4f15cb6..1f25ab3938a3 100644 --- a/tests/ui/should_impl_trait/method_list_2.rs +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -1,4 +1,3 @@ -#![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, clippy::needless_pass_by_value, diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index 85de74337020..0f5818507779 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -1,5 +1,5 @@ error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` - --> tests/ui/should_impl_trait/method_list_2.rs:26:5 + --> tests/ui/should_impl_trait/method_list_2.rs:25:5 | LL | / pub fn eq(&self, other: &Self) -> bool { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` - --> tests/ui/should_impl_trait/method_list_2.rs:32:5 + --> tests/ui/should_impl_trait/method_list_2.rs:31:5 | LL | / pub fn from_iter(iter: T) -> Self { LL | | @@ -25,7 +25,7 @@ LL | | } = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` - --> tests/ui/should_impl_trait/method_list_2.rs:38:5 + --> tests/ui/should_impl_trait/method_list_2.rs:37:5 | LL | / pub fn from_str(s: &str) -> Result { LL | | @@ -37,7 +37,7 @@ LL | | } = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` - --> tests/ui/should_impl_trait/method_list_2.rs:44:5 + --> tests/ui/should_impl_trait/method_list_2.rs:43:5 | LL | / pub fn hash(&self, state: &mut T) { LL | | @@ -49,7 +49,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> tests/ui/should_impl_trait/method_list_2.rs:50:5 + --> tests/ui/should_impl_trait/method_list_2.rs:49:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | @@ -61,7 +61,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> tests/ui/should_impl_trait/method_list_2.rs:56:5 + --> tests/ui/should_impl_trait/method_list_2.rs:55:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | @@ -73,7 +73,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> tests/ui/should_impl_trait/method_list_2.rs:62:5 + --> tests/ui/should_impl_trait/method_list_2.rs:61:5 | LL | / pub fn into_iter(self) -> Self { LL | | @@ -85,7 +85,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> tests/ui/should_impl_trait/method_list_2.rs:68:5 + --> tests/ui/should_impl_trait/method_list_2.rs:67:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | @@ -97,7 +97,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> tests/ui/should_impl_trait/method_list_2.rs:74:5 + --> tests/ui/should_impl_trait/method_list_2.rs:73:5 | LL | / pub fn neg(self) -> Self { LL | | @@ -109,7 +109,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> tests/ui/should_impl_trait/method_list_2.rs:80:5 + --> tests/ui/should_impl_trait/method_list_2.rs:79:5 | LL | / pub fn next(&mut self) -> Option { LL | | @@ -121,7 +121,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> tests/ui/should_impl_trait/method_list_2.rs:86:5 + --> tests/ui/should_impl_trait/method_list_2.rs:85:5 | LL | / pub fn not(self) -> Self { LL | | @@ -133,7 +133,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> tests/ui/should_impl_trait/method_list_2.rs:92:5 + --> tests/ui/should_impl_trait/method_list_2.rs:91:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | @@ -145,7 +145,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> tests/ui/should_impl_trait/method_list_2.rs:98:5 + --> tests/ui/should_impl_trait/method_list_2.rs:97:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | @@ -157,7 +157,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> tests/ui/should_impl_trait/method_list_2.rs:104:5 + --> tests/ui/should_impl_trait/method_list_2.rs:103:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | @@ -169,7 +169,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> tests/ui/should_impl_trait/method_list_2.rs:110:5 + --> tests/ui/should_impl_trait/method_list_2.rs:109:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | diff --git a/tests/ui/single_call_fn.rs b/tests/ui/single_call_fn.rs index c1cc4032bec9..a1ecd7bc166c 100644 --- a/tests/ui/single_call_fn.rs +++ b/tests/ui/single_call_fn.rs @@ -94,7 +94,7 @@ trait Trait { //~^ single_call_fn fn foo(&self); } -extern "C" { +unsafe extern "C" { // test some kind of foreign item fn rand() -> std::ffi::c_int; } diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 0e198ec79344..db5107600ee6 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -366,3 +366,39 @@ fn irrefutable_match() { //~^^^^^^^^^ single_match //~| NOTE: you might want to preserve the comments from inside the `match` } + +fn issue_14493() { + macro_rules! mac { + (some) => { + Some(42) + }; + (any) => { + _ + }; + (str) => { + "foo" + }; + } + + if let Some(u) = mac!(some) { println!("{u}") } + //~^^^^ single_match + + // When scrutinee comes from macro, do not tell that arm will always match + // and suggest an equality check instead. + if mac!(str) == "foo" { println!("eq") } + //~^^^^ ERROR: for an equality check + + // Do not lint if any match arm come from expansion + match Some(0) { + mac!(some) => println!("eq"), + mac!(any) => println!("neq"), + } + match Some(0) { + Some(42) => println!("eq"), + mac!(any) => println!("neq"), + } + match Some(0) { + mac!(some) => println!("eq"), + _ => println!("neq"), + } +} diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index fcac65f8aaf5..a367b94c4ca6 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -461,3 +461,45 @@ fn irrefutable_match() { //~^^^^^^^^^ single_match //~| NOTE: you might want to preserve the comments from inside the `match` } + +fn issue_14493() { + macro_rules! mac { + (some) => { + Some(42) + }; + (any) => { + _ + }; + (str) => { + "foo" + }; + } + + match mac!(some) { + Some(u) => println!("{u}"), + _ => (), + } + //~^^^^ single_match + + // When scrutinee comes from macro, do not tell that arm will always match + // and suggest an equality check instead. + match mac!(str) { + "foo" => println!("eq"), + _ => (), + } + //~^^^^ ERROR: for an equality check + + // Do not lint if any match arm come from expansion + match Some(0) { + mac!(some) => println!("eq"), + mac!(any) => println!("neq"), + } + match Some(0) { + Some(42) => println!("eq"), + mac!(any) => println!("neq"), + } + match Some(0) { + mac!(some) => println!("eq"), + _ => println!("neq"), + } +} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 2467423b9c17..1a4edc45c928 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -321,5 +321,23 @@ LL + println!("{u}"); LL + } | -error: aborting due to 29 previous errors +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> tests/ui/single_match.rs:478:5 + | +LL | / match mac!(some) { +LL | | Some(u) => println!("{u}"), +LL | | _ => (), +LL | | } + | |_____^ help: try: `if let Some(u) = mac!(some) { println!("{u}") }` + +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match.rs:486:5 + | +LL | / match mac!(str) { +LL | | "foo" => println!("eq"), +LL | | _ => (), +LL | | } + | |_____^ help: try: `if mac!(str) == "foo" { println!("eq") }` + +error: aborting due to 31 previous errors diff --git a/tests/ui/suspicious_doc_comments.fixed b/tests/ui/suspicious_doc_comments.fixed index 3696b0e066d2..3faa4b21ee41 100644 --- a/tests/ui/suspicious_doc_comments.fixed +++ b/tests/ui/suspicious_doc_comments.fixed @@ -87,4 +87,8 @@ pub mod useless_outer_doc { use std::mem; } +// Do not lint, this is not a `///!` +#[doc = "! here's some docs !"] +fn issue14265() {} + fn main() {} diff --git a/tests/ui/suspicious_doc_comments.rs b/tests/ui/suspicious_doc_comments.rs index 4107f5526d13..4af6ed850c2b 100644 --- a/tests/ui/suspicious_doc_comments.rs +++ b/tests/ui/suspicious_doc_comments.rs @@ -87,4 +87,8 @@ pub mod useless_outer_doc { use std::mem; } +// Do not lint, this is not a `///!` +#[doc = "! here's some docs !"] +fn issue14265() {} + fn main() {} diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 888665a17ad1..6a64e64e98fa 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -1,14 +1,9 @@ //@aux-build: macro_rules.rs -#![warn(clippy::all)] #![allow( clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, - redundant_semicolons, - dead_code, - unused_assignments, - unused_variables, clippy::let_and_return, clippy::useless_vec, clippy::redundant_locals diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 51af55ecd27c..e2d89c47382d 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,14 +1,9 @@ //@aux-build: macro_rules.rs -#![warn(clippy::all)] #![allow( clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, - redundant_semicolons, - dead_code, - unused_assignments, - unused_variables, clippy::let_and_return, clippy::useless_vec, clippy::redundant_locals diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 15f7566d5896..195b888187e6 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> tests/ui/swap.rs:28:5 + --> tests/ui/swap.rs:23:5 | LL | / let temp = bar.a; LL | | @@ -12,7 +12,7 @@ LL | | bar.b = temp; = help: to override `-D warnings` add `#[allow(clippy::manual_swap)]` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:41:5 + --> tests/ui/swap.rs:36:5 | LL | / let temp = foo[0]; LL | | @@ -21,7 +21,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:51:5 + --> tests/ui/swap.rs:46:5 | LL | / let temp = foo[0]; LL | | @@ -30,7 +30,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:71:5 + --> tests/ui/swap.rs:66:5 | LL | / let temp = foo[0]; LL | | @@ -39,7 +39,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> tests/ui/swap.rs:83:5 + --> tests/ui/swap.rs:78:5 | LL | / a ^= b; LL | | @@ -48,7 +48,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> tests/ui/swap.rs:92:5 + --> tests/ui/swap.rs:87:5 | LL | / bar.a ^= bar.b; LL | | @@ -57,7 +57,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:101:5 + --> tests/ui/swap.rs:96:5 | LL | / foo[0] ^= foo[1]; LL | | @@ -66,7 +66,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> tests/ui/swap.rs:131:5 + --> tests/ui/swap.rs:126:5 | LL | / let temp = foo[0][1]; LL | | @@ -77,7 +77,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> tests/ui/swap.rs:147:7 + --> tests/ui/swap.rs:142:7 | LL | ; let t = a; | _______^ @@ -89,7 +89,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> tests/ui/swap.rs:158:7 + --> tests/ui/swap.rs:153:7 | LL | ; let t = c.0; | _______^ @@ -101,7 +101,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> tests/ui/swap.rs:188:5 + --> tests/ui/swap.rs:183:5 | LL | / let t = b; LL | | @@ -112,7 +112,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:143:5 + --> tests/ui/swap.rs:138:5 | LL | / a = b; LL | | @@ -120,11 +120,10 @@ LL | | b = a; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | = note: or maybe you should use `std::mem::replace`? - = note: `-D clippy::almost-swapped` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]` + = note: `#[deny(clippy::almost_swapped)]` on by default error: this looks like you are trying to swap `c.0` and `a` - --> tests/ui/swap.rs:154:5 + --> tests/ui/swap.rs:149:5 | LL | / c.0 = a; LL | | @@ -134,7 +133,7 @@ LL | | a = c.0; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:163:5 + --> tests/ui/swap.rs:158:5 | LL | / let a = b; LL | | @@ -144,7 +143,7 @@ LL | | let b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> tests/ui/swap.rs:169:5 + --> tests/ui/swap.rs:164:5 | LL | / d = c; LL | | @@ -154,7 +153,7 @@ LL | | c = d; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:174:5 + --> tests/ui/swap.rs:169:5 | LL | / let a = b; LL | | @@ -164,7 +163,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> tests/ui/swap.rs:224:5 + --> tests/ui/swap.rs:219:5 | LL | / let t = s.0.x; LL | | diff --git a/tests/ui/swap_with_temporary.fixed b/tests/ui/swap_with_temporary.fixed new file mode 100644 index 000000000000..4007d998ba06 --- /dev/null +++ b/tests/ui/swap_with_temporary.fixed @@ -0,0 +1,74 @@ +#![warn(clippy::swap_with_temporary)] + +use std::mem::swap; + +fn func() -> String { + String::from("func") +} + +fn func_returning_refmut(s: &mut String) -> &mut String { + s +} + +fn main() { + let mut x = String::from("x"); + let mut y = String::from("y"); + let mut zz = String::from("zz"); + let z = &mut zz; + + // No lint + swap(&mut x, &mut y); + + y = func(); + //~^ ERROR: swapping with a temporary value is inefficient + + x = func(); + //~^ ERROR: swapping with a temporary value is inefficient + + *z = func(); + //~^ ERROR: swapping with a temporary value is inefficient + + // No lint + swap(z, func_returning_refmut(&mut x)); + + swap(&mut y, z); + + *z = func(); + //~^ ERROR: swapping with a temporary value is inefficient + + macro_rules! mac { + (refmut $x:expr) => { + &mut $x + }; + (funcall $f:ident) => { + $f() + }; + (wholeexpr) => { + swap(&mut 42, &mut 0) + }; + (ident $v:ident) => { + $v + }; + } + *z = mac!(funcall func); + //~^ ERROR: swapping with a temporary value is inefficient + *mac!(ident z) = mac!(funcall func); + //~^ ERROR: swapping with a temporary value is inefficient + *mac!(ident z) = mac!(funcall func); + //~^ ERROR: swapping with a temporary value is inefficient + *mac!(refmut y) = func(); + //~^ ERROR: swapping with a temporary value is inefficient + + // No lint if it comes from a macro as it may depend on the arguments + mac!(wholeexpr); +} + +struct S { + t: String, +} + +fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) { + swap(&mut s.t, &mut v[0]); + swap(&mut s.t, v.get_mut(0).unwrap()); + swap(w.unwrap(), &mut s.t); +} diff --git a/tests/ui/swap_with_temporary.rs b/tests/ui/swap_with_temporary.rs new file mode 100644 index 000000000000..d403c086c0f4 --- /dev/null +++ b/tests/ui/swap_with_temporary.rs @@ -0,0 +1,74 @@ +#![warn(clippy::swap_with_temporary)] + +use std::mem::swap; + +fn func() -> String { + String::from("func") +} + +fn func_returning_refmut(s: &mut String) -> &mut String { + s +} + +fn main() { + let mut x = String::from("x"); + let mut y = String::from("y"); + let mut zz = String::from("zz"); + let z = &mut zz; + + // No lint + swap(&mut x, &mut y); + + swap(&mut func(), &mut y); + //~^ ERROR: swapping with a temporary value is inefficient + + swap(&mut x, &mut func()); + //~^ ERROR: swapping with a temporary value is inefficient + + swap(z, &mut func()); + //~^ ERROR: swapping with a temporary value is inefficient + + // No lint + swap(z, func_returning_refmut(&mut x)); + + swap(&mut y, z); + + swap(&mut func(), z); + //~^ ERROR: swapping with a temporary value is inefficient + + macro_rules! mac { + (refmut $x:expr) => { + &mut $x + }; + (funcall $f:ident) => { + $f() + }; + (wholeexpr) => { + swap(&mut 42, &mut 0) + }; + (ident $v:ident) => { + $v + }; + } + swap(&mut mac!(funcall func), z); + //~^ ERROR: swapping with a temporary value is inefficient + swap(&mut mac!(funcall func), mac!(ident z)); + //~^ ERROR: swapping with a temporary value is inefficient + swap(mac!(ident z), &mut mac!(funcall func)); + //~^ ERROR: swapping with a temporary value is inefficient + swap(mac!(refmut y), &mut func()); + //~^ ERROR: swapping with a temporary value is inefficient + + // No lint if it comes from a macro as it may depend on the arguments + mac!(wholeexpr); +} + +struct S { + t: String, +} + +fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) { + swap(&mut s.t, &mut v[0]); + swap(&mut s.t, v.get_mut(0).unwrap()); + swap(w.unwrap(), &mut s.t); +} diff --git a/tests/ui/swap_with_temporary.stderr b/tests/ui/swap_with_temporary.stderr new file mode 100644 index 000000000000..59355771a964 --- /dev/null +++ b/tests/ui/swap_with_temporary.stderr @@ -0,0 +1,100 @@ +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:22:5 + | +LL | swap(&mut func(), &mut y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `y = func()` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:22:15 + | +LL | swap(&mut func(), &mut y); + | ^^^^^^ + = note: `-D clippy::swap-with-temporary` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::swap_with_temporary)]` + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:25:5 + | +LL | swap(&mut x, &mut func()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `x = func()` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:25:23 + | +LL | swap(&mut x, &mut func()); + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:28:5 + | +LL | swap(z, &mut func()); + | ^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = func()` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:28:18 + | +LL | swap(z, &mut func()); + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:36:5 + | +LL | swap(&mut func(), z); + | ^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = func()` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:36:15 + | +LL | swap(&mut func(), z); + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:53:5 + | +LL | swap(&mut mac!(funcall func), z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = mac!(funcall func)` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:53:15 + | +LL | swap(&mut mac!(funcall func), z); + | ^^^^^^^^^^^^^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:55:5 + | +LL | swap(&mut mac!(funcall func), mac!(ident z)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(ident z) = mac!(funcall func)` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:55:15 + | +LL | swap(&mut mac!(funcall func), mac!(ident z)); + | ^^^^^^^^^^^^^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:57:5 + | +LL | swap(mac!(ident z), &mut mac!(funcall func)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(ident z) = mac!(funcall func)` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:57:30 + | +LL | swap(mac!(ident z), &mut mac!(funcall func)); + | ^^^^^^^^^^^^^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:59:5 + | +LL | swap(mac!(refmut y), &mut func()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(refmut y) = func()` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:59:31 + | +LL | swap(mac!(refmut y), &mut func()); + | ^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/swap_with_temporary_unfixable.rs b/tests/ui/swap_with_temporary_unfixable.rs new file mode 100644 index 000000000000..a974ca82abf2 --- /dev/null +++ b/tests/ui/swap_with_temporary_unfixable.rs @@ -0,0 +1,62 @@ +//@no-rustfix +#![warn(clippy::swap_with_temporary)] + +use std::mem::swap; + +fn func() -> String { + String::from("func") +} + +fn func_returning_refmut(s: &mut String) -> &mut String { + s +} + +fn main() { + let mut x = String::from("x"); + let mut y = String::from("y"); + let mut zz = String::from("zz"); + let z = &mut zz; + + swap(&mut func(), &mut func()); + //~^ ERROR: swapping temporary values has no effect + + if matches!(swap(&mut func(), &mut func()), ()) { + //~^ ERROR: swapping temporary values has no effect + println!("Yeah"); + } + + if matches!(swap(z, &mut func()), ()) { + //~^ ERROR: swapping with a temporary value is inefficient + println!("Yeah"); + } + + macro_rules! mac { + (refmut $x:expr) => { + &mut $x + }; + (refmut) => { + mac!(refmut String::new()) + }; + (funcall $f:ident) => { + $f() + }; + } + + swap(mac!(refmut func()), z); + //~^ ERROR: swapping with a temporary value is inefficient + swap(&mut mac!(funcall func), &mut mac!(funcall func)); + //~^ ERROR: swapping temporary values has no effect + swap(mac!(refmut), mac!(refmut)); + //~^ ERROR: swapping temporary values has no effect + swap(mac!(refmut y), mac!(refmut)); + //~^ ERROR: swapping with a temporary value is inefficient +} + +fn bug(v1: &mut [i32], v2: &mut [i32]) { + // Incorrect: swapping temporary references (`&mut &mut` passed to swap) + std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap()); + //~^ ERROR: swapping temporary values has no effect + + // Correct + std::mem::swap(v1.last_mut().unwrap(), v2.last_mut().unwrap()); +} diff --git a/tests/ui/swap_with_temporary_unfixable.stderr b/tests/ui/swap_with_temporary_unfixable.stderr new file mode 100644 index 000000000000..856c5415d676 --- /dev/null +++ b/tests/ui/swap_with_temporary_unfixable.stderr @@ -0,0 +1,125 @@ +error: swapping temporary values has no effect + --> tests/ui/swap_with_temporary_unfixable.rs:20:5 + | +LL | swap(&mut func(), &mut func()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:20:15 + | +LL | swap(&mut func(), &mut func()); + | ^^^^^^ +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:20:28 + | +LL | swap(&mut func(), &mut func()); + | ^^^^^^ + = note: `-D clippy::swap-with-temporary` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::swap_with_temporary)]` + +error: swapping temporary values has no effect + --> tests/ui/swap_with_temporary_unfixable.rs:23:17 + | +LL | if matches!(swap(&mut func(), &mut func()), ()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:23:27 + | +LL | if matches!(swap(&mut func(), &mut func()), ()) { + | ^^^^^^ +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:23:40 + | +LL | if matches!(swap(&mut func(), &mut func()), ()) { + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary_unfixable.rs:28:17 + | +LL | if matches!(swap(z, &mut func()), ()) { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:28:30 + | +LL | if matches!(swap(z, &mut func()), ()) { + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary_unfixable.rs:45:5 + | +LL | swap(mac!(refmut func()), z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this is a mutable reference to a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:45:10 + | +LL | swap(mac!(refmut func()), z); + | ^^^^^^^^^^^^^^^^^^^ + +error: swapping temporary values has no effect + --> tests/ui/swap_with_temporary_unfixable.rs:47:5 + | +LL | swap(&mut mac!(funcall func), &mut mac!(funcall func)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:47:15 + | +LL | swap(&mut mac!(funcall func), &mut mac!(funcall func)); + | ^^^^^^^^^^^^^^^^^^ +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:47:40 + | +LL | swap(&mut mac!(funcall func), &mut mac!(funcall func)); + | ^^^^^^^^^^^^^^^^^^ + +error: swapping temporary values has no effect + --> tests/ui/swap_with_temporary_unfixable.rs:49:5 + | +LL | swap(mac!(refmut), mac!(refmut)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this is a mutable reference to a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:49:10 + | +LL | swap(mac!(refmut), mac!(refmut)); + | ^^^^^^^^^^^^ +note: this is a mutable reference to a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:49:24 + | +LL | swap(mac!(refmut), mac!(refmut)); + | ^^^^^^^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary_unfixable.rs:51:5 + | +LL | swap(mac!(refmut y), mac!(refmut)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this is a mutable reference to a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:51:26 + | +LL | swap(mac!(refmut y), mac!(refmut)); + | ^^^^^^^^^^^^ + +error: swapping temporary values has no effect + --> tests/ui/swap_with_temporary_unfixable.rs:57:5 + | +LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:57:25 + | +LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary_unfixable.rs:57:54 + | +LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 3aecde398dc3..8c8674ac356d 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -23,19 +23,21 @@ fn my_vec() -> MyVec { #[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)] #[warn(clippy::useless_transmute)] unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { - // FIXME: should lint - // let _: &'a T = core::mem::transmute(t); + unsafe { + // FIXME: should lint + // let _: &'a T = core::mem::transmute(t); - let _: &'a U = core::mem::transmute(t); + let _: &'a U = core::mem::transmute(t); - let _: *const T = core::mem::transmute(t); - //~^ useless_transmute + let _: *const T = core::mem::transmute(t); + //~^ useless_transmute - let _: *mut T = core::mem::transmute(t); - //~^ useless_transmute + let _: *mut T = core::mem::transmute(t); + //~^ useless_transmute - let _: *const U = core::mem::transmute(t); - //~^ useless_transmute + let _: *const U = core::mem::transmute(t); + //~^ useless_transmute + } } #[warn(clippy::useless_transmute)] @@ -59,7 +61,7 @@ fn useless() { let _: *const usize = std::mem::transmute(5_isize); //~^ useless_transmute - let _ = 5_isize as *const usize; + let _ = std::ptr::dangling::(); let _: *const usize = std::mem::transmute(1 + 1usize); //~^ useless_transmute @@ -68,19 +70,19 @@ fn useless() { } unsafe fn _f<'a, 'b>(x: &'a u32) -> &'b u32 { - std::mem::transmute(x) + unsafe { std::mem::transmute(x) } } unsafe fn _f2<'a, 'b>(x: *const (dyn Iterator + 'a)) -> *const (dyn Iterator + 'b) { - std::mem::transmute(x) + unsafe { std::mem::transmute(x) } } unsafe fn _f3<'a, 'b>(x: fn(&'a u32)) -> fn(&'b u32) { - std::mem::transmute(x) + unsafe { std::mem::transmute(x) } } unsafe fn _f4<'a, 'b>(x: std::borrow::Cow<'a, str>) -> std::borrow::Cow<'b, str> { - std::mem::transmute(x) + unsafe { std::mem::transmute(x) } } } diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index e0d28437aafc..4219e09d2aba 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -1,68 +1,68 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:31:23 + --> tests/ui/transmute.rs:32:27 | -LL | let _: *const T = core::mem::transmute(t); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` +LL | let _: *const T = core::mem::transmute(t); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` | = note: `-D clippy::useless-transmute` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:34:21 + --> tests/ui/transmute.rs:35:25 | -LL | let _: *mut T = core::mem::transmute(t); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` +LL | let _: *mut T = core::mem::transmute(t); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:37:23 + --> tests/ui/transmute.rs:38:27 | -LL | let _: *const U = core::mem::transmute(t); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` +LL | let _: *const U = core::mem::transmute(t); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:44:27 + --> tests/ui/transmute.rs:46:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:49:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:52:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:55:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:58:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:59:31 + --> tests/ui/transmute.rs:61:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:64:31 + --> tests/ui/transmute.rs:66:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:96:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:102:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:105:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:112:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:119:31 + --> tests/ui/transmute.rs:121:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` @@ -107,97 +107,97 @@ LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:122:31 + --> tests/ui/transmute.rs:124:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:125:31 + --> tests/ui/transmute.rs:127:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:128:31 + --> tests/ui/transmute.rs:130:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:131:31 + --> tests/ui/transmute.rs:133:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:134:31 + --> tests/ui/transmute.rs:136:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:137:32 + --> tests/ui/transmute.rs:139:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:140:32 + --> tests/ui/transmute.rs:142:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:145:39 + --> tests/ui/transmute.rs:147:39 | LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:148:39 + --> tests/ui/transmute.rs:150:39 | LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:151:39 + --> tests/ui/transmute.rs:153:39 | LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:154:41 + --> tests/ui/transmute.rs:156:41 | LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:158:22 + --> tests/ui/transmute.rs:160:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:163:22 + --> tests/ui/transmute.rs:165:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:168:22 + --> tests/ui/transmute.rs:170:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:173:22 + --> tests/ui/transmute.rs:175:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:182:30 + --> tests/ui/transmute.rs:184:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -206,121 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:185:30 + --> tests/ui/transmute.rs:187:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:188:31 + --> tests/ui/transmute.rs:190:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:191:30 + --> tests/ui/transmute.rs:193:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:194:30 + --> tests/ui/transmute.rs:196:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:197:31 + --> tests/ui/transmute.rs:199:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:200:30 + --> tests/ui/transmute.rs:202:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:203:30 + --> tests/ui/transmute.rs:205:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:206:30 + --> tests/ui/transmute.rs:208:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:209:31 + --> tests/ui/transmute.rs:211:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:215:30 + --> tests/ui/transmute.rs:217:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:218:30 + --> tests/ui/transmute.rs:220:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:221:31 + --> tests/ui/transmute.rs:223:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:224:30 + --> tests/ui/transmute.rs:226:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:227:30 + --> tests/ui/transmute.rs:229:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:230:31 + --> tests/ui/transmute.rs:232:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:233:30 + --> tests/ui/transmute.rs:235:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:236:30 + --> tests/ui/transmute.rs:238:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:239:30 + --> tests/ui/transmute.rs:241:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:242:31 + --> tests/ui/transmute.rs:244:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:251:28 + --> tests/ui/transmute.rs:253:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -329,13 +329,13 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:254:32 + --> tests/ui/transmute.rs:256:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:257:30 + --> tests/ui/transmute.rs:259:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` diff --git a/tests/ui/transmute_null_to_fn.rs b/tests/ui/transmute_null_to_fn.rs index e88f05bb662e..4712374af934 100644 --- a/tests/ui/transmute_null_to_fn.rs +++ b/tests/ui/transmute_null_to_fn.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] #![warn(clippy::transmute_null_to_fn)] #![allow(clippy::zero_ptr, clippy::missing_transmute_annotations)] +#![allow(clippy::manual_dangling_ptr)] // Easy to lint because these only span one line. fn one_liners() { diff --git a/tests/ui/transmute_null_to_fn.stderr b/tests/ui/transmute_null_to_fn.stderr index f7d80147445d..b5b0d4ecc7c0 100644 --- a/tests/ui/transmute_null_to_fn.stderr +++ b/tests/ui/transmute_null_to_fn.stderr @@ -1,5 +1,5 @@ error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:8:23 + --> tests/ui/transmute_null_to_fn.rs:9:23 | LL | let _: fn() = std::mem::transmute(0 as *const ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -9,7 +9,7 @@ LL | let _: fn() = std::mem::transmute(0 as *const ()); = help: to override `-D warnings` add `#[allow(clippy::transmute_null_to_fn)]` error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:11:23 + --> tests/ui/transmute_null_to_fn.rs:12:23 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -17,7 +17,7 @@ LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:22:23 + --> tests/ui/transmute_null_to_fn.rs:23:23 | LL | let _: fn() = std::mem::transmute(ZPTR); | ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -25,7 +25,7 @@ LL | let _: fn() = std::mem::transmute(ZPTR); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:32:23 + --> tests/ui/transmute_null_to_fn.rs:33:23 | LL | let _: fn() = std::mem::transmute(0 as *const u8 as *const ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -33,7 +33,7 @@ LL | let _: fn() = std::mem::transmute(0 as *const u8 as *const ()); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:35:23 + --> tests/ui/transmute_null_to_fn.rs:36:23 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -41,7 +41,7 @@ LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:38:23 + --> tests/ui/transmute_null_to_fn.rs:39:23 | LL | let _: fn() = std::mem::transmute(ZPTR as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior diff --git a/tests/ui/transmute_ptr_to_ptr.fixed b/tests/ui/transmute_ptr_to_ptr.fixed index 3a67be5f45d0..476e7e35a1f6 100644 --- a/tests/ui/transmute_ptr_to_ptr.fixed +++ b/tests/ui/transmute_ptr_to_ptr.fixed @@ -8,12 +8,12 @@ use std::mem::transmute; // Make sure we can do static lifetime transmutes unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T { - transmute::<&'a T, &'static T>(t) + unsafe { transmute::<&'a T, &'static T>(t) } } // Make sure we can do non-static lifetime transmutes unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T { - transmute::<&'a T, &'b T>(t) + unsafe { transmute::<&'a T, &'b T>(t) } } struct LifetimeParam<'a> { diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index 01ad3a3296b1..7356668bcab5 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -8,12 +8,12 @@ use std::mem::transmute; // Make sure we can do static lifetime transmutes unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T { - transmute::<&'a T, &'static T>(t) + unsafe { transmute::<&'a T, &'static T>(t) } } // Make sure we can do non-static lifetime transmutes unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T { - transmute::<&'a T, &'b T>(t) + unsafe { transmute::<&'a T, &'b T>(t) } } struct LifetimeParam<'a> { diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed index 1bd45bc10a39..61e3ac2fe88e 100644 --- a/tests/ui/transmute_ptr_to_ref.fixed +++ b/tests/ui/transmute_ptr_to_ref.fixed @@ -6,33 +6,35 @@ )] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { - let _: &T = &*p; - //~^ transmute_ptr_to_ref - let _: &T = &*p; + unsafe { + let _: &T = &*p; + //~^ transmute_ptr_to_ref + let _: &T = &*p; - let _: &mut T = &mut *m; - //~^ transmute_ptr_to_ref - let _: &mut T = &mut *m; + let _: &mut T = &mut *m; + //~^ transmute_ptr_to_ref + let _: &mut T = &mut *m; - let _: &T = &*m; - //~^ transmute_ptr_to_ref - let _: &T = &*m; + let _: &T = &*m; + //~^ transmute_ptr_to_ref + let _: &T = &*m; - let _: &mut T = &mut *(p as *mut T); - //~^ transmute_ptr_to_ref - let _ = &mut *(p as *mut T); + let _: &mut T = &mut *(p as *mut T); + //~^ transmute_ptr_to_ref + let _ = &mut *(p as *mut T); - let _: &T = &*(o as *const T); - //~^ transmute_ptr_to_ref - let _: &T = &*(o as *const T); + let _: &T = &*(o as *const T); + //~^ transmute_ptr_to_ref + let _: &T = &*(o as *const T); - let _: &mut T = &mut *(om as *mut T); - //~^ transmute_ptr_to_ref - let _: &mut T = &mut *(om as *mut T); + let _: &mut T = &mut *(om as *mut T); + //~^ transmute_ptr_to_ref + let _: &mut T = &mut *(om as *mut T); - let _: &T = &*(om as *const T); - //~^ transmute_ptr_to_ref - let _: &T = &*(om as *const T); + let _: &T = &*(om as *const T); + //~^ transmute_ptr_to_ref + let _: &T = &*(om as *const T); + } } fn _issue1231() { @@ -54,47 +56,53 @@ fn _issue1231() { } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { - match 0 { - 0 => &*x.cast::<&u32>(), - //~^ transmute_ptr_to_ref - 1 => &*y.cast::<&u32>(), - //~^ transmute_ptr_to_ref - 2 => &*x.cast::<&'b u32>(), - //~^ transmute_ptr_to_ref - _ => &*y.cast::<&'b u32>(), - //~^ transmute_ptr_to_ref + unsafe { + match 0 { + 0 => &*x.cast::<&u32>(), + //~^ transmute_ptr_to_ref + 1 => &*y.cast::<&u32>(), + //~^ transmute_ptr_to_ref + 2 => &*x.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref + _ => &*y.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref + } } } #[clippy::msrv = "1.38"] unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { - let a = 0u32; - let a = &a as *const u32; - let _: &u32 = &*a; - //~^ transmute_ptr_to_ref - let _: &u32 = &*a.cast::(); - //~^ transmute_ptr_to_ref - match 0 { - 0 => &*x.cast::<&u32>(), + unsafe { + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = &*a; //~^ transmute_ptr_to_ref - _ => &*x.cast::<&'b u32>(), + let _: &u32 = &*a.cast::(); //~^ transmute_ptr_to_ref + match 0 { + 0 => &*x.cast::<&u32>(), + //~^ transmute_ptr_to_ref + _ => &*x.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref + } } } #[clippy::msrv = "1.37"] unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { - let a = 0u32; - let a = &a as *const u32; - let _: &u32 = &*a; - //~^ transmute_ptr_to_ref - let _: &u32 = &*(a as *const u32); - //~^ transmute_ptr_to_ref - match 0 { - 0 => &*(x as *const () as *const &u32), + unsafe { + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = &*a; //~^ transmute_ptr_to_ref - _ => &*(x as *const () as *const &'b u32), + let _: &u32 = &*(a as *const u32); //~^ transmute_ptr_to_ref + match 0 { + 0 => &*(x as *const () as *const &u32), + //~^ transmute_ptr_to_ref + _ => &*(x as *const () as *const &'b u32), + //~^ transmute_ptr_to_ref + } } } diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs index cbe64bf1ea6b..48e2f527b554 100644 --- a/tests/ui/transmute_ptr_to_ref.rs +++ b/tests/ui/transmute_ptr_to_ref.rs @@ -6,33 +6,35 @@ )] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { - let _: &T = std::mem::transmute(p); - //~^ transmute_ptr_to_ref - let _: &T = &*p; + unsafe { + let _: &T = std::mem::transmute(p); + //~^ transmute_ptr_to_ref + let _: &T = &*p; - let _: &mut T = std::mem::transmute(m); - //~^ transmute_ptr_to_ref - let _: &mut T = &mut *m; + let _: &mut T = std::mem::transmute(m); + //~^ transmute_ptr_to_ref + let _: &mut T = &mut *m; - let _: &T = std::mem::transmute(m); - //~^ transmute_ptr_to_ref - let _: &T = &*m; + let _: &T = std::mem::transmute(m); + //~^ transmute_ptr_to_ref + let _: &T = &*m; - let _: &mut T = std::mem::transmute(p as *mut T); - //~^ transmute_ptr_to_ref - let _ = &mut *(p as *mut T); + let _: &mut T = std::mem::transmute(p as *mut T); + //~^ transmute_ptr_to_ref + let _ = &mut *(p as *mut T); - let _: &T = std::mem::transmute(o); - //~^ transmute_ptr_to_ref - let _: &T = &*(o as *const T); + let _: &T = std::mem::transmute(o); + //~^ transmute_ptr_to_ref + let _: &T = &*(o as *const T); - let _: &mut T = std::mem::transmute(om); - //~^ transmute_ptr_to_ref - let _: &mut T = &mut *(om as *mut T); + let _: &mut T = std::mem::transmute(om); + //~^ transmute_ptr_to_ref + let _: &mut T = &mut *(om as *mut T); - let _: &T = std::mem::transmute(om); - //~^ transmute_ptr_to_ref - let _: &T = &*(om as *const T); + let _: &T = std::mem::transmute(om); + //~^ transmute_ptr_to_ref + let _: &T = &*(om as *const T); + } } fn _issue1231() { @@ -54,47 +56,53 @@ fn _issue1231() { } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { - match 0 { - 0 => std::mem::transmute(x), - //~^ transmute_ptr_to_ref - 1 => std::mem::transmute(y), - //~^ transmute_ptr_to_ref - 2 => std::mem::transmute::<_, &&'b u32>(x), - //~^ transmute_ptr_to_ref - _ => std::mem::transmute::<_, &&'b u32>(y), - //~^ transmute_ptr_to_ref + unsafe { + match 0 { + 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref + 1 => std::mem::transmute(y), + //~^ transmute_ptr_to_ref + 2 => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref + _ => std::mem::transmute::<_, &&'b u32>(y), + //~^ transmute_ptr_to_ref + } } } #[clippy::msrv = "1.38"] unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { - let a = 0u32; - let a = &a as *const u32; - let _: &u32 = std::mem::transmute(a); - //~^ transmute_ptr_to_ref - let _: &u32 = std::mem::transmute::<_, &u32>(a); - //~^ transmute_ptr_to_ref - match 0 { - 0 => std::mem::transmute(x), + unsafe { + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = std::mem::transmute(a); //~^ transmute_ptr_to_ref - _ => std::mem::transmute::<_, &&'b u32>(x), + let _: &u32 = std::mem::transmute::<_, &u32>(a); //~^ transmute_ptr_to_ref + match 0 { + 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref + _ => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref + } } } #[clippy::msrv = "1.37"] unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { - let a = 0u32; - let a = &a as *const u32; - let _: &u32 = std::mem::transmute(a); - //~^ transmute_ptr_to_ref - let _: &u32 = std::mem::transmute::<_, &u32>(a); - //~^ transmute_ptr_to_ref - match 0 { - 0 => std::mem::transmute(x), + unsafe { + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = std::mem::transmute(a); //~^ transmute_ptr_to_ref - _ => std::mem::transmute::<_, &&'b u32>(x), + let _: &u32 = std::mem::transmute::<_, &u32>(a); //~^ transmute_ptr_to_ref + match 0 { + 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref + _ => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref + } } } diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr index 7fad9b4065a5..7685c345c861 100644 --- a/tests/ui/transmute_ptr_to_ref.stderr +++ b/tests/ui/transmute_ptr_to_ref.stderr @@ -1,137 +1,137 @@ error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:9:17 + --> tests/ui/transmute_ptr_to_ref.rs:10:21 | -LL | let _: &T = std::mem::transmute(p); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` +LL | let _: &T = std::mem::transmute(p); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` | = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ref)]` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:13:21 + --> tests/ui/transmute_ptr_to_ref.rs:14:25 | -LL | let _: &mut T = std::mem::transmute(m); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` +LL | let _: &mut T = std::mem::transmute(m); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:17:17 + --> tests/ui/transmute_ptr_to_ref.rs:18:21 | -LL | let _: &T = std::mem::transmute(m); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` +LL | let _: &T = std::mem::transmute(m); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:21:21 + --> tests/ui/transmute_ptr_to_ref.rs:22:25 | -LL | let _: &mut T = std::mem::transmute(p as *mut T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` +LL | let _: &mut T = std::mem::transmute(p as *mut T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:25:17 + --> tests/ui/transmute_ptr_to_ref.rs:26:21 | -LL | let _: &T = std::mem::transmute(o); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` +LL | let _: &T = std::mem::transmute(o); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:29:21 + --> tests/ui/transmute_ptr_to_ref.rs:30:25 | -LL | let _: &mut T = std::mem::transmute(om); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` +LL | let _: &mut T = std::mem::transmute(om); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:33:17 + --> tests/ui/transmute_ptr_to_ref.rs:34:21 | -LL | let _: &T = std::mem::transmute(om); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` +LL | let _: &T = std::mem::transmute(om); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`) - --> tests/ui/transmute_ptr_to_ref.rs:44:32 + --> tests/ui/transmute_ptr_to_ref.rs:46:32 | LL | let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`) - --> tests/ui/transmute_ptr_to_ref.rs:47:33 + --> tests/ui/transmute_ptr_to_ref.rs:49:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> tests/ui/transmute_ptr_to_ref.rs:52:14 + --> tests/ui/transmute_ptr_to_ref.rs:54:14 | LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:58:14 + --> tests/ui/transmute_ptr_to_ref.rs:61:18 | -LL | 0 => std::mem::transmute(x), - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:60:14 + --> tests/ui/transmute_ptr_to_ref.rs:63:18 | -LL | 1 => std::mem::transmute(y), - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` +LL | 1 => std::mem::transmute(y), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:62:14 + --> tests/ui/transmute_ptr_to_ref.rs:65:18 | -LL | 2 => std::mem::transmute::<_, &&'b u32>(x), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` +LL | 2 => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:64:14 + --> tests/ui/transmute_ptr_to_ref.rs:67:18 | -LL | _ => std::mem::transmute::<_, &&'b u32>(y), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` +LL | _ => std::mem::transmute::<_, &&'b u32>(y), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:73:19 + --> tests/ui/transmute_ptr_to_ref.rs:78:23 | -LL | let _: &u32 = std::mem::transmute(a); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` +LL | let _: &u32 = std::mem::transmute(a); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:75:19 + --> tests/ui/transmute_ptr_to_ref.rs:80:23 | -LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` +LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:78:14 + --> tests/ui/transmute_ptr_to_ref.rs:83:18 | -LL | 0 => std::mem::transmute(x), - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:80:14 + --> tests/ui/transmute_ptr_to_ref.rs:85:18 | -LL | _ => std::mem::transmute::<_, &&'b u32>(x), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` +LL | _ => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:89:19 + --> tests/ui/transmute_ptr_to_ref.rs:96:23 | -LL | let _: &u32 = std::mem::transmute(a); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` +LL | let _: &u32 = std::mem::transmute(a); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:91:19 + --> tests/ui/transmute_ptr_to_ref.rs:98:23 | -LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` +LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:94:14 + --> tests/ui/transmute_ptr_to_ref.rs:101:18 | -LL | 0 => std::mem::transmute(x), - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:96:14 + --> tests/ui/transmute_ptr_to_ref.rs:103:18 | -LL | _ => std::mem::transmute::<_, &&'b u32>(x), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` +LL | _ => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` error: aborting due to 22 previous errors diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index bcd35bbd4e72..f3eb5060cd0d 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -3,6 +3,7 @@ #![allow(clippy::zero_ptr)] #![allow(clippy::transmute_ptr_to_ref)] #![allow(clippy::eq_op, clippy::missing_transmute_annotations)] +#![allow(clippy::manual_dangling_ptr)] // Easy to lint because these only span one line. fn one_liners() { diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index 84e6e374d525..c68e4102e405 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -1,5 +1,5 @@ error: transmuting a known null pointer into a reference - --> tests/ui/transmuting_null.rs:10:23 + --> tests/ui/transmuting_null.rs:11:23 | LL | let _: &u64 = std::mem::transmute(0 as *const u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | let _: &u64 = std::mem::transmute(0 as *const u64); = help: to override `-D warnings` add `#[allow(clippy::transmuting_null)]` error: transmuting a known null pointer into a reference - --> tests/ui/transmuting_null.rs:13:23 + --> tests/ui/transmuting_null.rs:14:23 | LL | let _: &u64 = std::mem::transmute(std::ptr::null::()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmuting a known null pointer into a reference - --> tests/ui/transmuting_null.rs:24:23 + --> tests/ui/transmuting_null.rs:25:23 | LL | let _: &u64 = std::mem::transmute(ZPTR); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/type_complexity.rs b/tests/ui/type_complexity.rs index 89c4955c9f6f..9d145516d610 100644 --- a/tests/ui/type_complexity.rs +++ b/tests/ui/type_complexity.rs @@ -1,6 +1,5 @@ -#![warn(clippy::all)] -#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] #![feature(associated_type_defaults)] +#![allow(clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] type Alias = Vec>>; // no warning here diff --git a/tests/ui/type_complexity.stderr b/tests/ui/type_complexity.stderr index 181e04d38e9a..a7f6a074a4a4 100644 --- a/tests/ui/type_complexity.stderr +++ b/tests/ui/type_complexity.stderr @@ -1,5 +1,5 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:7:12 + --> tests/ui/type_complexity.rs:6:12 | LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,85 +8,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]` error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:10:12 + --> tests/ui/type_complexity.rs:9:12 | LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:14:8 + --> tests/ui/type_complexity.rs:13:8 | LL | f: Vec>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:18:11 + --> tests/ui/type_complexity.rs:17:11 | LL | struct Ts(Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:22:11 + --> tests/ui/type_complexity.rs:21:11 | LL | Tuple(Vec>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:24:17 + --> tests/ui/type_complexity.rs:23:17 | LL | Struct { f: Vec>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:29:14 + --> tests/ui/type_complexity.rs:28:14 | LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:32:30 + --> tests/ui/type_complexity.rs:31:30 | LL | fn impl_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:37:14 + --> tests/ui/type_complexity.rs:36:14 | LL | const A: Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:40:14 + --> tests/ui/type_complexity.rs:39:14 | LL | type B = Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:43:25 + --> tests/ui/type_complexity.rs:42:25 | LL | fn method(&self, p: Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:46:29 + --> tests/ui/type_complexity.rs:45:29 | LL | fn def_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:59:15 + --> tests/ui/type_complexity.rs:58:15 | LL | fn test1() -> Vec>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:65:14 + --> tests/ui/type_complexity.rs:64:14 | LL | fn test2(_x: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:69:13 + --> tests/ui/type_complexity.rs:68:13 | LL | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index a48397137992..eeb281322da9 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -15,9 +15,17 @@ union MyOwnMaybeUninit { // https://github.com/rust-lang/rust/issues/119620 unsafe fn requires_paramenv() { - let mut vec = Vec::>::with_capacity(1); + unsafe { + let mut vec = Vec::>::with_capacity(1); + //~^ uninit_vec + vec.set_len(1); + } + + let mut vec = Vec::>::with_capacity(2); //~^ uninit_vec - vec.set_len(1); + unsafe { + vec.set_len(2); + } } fn main() { diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 7ff6140a2c3e..1b821ef004e6 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -1,18 +1,29 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:18:5 + --> tests/ui/uninit_vec.rs:24:5 | -LL | let mut vec = Vec::>::with_capacity(1); +LL | let mut vec = Vec::>::with_capacity(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | vec.set_len(1); - | ^^^^^^^^^^^^^^ +... +LL | vec.set_len(2); + | ^^^^^^^^^^^^^^ | = help: initialize the buffer or wrap the content in `MaybeUninit` = note: `-D clippy::uninit-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:25:5 + --> tests/ui/uninit_vec.rs:19:9 + | +LL | let mut vec = Vec::>::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:33:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +34,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:33:5 + --> tests/ui/uninit_vec.rs:41:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -34,7 +45,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:41:5 + --> tests/ui/uninit_vec.rs:49:5 | LL | let mut vec: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +54,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:49:5 + --> tests/ui/uninit_vec.rs:57:5 | LL | let mut vec: Vec = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +63,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:56:5 + --> tests/ui/uninit_vec.rs:64:5 | LL | let mut vec: Vec = Vec::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +72,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:76:5 + --> tests/ui/uninit_vec.rs:84:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +83,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:87:5 + --> tests/ui/uninit_vec.rs:95:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +94,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:94:5 + --> tests/ui/uninit_vec.rs:102:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +105,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:65:9 + --> tests/ui/uninit_vec.rs:73:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +116,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:70:9 + --> tests/ui/uninit_vec.rs:78:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -116,7 +127,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:150:9 + --> tests/ui/uninit_vec.rs:158:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +138,7 @@ LL | vec.set_len(10); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:178:9 + --> tests/ui/uninit_vec.rs:186:9 | LL | let mut vec: Vec> = Vec::with_capacity(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +149,7 @@ LL | vec.set_len(1); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:192:9 + --> tests/ui/uninit_vec.rs:200:9 | LL | let mut vec: Vec> = Vec::with_capacity(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,5 +159,5 @@ LL | vec.set_len(1); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/unnecessary_cast_unfixable.rs b/tests/ui/unnecessary_cast_unfixable.rs index 2bb64c3e80e3..4b1f4f76cc45 100644 --- a/tests/ui/unnecessary_cast_unfixable.rs +++ b/tests/ui/unnecessary_cast_unfixable.rs @@ -17,8 +17,10 @@ mod issue11113 { impl TearOff { unsafe fn query(&self) { - ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() - //~^ unnecessary_cast + unsafe { + ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() + //~^ unnecessary_cast + } } } } diff --git a/tests/ui/unnecessary_cast_unfixable.stderr b/tests/ui/unnecessary_cast_unfixable.stderr index 6ba1c7873066..6b26bea9de2a 100644 --- a/tests/ui/unnecessary_cast_unfixable.stderr +++ b/tests/ui/unnecessary_cast_unfixable.stderr @@ -8,10 +8,10 @@ LL | let _ = std::ptr::null() as *const u8; = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting raw pointers to the same type and constness is unnecessary (`*mut issue11113::Vtbl` -> `*mut issue11113::Vtbl`) - --> tests/ui/unnecessary_cast_unfixable.rs:20:16 + --> tests/ui/unnecessary_cast_unfixable.rs:21:20 | -LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)` +LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)` error: aborting due to 2 previous errors diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs index c4f1b6bc7e3d..85582c399ce5 100644 --- a/tests/ui/unnecessary_filter_map.rs +++ b/tests/ui/unnecessary_filter_map.rs @@ -1,5 +1,4 @@ -//@no-rustfix -#![allow(dead_code)] +#![allow(clippy::redundant_closure)] fn main() { let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); @@ -27,9 +26,7 @@ fn main() { let _ = (0..4).filter_map(Some); let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); - //~^ redundant_closure - //~| unnecessary_filter_map - //~| unnecessary_filter_map + //~^ unnecessary_filter_map } fn filter_map_none_changes_item_type() -> impl Iterator { diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr index 6683444b7273..a879633e10f2 100644 --- a/tests/ui/unnecessary_filter_map.stderr +++ b/tests/ui/unnecessary_filter_map.stderr @@ -1,14 +1,14 @@ -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:5:13 +error: this `.filter_map(..)` can be written more simply using `.filter(..)` + --> tests/ui/unnecessary_filter_map.rs:4:13 | LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_filter_map)]` -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:8:13 +error: this `.filter_map(..)` can be written more simply using `.filter(..)` + --> tests/ui/unnecessary_filter_map.rs:7:13 | LL | let _ = (0..4).filter_map(|x| { | _____________^ @@ -18,10 +18,10 @@ LL | | if x > 1 { ... | LL | | None LL | | }); - | |______^ help: try instead: `filter` + | |______^ -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:16:13 +error: this `.filter_map(..)` can be written more simply using `.filter(..)` + --> tests/ui/unnecessary_filter_map.rs:15:13 | LL | let _ = (0..4).filter_map(|x| match x { | _____________^ @@ -29,40 +29,25 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ help: try instead: `filter` + | |______^ -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:22:13 +error: this `.filter_map(..)` can be written more simply using `.map(..)` + --> tests/ui/unnecessary_filter_map.rs:21:13 | LL | let _ = (0..4).filter_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: redundant closure - --> tests/ui/unnecessary_filter_map.rs:29:57 +error: this call to `.filter_map(..)` is unnecessary + --> tests/ui/unnecessary_filter_map.rs:28:61 | LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); - | ^^^^^^^^^^^ help: replace the closure with the function itself: `Some` - | - = note: `-D clippy::redundant-closure` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` + | ^^^^ -error: filter_map is unnecessary - --> tests/ui/unnecessary_filter_map.rs:29:61 - | -LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); - | ^^^^ help: try removing the filter_map - -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:29:13 - | -LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` - -error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:169:14 +error: this `.filter_map(..)` can be written more simply using `.filter(..)` + --> tests/ui/unnecessary_filter_map.rs:166:14 | LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/unnecessary_find_map.rs b/tests/ui/unnecessary_find_map.rs index 8c8a3799f021..33ba7074d623 100644 --- a/tests/ui/unnecessary_find_map.rs +++ b/tests/ui/unnecessary_find_map.rs @@ -1,4 +1,3 @@ -//@no-rustfix #![allow(dead_code)] fn main() { diff --git a/tests/ui/unnecessary_find_map.stderr b/tests/ui/unnecessary_find_map.stderr index 94e320773a6f..3754a3d99538 100644 --- a/tests/ui/unnecessary_find_map.stderr +++ b/tests/ui/unnecessary_find_map.stderr @@ -1,14 +1,14 @@ -error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:5:13 +error: this `.find_map(..)` can be written more simply using `.find(..)` + --> tests/ui/unnecessary_find_map.rs:4:13 | LL | let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-find-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_find_map)]` -error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:8:13 +error: this `.find_map(..)` can be written more simply using `.find(..)` + --> tests/ui/unnecessary_find_map.rs:7:13 | LL | let _ = (0..4).find_map(|x| { | _____________^ @@ -18,10 +18,10 @@ LL | | if x > 1 { ... | LL | | None LL | | }); - | |______^ help: try instead: `find` + | |______^ -error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:16:13 +error: this `.find_map(..)` can be written more simply using `.find(..)` + --> tests/ui/unnecessary_find_map.rs:15:13 | LL | let _ = (0..4).find_map(|x| match x { | _____________^ @@ -29,19 +29,19 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ help: try instead: `find` + | |______^ -error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:22:13 +error: this `.find_map(..)` can be written more simply using `.map(..).next()` + --> tests/ui/unnecessary_find_map.rs:21:13 | LL | let _ = (0..4).find_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map(..).next()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:34:14 +error: this `.find_map(..)` can be written more simply using `.find(..)` + --> tests/ui/unnecessary_find_map.rs:33:14 | LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index aed2dbe1f1ce..61f2e3745ad0 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, clippy::uninlined_format_args)] #![warn(clippy::unnecessary_to_owned)] #[allow(dead_code)] diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index 12fdd150e423..b90ca00a5fec 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, clippy::uninlined_format_args)] #![warn(clippy::unnecessary_to_owned)] #[allow(dead_code)] diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 9a3290816389..409a8efbfeb9 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -321,3 +321,7 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let _x = false.then_some(f1 + f2); //~^ unnecessary_lazy_evaluations } + +fn issue14578() { + let _: Box> = Box::new(true.then(async || 42).unwrap()); +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 2d05ef5c2917..54735023a935 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -321,3 +321,7 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let _x = false.then(|| f1 + f2); //~^ unnecessary_lazy_evaluations } + +fn issue14578() { + let _: Box> = Box::new(true.then(async || 42).unwrap()); +} diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 05dfb72f48d2..645b56fe95e7 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,9 +1,10 @@ #![allow( clippy::deref_addrof, - dead_code, - unused, clippy::no_effect, - clippy::unnecessary_struct_initialization + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization, + dead_code, + unused )] #![warn(clippy::unnecessary_operation)] diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 6ef74c3eb1c1..97e90269c5c0 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,9 +1,10 @@ #![allow( clippy::deref_addrof, - dead_code, - unused, clippy::no_effect, - clippy::unnecessary_struct_initialization + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization, + dead_code, + unused )] #![warn(clippy::unnecessary_operation)] diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index eb98af09e7a3..0fda1dfde190 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:70:5 + --> tests/ui/unnecessary_operation.rs:71:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -8,103 +8,103 @@ LL | Tuple(get_number()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:72:5 + --> tests/ui/unnecessary_operation.rs:73:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:74:5 + --> tests/ui/unnecessary_operation.rs:75:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:76:5 + --> tests/ui/unnecessary_operation.rs:77:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:78:5 + --> tests/ui/unnecessary_operation.rs:79:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:80:5 + --> tests/ui/unnecessary_operation.rs:81:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:82:5 + --> tests/ui/unnecessary_operation.rs:83:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:84:5 + --> tests/ui/unnecessary_operation.rs:85:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:86:5 + --> tests/ui/unnecessary_operation.rs:87:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:88:5 + --> tests/ui/unnecessary_operation.rs:89:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:90:5 + --> tests/ui/unnecessary_operation.rs:91:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:92:5 + --> tests/ui/unnecessary_operation.rs:93:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:94:5 + --> tests/ui/unnecessary_operation.rs:95:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:96:5 + --> tests/ui/unnecessary_operation.rs:97:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:98:5 + --> tests/ui/unnecessary_operation.rs:99:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:100:5 + --> tests/ui/unnecessary_operation.rs:101:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:102:5 + --> tests/ui/unnecessary_operation.rs:103:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:104:5 + --> tests/ui/unnecessary_operation.rs:105:5 | LL | / { LL | | @@ -113,7 +113,7 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:108:5 + --> tests/ui/unnecessary_operation.rs:109:5 | LL | / FooString { LL | | @@ -122,7 +122,7 @@ LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:149:5 + --> tests/ui/unnecessary_operation.rs:150:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` diff --git a/tests/ui/unnecessary_os_str_debug_formatting.rs b/tests/ui/unnecessary_os_str_debug_formatting.rs index 12663ec9a528..6652efd9ae1d 100644 --- a/tests/ui/unnecessary_os_str_debug_formatting.rs +++ b/tests/ui/unnecessary_os_str_debug_formatting.rs @@ -1,4 +1,5 @@ #![warn(clippy::unnecessary_debug_formatting)] +#![allow(clippy::uninlined_format_args)] use std::ffi::{OsStr, OsString}; diff --git a/tests/ui/unnecessary_os_str_debug_formatting.stderr b/tests/ui/unnecessary_os_str_debug_formatting.stderr index 001309ab817a..382e59b04619 100644 --- a/tests/ui/unnecessary_os_str_debug_formatting.stderr +++ b/tests/ui/unnecessary_os_str_debug_formatting.stderr @@ -1,5 +1,5 @@ error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:14:22 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:15:22 | LL | println!("{:?}", os_str); | ^^^^^^ @@ -10,7 +10,7 @@ LL | println!("{:?}", os_str); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]` error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:15:22 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:16:22 | LL | println!("{:?}", os_string); | ^^^^^^^^^ @@ -19,7 +19,7 @@ LL | println!("{:?}", os_string); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:17:16 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:18:16 | LL | println!("{os_str:?}"); | ^^^^^^ @@ -28,7 +28,7 @@ LL | println!("{os_str:?}"); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:18:16 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:19:16 | LL | println!("{os_string:?}"); | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL | println!("{os_string:?}"); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `format!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:20:37 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:21:37 | LL | let _: String = format!("{:?}", os_str); | ^^^^^^ @@ -46,7 +46,7 @@ LL | let _: String = format!("{:?}", os_str); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `format!` args - --> tests/ui/unnecessary_os_str_debug_formatting.rs:21:37 + --> tests/ui/unnecessary_os_str_debug_formatting.rs:22:37 | LL | let _: String = format!("{:?}", os_string); | ^^^^^^^^^ diff --git a/tests/ui/unnecessary_path_debug_formatting.rs b/tests/ui/unnecessary_path_debug_formatting.rs index f14f6085c9a1..215e0d5d7802 100644 --- a/tests/ui/unnecessary_path_debug_formatting.rs +++ b/tests/ui/unnecessary_path_debug_formatting.rs @@ -1,4 +1,5 @@ #![warn(clippy::unnecessary_debug_formatting)] +#![allow(clippy::uninlined_format_args)] use std::ffi::{OsStr, OsString}; use std::ops::Deref; diff --git a/tests/ui/unnecessary_path_debug_formatting.stderr b/tests/ui/unnecessary_path_debug_formatting.stderr index f12fa72c84b3..d244b9ad6716 100644 --- a/tests/ui/unnecessary_path_debug_formatting.stderr +++ b/tests/ui/unnecessary_path_debug_formatting.stderr @@ -1,5 +1,5 @@ error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:29:22 + --> tests/ui/unnecessary_path_debug_formatting.rs:30:22 | LL | println!("{:?}", os_str); | ^^^^^^ @@ -10,7 +10,7 @@ LL | println!("{:?}", os_str); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]` error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:30:22 + --> tests/ui/unnecessary_path_debug_formatting.rs:31:22 | LL | println!("{:?}", os_string); | ^^^^^^^^^ @@ -19,7 +19,7 @@ LL | println!("{:?}", os_string); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:32:22 + --> tests/ui/unnecessary_path_debug_formatting.rs:33:22 | LL | println!("{:?}", path); | ^^^^ @@ -28,7 +28,7 @@ LL | println!("{:?}", path); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:33:22 + --> tests/ui/unnecessary_path_debug_formatting.rs:34:22 | LL | println!("{:?}", path_buf); | ^^^^^^^^ @@ -37,7 +37,7 @@ LL | println!("{:?}", path_buf); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:35:16 + --> tests/ui/unnecessary_path_debug_formatting.rs:36:16 | LL | println!("{path:?}"); | ^^^^ @@ -46,7 +46,7 @@ LL | println!("{path:?}"); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:36:16 + --> tests/ui/unnecessary_path_debug_formatting.rs:37:16 | LL | println!("{path_buf:?}"); | ^^^^^^^^ @@ -55,7 +55,7 @@ LL | println!("{path_buf:?}"); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `format!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:38:37 + --> tests/ui/unnecessary_path_debug_formatting.rs:39:37 | LL | let _: String = format!("{:?}", path); | ^^^^ @@ -64,7 +64,7 @@ LL | let _: String = format!("{:?}", path); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `format!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:39:37 + --> tests/ui/unnecessary_path_debug_formatting.rs:40:37 | LL | let _: String = format!("{:?}", path_buf); | ^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _: String = format!("{:?}", path_buf); = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed error: unnecessary `Debug` formatting in `println!` args - --> tests/ui/unnecessary_path_debug_formatting.rs:42:22 + --> tests/ui/unnecessary_path_debug_formatting.rs:43:22 | LL | println!("{:?}", &*deref_path); | ^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 5410033dbd8f..b064a8b8f46f 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,10 +1,11 @@ #![allow( + clippy::manual_async_fn, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, - clippy::ptr_arg, - clippy::manual_async_fn, clippy::needless_lifetimes, - clippy::owned_cow + clippy::owned_cow, + clippy::ptr_arg, + clippy::uninlined_format_args )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 0619dd4ddec0..7954a4ad4ce7 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,10 +1,11 @@ #![allow( + clippy::manual_async_fn, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, - clippy::ptr_arg, - clippy::manual_async_fn, clippy::needless_lifetimes, - clippy::owned_cow + clippy::owned_cow, + clippy::ptr_arg, + clippy::uninlined_format_args )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 8926db34da8c..6c52be839301 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:217:64 + --> tests/ui/unnecessary_to_owned.rs:218:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:217:20 + --> tests/ui/unnecessary_to_owned.rs:218:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:219:40 + --> tests/ui/unnecessary_to_owned.rs:220:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:219:21 + --> tests/ui/unnecessary_to_owned.rs:220:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:221:48 + --> tests/ui/unnecessary_to_owned.rs:222:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:221:19 + --> tests/ui/unnecessary_to_owned.rs:222:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:223:35 + --> tests/ui/unnecessary_to_owned.rs:224:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:223:18 + --> tests/ui/unnecessary_to_owned.rs:224:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:225:39 + --> tests/ui/unnecessary_to_owned.rs:226:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:225:20 + --> tests/ui/unnecessary_to_owned.rs:226:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:65:36 + --> tests/ui/unnecessary_to_owned.rs:66:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,391 +70,391 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:67:19 + --> tests/ui/unnecessary_to_owned.rs:68:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> tests/ui/unnecessary_to_owned.rs:70:20 + --> tests/ui/unnecessary_to_owned.rs:71:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:72:38 + --> tests/ui/unnecessary_to_owned.rs:73:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:74:20 + --> tests/ui/unnecessary_to_owned.rs:75:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> tests/ui/unnecessary_to_owned.rs:77:18 + --> tests/ui/unnecessary_to_owned.rs:78:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:79:34 + --> tests/ui/unnecessary_to_owned.rs:80:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:81:18 + --> tests/ui/unnecessary_to_owned.rs:82:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:84:17 + --> tests/ui/unnecessary_to_owned.rs:85:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:86:30 + --> tests/ui/unnecessary_to_owned.rs:87:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:88:17 + --> tests/ui/unnecessary_to_owned.rs:89:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:90:17 + --> tests/ui/unnecessary_to_owned.rs:91:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:93:19 + --> tests/ui/unnecessary_to_owned.rs:94:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:95:36 + --> tests/ui/unnecessary_to_owned.rs:96:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:97:19 + --> tests/ui/unnecessary_to_owned.rs:98:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:99:19 + --> tests/ui/unnecessary_to_owned.rs:100:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:101:19 + --> tests/ui/unnecessary_to_owned.rs:102:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:105:42 + --> tests/ui/unnecessary_to_owned.rs:106:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:109:25 + --> tests/ui/unnecessary_to_owned.rs:110:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:111:26 + --> tests/ui/unnecessary_to_owned.rs:112:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:113:24 + --> tests/ui/unnecessary_to_owned.rs:114:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:115:23 + --> tests/ui/unnecessary_to_owned.rs:116:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:117:25 + --> tests/ui/unnecessary_to_owned.rs:118:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:120:30 + --> tests/ui/unnecessary_to_owned.rs:121:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:122:31 + --> tests/ui/unnecessary_to_owned.rs:123:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:124:29 + --> tests/ui/unnecessary_to_owned.rs:125:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:28 + --> tests/ui/unnecessary_to_owned.rs:127:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:30 + --> tests/ui/unnecessary_to_owned.rs:129:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:131:29 + --> tests/ui/unnecessary_to_owned.rs:132:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:131:43 + --> tests/ui/unnecessary_to_owned.rs:132:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:134:29 + --> tests/ui/unnecessary_to_owned.rs:135:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:134:47 + --> tests/ui/unnecessary_to_owned.rs:135:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:138:26 + --> tests/ui/unnecessary_to_owned.rs:139:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:140:27 + --> tests/ui/unnecessary_to_owned.rs:141:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:142:25 + --> tests/ui/unnecessary_to_owned.rs:143:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:144:24 + --> tests/ui/unnecessary_to_owned.rs:145:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:146:24 + --> tests/ui/unnecessary_to_owned.rs:147:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:148:26 + --> tests/ui/unnecessary_to_owned.rs:149:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:150:26 + --> tests/ui/unnecessary_to_owned.rs:151:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:152:26 + --> tests/ui/unnecessary_to_owned.rs:153:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:155:31 + --> tests/ui/unnecessary_to_owned.rs:156:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:157:32 + --> tests/ui/unnecessary_to_owned.rs:158:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:159:30 + --> tests/ui/unnecessary_to_owned.rs:160:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:161:29 + --> tests/ui/unnecessary_to_owned.rs:162:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:163:29 + --> tests/ui/unnecessary_to_owned.rs:164:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:165:31 + --> tests/ui/unnecessary_to_owned.rs:166:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:167:31 + --> tests/ui/unnecessary_to_owned.rs:168:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:169:31 + --> tests/ui/unnecessary_to_owned.rs:170:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:172:30 + --> tests/ui/unnecessary_to_owned.rs:173:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:172:44 + --> tests/ui/unnecessary_to_owned.rs:173:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:175:30 + --> tests/ui/unnecessary_to_owned.rs:176:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:175:44 + --> tests/ui/unnecessary_to_owned.rs:176:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:178:30 + --> tests/ui/unnecessary_to_owned.rs:179:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:178:44 + --> tests/ui/unnecessary_to_owned.rs:179:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:181:30 + --> tests/ui/unnecessary_to_owned.rs:182:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:181:48 + --> tests/ui/unnecessary_to_owned.rs:182:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:184:30 + --> tests/ui/unnecessary_to_owned.rs:185:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:184:52 + --> tests/ui/unnecessary_to_owned.rs:185:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:187:30 + --> tests/ui/unnecessary_to_owned.rs:188:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:187:48 + --> tests/ui/unnecessary_to_owned.rs:188:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:191:20 + --> tests/ui/unnecessary_to_owned.rs:192:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:194:13 + --> tests/ui/unnecessary_to_owned.rs:195:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:196:13 + --> tests/ui/unnecessary_to_owned.rs:197:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:199:13 + --> tests/ui/unnecessary_to_owned.rs:200:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:201:13 + --> tests/ui/unnecessary_to_owned.rs:202:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:229:26 + --> tests/ui/unnecessary_to_owned.rs:230:26 | LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:231:26 + --> tests/ui/unnecessary_to_owned.rs:232:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:233:26 + --> tests/ui/unnecessary_to_owned.rs:234:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -490,7 +490,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:291:14 + --> tests/ui/unnecessary_to_owned.rs:292:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -503,49 +503,49 @@ LL ~ let path = match get_file_path(t) { | error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:357:24 + --> tests/ui/unnecessary_to_owned.rs:358:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:467:12 + --> tests/ui/unnecessary_to_owned.rs:468:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:611:37 + --> tests/ui/unnecessary_to_owned.rs:612:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:622:18 + --> tests/ui/unnecessary_to_owned.rs:623:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:627:14 + --> tests/ui/unnecessary_to_owned.rs:628:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:629:14 + --> tests/ui/unnecessary_to_owned.rs:630:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:635:14 + --> tests/ui/unnecessary_to_owned.rs:636:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:637:14 + --> tests/ui/unnecessary_to_owned.rs:638:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` diff --git a/tests/ui/unnested_or_patterns.fixed b/tests/ui/unnested_or_patterns.fixed index 791b2fa131f2..2081772d06b3 100644 --- a/tests/ui/unnested_or_patterns.fixed +++ b/tests/ui/unnested_or_patterns.fixed @@ -64,3 +64,16 @@ fn msrv_1_53() { if let [1 | 53] = [0] {} //~^ unnested_or_patterns } + +mod issue9952 { + fn or_in_local() { + let (0 | 1 | _) = 0; + //~^ unnested_or_patterns + + if let (0 | 1 | _) = 0 {} + //~^ unnested_or_patterns + } + + fn or_in_param((x | x | x): i32) {} + //~^ unnested_or_patterns +} diff --git a/tests/ui/unnested_or_patterns.rs b/tests/ui/unnested_or_patterns.rs index e7e7c7cd2e49..6bf8fce36616 100644 --- a/tests/ui/unnested_or_patterns.rs +++ b/tests/ui/unnested_or_patterns.rs @@ -64,3 +64,16 @@ fn msrv_1_53() { if let [1] | [53] = [0] {} //~^ unnested_or_patterns } + +mod issue9952 { + fn or_in_local() { + let (0 | (1 | _)) = 0; + //~^ unnested_or_patterns + + if let (0 | (1 | _)) = 0 {} + //~^ unnested_or_patterns + } + + fn or_in_param((x | (x | x)): i32) {} + //~^ unnested_or_patterns +} diff --git a/tests/ui/unnested_or_patterns.stderr b/tests/ui/unnested_or_patterns.stderr index ec5eb983c5a0..c805dc992b1c 100644 --- a/tests/ui/unnested_or_patterns.stderr +++ b/tests/ui/unnested_or_patterns.stderr @@ -204,5 +204,41 @@ LL - if let [1] | [53] = [0] {} LL + if let [1 | 53] = [0] {} | -error: aborting due to 17 previous errors +error: unnested or-patterns + --> tests/ui/unnested_or_patterns.rs:70:13 + | +LL | let (0 | (1 | _)) = 0; + | ^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL - let (0 | (1 | _)) = 0; +LL + let (0 | 1 | _) = 0; + | + +error: unnested or-patterns + --> tests/ui/unnested_or_patterns.rs:73:16 + | +LL | if let (0 | (1 | _)) = 0 {} + | ^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL - if let (0 | (1 | _)) = 0 {} +LL + if let (0 | 1 | _) = 0 {} + | + +error: unnested or-patterns + --> tests/ui/unnested_or_patterns.rs:77:20 + | +LL | fn or_in_param((x | (x | x)): i32) {} + | ^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL - fn or_in_param((x | (x | x)): i32) {} +LL + fn or_in_param((x | x | x): i32) {} + | + +error: aborting due to 20 previous errors diff --git a/tests/ui/unwrap_or.fixed b/tests/ui/unwrap_or.fixed index c794ed577032..e550484b5d9f 100644 --- a/tests/ui/unwrap_or.fixed +++ b/tests/ui/unwrap_or.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::all, clippy::or_fun_call)] +#![warn(clippy::or_fun_call)] #![allow(clippy::unnecessary_literal_unwrap)] fn main() { diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index 11a6883b7403..cdd61ac898e6 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -1,4 +1,4 @@ -#![warn(clippy::all, clippy::or_fun_call)] +#![warn(clippy::or_fun_call)] #![allow(clippy::unnecessary_literal_unwrap)] fn main() { diff --git a/tests/ui/used_underscore_items.rs b/tests/ui/used_underscore_items.rs index 3401df6ae743..7e8289f1406b 100644 --- a/tests/ui/used_underscore_items.rs +++ b/tests/ui/used_underscore_items.rs @@ -73,7 +73,7 @@ fn external_item_call() { // should not lint foreign functions. // issue #14156 -extern "C" { +unsafe extern "C" { pub fn _exit(code: i32) -> !; } diff --git a/triagebot.toml b/triagebot.toml index 33d3b0728f3d..f27b109e9953 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -9,11 +9,32 @@ allow-unauthenticated = [ # See https://forge.rust-lang.org/triagebot/shortcuts.html [shortcut] +[merge-conflicts] + +[note] + +[canonicalize-issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] + # Have rustbot inform users about the *No Merge Policy* [no-merges] exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust labels = ["has-merge-commits", "S-waiting-on-author"] +[review-requested] +# Those labels are removed when PR author requests a review from an assignee +remove_labels = ["S-waiting-on-author"] +# Those labels are added when PR author requests a review from an assignee +add_labels = ["S-waiting-on-review"] + +[review-submitted] +# These labels are removed when a review is submitted. +review_labels = ["S-waiting-on-review"] +# This label is added when a review is submitted. +reviewed_label = "S-waiting-on-author" + [autolabel."S-waiting-on-review"] new_pr = true @@ -21,10 +42,12 @@ new_pr = true contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ "matthiaskrgr", + "samueltardieu", ] [assign.owners] "/.github" = ["@flip1995"] +"/triagebot.toml" = ["@flip1995"] "/book" = ["@flip1995"] "*" = [ "@Manishearth", @@ -34,4 +57,5 @@ users_on_vacation = [ "@Jarcho", "@blyxyas", "@y21", + "@samueltardieu", ] From bf713a0e78208889c666e3656b073a8971fd4dd2 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 22 Apr 2025 23:51:42 +0200 Subject: [PATCH 021/302] style: pull one more `if` into the let-chain --- clippy_lints/src/types/vec_box.rs | 105 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 769244c675e1..f13042a6fa6b 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -19,61 +19,58 @@ pub(super) fn check<'tcx>( def_id: DefId, box_size_threshold: u64, ) -> bool { - if cx.tcx.is_diagnostic_item(sym::Vec, def_id) { - if let Some(last) = last_path_segment(qpath).args - // Get the _ part of Vec<_> - && let Some(GenericArg::Type(ty)) = last.args.first() - // extract allocator from the Vec for later - && let vec_alloc_ty = last.args.get(1) - // ty is now _ at this point - && let TyKind::Path(ref ty_qpath) = ty.kind - && let res = cx.qpath_res(ty_qpath, ty.hir_id) - && let Some(def_id) = res.opt_def_id() - && Some(def_id) == cx.tcx.lang_items().owned_box() - // At this point, we know ty is Box, now get T - && let Some(last) = last_path_segment(ty_qpath).args - && let Some(GenericArg::Type(boxed_ty)) = last.args.first() - // extract allocator from the Box for later - && let boxed_alloc_ty = last.args.get(1) - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) - && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.typing_env()) - && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) - && ty_ty_size < box_size_threshold - // https://github.com/rust-lang/rust-clippy/issues/7114 - && match (vec_alloc_ty, boxed_alloc_ty) { - (None, None) => true, - // this is in the event that we have something like - // Vec<_, Global>, in which case is equivalent to - // Vec<_> - (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { - if let TyKind::Path(path) = inner.kind - && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { - cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) - } else { - false - } - }, - (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), - _ => false - } - { - span_lint_and_sugg( - cx, - VEC_BOX, - hir_ty.span, - "`Vec` is already on the heap, the boxing is unnecessary", - "try", - format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), - Applicability::Unspecified, - ); - true - } else { - false + if cx.tcx.is_diagnostic_item(sym::Vec, def_id) + && let Some(last) = last_path_segment(qpath).args + // Get the _ part of Vec<_> + && let Some(GenericArg::Type(ty)) = last.args.first() + // extract allocator from the Vec for later + && let vec_alloc_ty = last.args.get(1) + // ty is now _ at this point + && let TyKind::Path(ref ty_qpath) = ty.kind + && let res = cx.qpath_res(ty_qpath, ty.hir_id) + && let Some(def_id) = res.opt_def_id() + && Some(def_id) == cx.tcx.lang_items().owned_box() + // At this point, we know ty is Box, now get T + && let Some(last) = last_path_segment(ty_qpath).args + && let Some(GenericArg::Type(boxed_ty)) = last.args.first() + // extract allocator from the Box for later + && let boxed_alloc_ty = last.args.get(1) + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) + && !ty_ty.has_escaping_bound_vars() + && ty_ty.is_sized(cx.tcx, cx.typing_env()) + && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) + && ty_ty_size < box_size_threshold + // https://github.com/rust-lang/rust-clippy/issues/7114 + && match (vec_alloc_ty, boxed_alloc_ty) { + (None, None) => true, + // this is in the event that we have something like + // Vec<_, Global>, in which case is equivalent to + // Vec<_> + (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { + if let TyKind::Path(path) = inner.kind + && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { + cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) + } else { + false + } + }, + (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), + _ => false } + { + span_lint_and_sugg( + cx, + VEC_BOX, + hir_ty.span, + "`Vec` is already on the heap, the boxing is unnecessary", + "try", + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), + Applicability::Unspecified, + ); + true } else { false } From 2304a9cb7638140bd839c3d8b001c77ca7c06f21 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 23 Apr 2025 00:42:30 +0200 Subject: [PATCH 022/302] remove non-existent pathspec from pre-commit hook it was added back in 6035e050e83cc991f94797eef4d720c0b61d8955, at which time there were some files matching it, e.g. https://github.com/rust-lang/rust-clippy/blob/6035e050e83cc991f94797eef4d720c0b61d8955/clippy_lints/src/lib.deprecated.rs --- util/etc/pre-commit.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/util/etc/pre-commit.sh b/util/etc/pre-commit.sh index 5dd2ba3d5f53..528f8953b25d 100755 --- a/util/etc/pre-commit.sh +++ b/util/etc/pre-commit.sh @@ -6,7 +6,6 @@ set -e # Update lints cargo dev update_lints git add clippy_lints/src/lib.rs -git add clippy_lints/src/lib.*.rs # Formatting: # Git will not automatically add the formatted code to the staged changes once From dd5948ccc2b10bee9dc3bef7595ea72fec366c86 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 23 Apr 2025 10:51:22 +0200 Subject: [PATCH 023/302] Clippy: Fix doc issue --- clippy_utils/src/source.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 3aa72cf5eaff..8645d5730fed 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -142,6 +142,7 @@ pub trait SpanRangeExt: SpanRange { map_range(cx.sess().source_map(), self.into_range(), f) } + #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")] /// Extends the range to include all preceding whitespace characters, unless there /// are non-whitespace characters left on the same line after `self`. /// From 36ae6575fd85dd6eb9a00e097e47b38fa25235a0 Mon Sep 17 00:00:00 2001 From: Artur Roos Date: Wed, 23 Apr 2025 14:31:34 +0300 Subject: [PATCH 024/302] Document breaking out of a named code block --- library/std/src/keyword_docs.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c07c391892d8..b0e55c787250 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -109,6 +109,33 @@ mod as_keyword {} /// println!("{result}"); /// ``` /// +/// It is also possible to exit from any *labelled* block returning the value early. +/// If no value specified `break;` returns `()`. +/// +/// ```rust +/// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; +/// +/// let mut results = vec![]; +/// for input in inputs { +/// let result = 'filter: { +/// if input.len() > 3 { +/// break 'filter Err("Too long"); +/// }; +/// +/// if !input.contains("C") { +/// break 'filter Err("No Cs"); +/// }; +/// +/// Ok(input.to_uppercase()) +/// }; +/// +/// results.push(result); +/// } +/// +/// // [Ok("COW"), Ok("CAT"), Err("No Cs"), Err("Too long"), Ok("COD")] +/// println!("{:?}", results) +/// ``` +/// /// For more details consult the [Reference on "break expression"] and the [Reference on "break and /// loop values"]. /// From 821925e8a476a39bbe71c1601388e677bfd8f410 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 22 Apr 2025 00:44:11 +0200 Subject: [PATCH 025/302] Update browser-ui-test version to 0.20.6 --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 3428dd4826a7..e15121e0f316 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.20.3 \ No newline at end of file +0.20.6 \ No newline at end of file From 934e86b24f8eaf9a52b7c7004fc7a02b1c8310f6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 22 Apr 2025 00:44:24 +0200 Subject: [PATCH 026/302] Unify sidebar buttons to use the same image --- src/librustdoc/html/static/css/rustdoc.css | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a6dd06b76ea9..5138c394434c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -55,6 +55,9 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --collapse-arrow-image: url('data:image/svg+xml,'); + --hamburger-image: url('data:image/svg+xml,\ + '); } :root.sans-serif { @@ -2001,9 +2004,11 @@ a.tooltip:hover::after { display: flex; margin-right: 4px; position: fixed; - left: 6px; height: 34px; width: 34px; +} +.hide-sidebar #sidebar-button { + left: 6px; background-color: var(--main-background-color); z-index: 1; } @@ -2019,6 +2024,8 @@ a.tooltip:hover::after { align-items: center; justify-content: center; flex-direction: column; +} +#settings-menu > a, #help-button > a, button#toggle-all-docs { border: 1px solid transparent; border-radius: var(--button-border-radius); color: var(--main-color); @@ -2031,14 +2038,15 @@ a.tooltip:hover::after { min-width: 0; } #sidebar-button > a { - background-color: var(--button-background-color); - border-color: var(--border-color); + background-color: var(--sidebar-background-color); width: 33px; } +#sidebar-button > a:hover, #sidebar-button > a:focus-visible { + background-color: var(--main-background-color); +} #settings-menu > a:hover, #settings-menu > a:focus-visible, #help-button > a:hover, #help-button > a:focus-visible, -#sidebar-button > a:hover, #sidebar-button > a:focus-visible, button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible { border-color: var(--settings-button-border-focus); text-decoration: none; @@ -2402,10 +2410,9 @@ However, it's not needed with smaller screen width because the doc/code block is use hamburger button */ .src #sidebar-button > a::before, .sidebar-menu-toggle::before { /* hamburger button image */ - content: url('data:image/svg+xml,\ - '); + content: var(--hamburger-image); opacity: 0.75; + filter: var(--mobile-sidebar-menu-filter); } .sidebar-menu-toggle:hover::before, .sidebar-menu-toggle:active::before, @@ -2413,17 +2420,6 @@ However, it's not needed with smaller screen width because the doc/code block is opacity: 1; } -/* src sidebar button opens a folder view */ -.src #sidebar-button > a::before { - /* folder image */ - content: url('data:image/svg+xml,\ - \ - \ - '); - opacity: 0.75; -} - /* Media Queries */ /* Make sure all the buttons line wrap at the same time */ @@ -2608,9 +2604,6 @@ in src-script.js and main.js width: 22px; height: 22px; } - .sidebar-menu-toggle::before { - filter: var(--mobile-sidebar-menu-filter); - } .sidebar-menu-toggle:hover { background: var(--main-background-color); } @@ -2668,6 +2661,14 @@ in src-script.js and main.js margin: 0 0 -25px 0; padding: var(--nav-sub-mobile-padding); } + + html:not(.src-sidebar-expanded) .src #sidebar-button > a { + background-color: var(--main-background-color); + } + html:not(.src-sidebar-expanded) .src #sidebar-button > a:hover, + html:not(.src-sidebar-expanded) .src #sidebar-button > a:focus-visible { + background-color: var(--sidebar-background-color); + } } From 7c5312bdab3ce012c136114559ba988bfad8ecc1 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 23 Apr 2025 19:03:46 +0000 Subject: [PATCH 027/302] Reword `needless_question_mark` diagnostics and docs --- clippy_lints/src/needless_question_mark.rs | 70 +++++----- tests/ui/needless_question_mark.stderr | 148 ++++++++++++++++----- tests/ui/question_mark.fixed | 5 + tests/ui/question_mark.rs | 5 + tests/ui/question_mark.stderr | 20 +-- 5 files changed, 171 insertions(+), 77 deletions(-) diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 72b0a80260e9..2a2160c3be2d 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,6 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::path_res; -use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Suggests alternatives for useless applications of `?` in terminating expressions + /// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator + /// is not needed to convert the type of `x`. /// /// ### Why is this bad? /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// Some(s.find('x')?) /// } /// - /// fn f(to: TO) -> Option { - /// Some(to.magic?) + /// fn g(s: &str) -> Result { + /// Ok(s.parse()?) /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| Ok(t.magic?)) - /// } - /// /// ``` /// Use instead: /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// s.find('x') /// } /// - /// fn f(to: TO) -> Option { - /// to.magic - /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| t.magic) + /// fn g(s: &str) -> Result { + /// s.parse() /// } /// ``` #[clippy::version = "1.51.0"] pub NEEDLESS_QUESTION_MARK, complexity, - "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result`." + "using `Ok(x?)` or `Some(x?)` where `x` would be equivalent" } declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); @@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(path, [arg]) = expr.kind && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path) && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) - && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { - "Some()" + && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { + "Some" } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { - "Ok()" + "Ok" } else { return; } @@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { && let inner_ty = cx.typeck_results().expr_ty(inner_expr) && expr_ty == inner_ty { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_QUESTION_MARK, + expr.hir_id, expr.span, - "question mark operator is useless here", - format!("try removing question mark and `{sugg_remove}`"), - format!("{}", snippet(cx, inner_expr.span, r#""...""#)), - Applicability::MachineApplicable, + format!("enclosing `{variant}` and `?` operator are unneeded"), + |diag| { + diag.multipart_suggestion( + format!("remove the enclosing `{variant}` and `?` operator"), + vec![ + (expr.span.until(inner_expr.span), String::new()), + ( + inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + String::new(), + ), + ], + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/tests/ui/needless_question_mark.stderr b/tests/ui/needless_question_mark.stderr index 55da4f28976c..8516cee48e67 100644 --- a/tests/ui/needless_question_mark.stderr +++ b/tests/ui/needless_question_mark.stderr @@ -1,100 +1,188 @@ -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:20:12 | LL | return Some(to.magic?); - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-question-mark` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]` +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?); +LL + return to.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:29:12 | LL | return Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?) +LL + return to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:35:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:41:21 | LL | to.and_then(|t| Some(t.magic?)) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - to.and_then(|t| Some(t.magic?)) +LL + to.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:51:9 | LL | Some(t.magic?) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:57:12 | LL | return Ok(tr.magic?); - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?); +LL + return tr.magic; + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:65:12 | LL | return Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?) +LL + return tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:70:5 | LL | Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(tr.magic?) +LL + tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:75:21 | LL | tr.and_then(|t| Ok(t.magic?)) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - tr.and_then(|t| Ok(t.magic?)) +LL + tr.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:84:9 | LL | Ok(t.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:92:16 | LL | return Ok(t.magic?); - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(t.magic?); +LL + return t.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:128:27 | LL | || -> Option<_> { Some(Some($expr)?) }() - | ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)` + | ^^^^^^^^^^^^^^^^^^ ... LL | let _x = some_and_qmark_in_macro!(x?); | ---------------------------- in this macro invocation | = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the enclosing `Some` and `?` operator + | +LL - || -> Option<_> { Some(Some($expr)?) }() +LL + || -> Option<_> { Some($expr) }() + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:140:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:149:5 | LL | Ok(s.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(s.magic?) +LL + s.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:154:7 | LL | { Some(a?) } - | ^^^^^^^^ help: try removing question mark and `Some()`: `a` + | ^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - { Some(a?) } +LL + { a } + | error: aborting due to 15 previous errors diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 6bd071d07f52..507bc2b29d86 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index dd093c9bf480..64b51b849ede 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 8fe04b895cea..d8ce4420aeeb 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -198,7 +198,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:390:13 + --> tests/ui/question_mark.rs:395:13 | LL | / if a.is_none() { LL | | @@ -208,7 +208,7 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:451:5 + --> tests/ui/question_mark.rs:456:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; @@ -216,7 +216,7 @@ LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:466:5 + --> tests/ui/question_mark.rs:471:5 | LL | / let Some(ref x) = foo.opt_x else { LL | | return None; @@ -224,7 +224,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:476:5 + --> tests/ui/question_mark.rs:481:5 | LL | / let Some(ref mut x) = foo.opt_x else { LL | | return None; @@ -232,7 +232,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:487:5 + --> tests/ui/question_mark.rs:492:5 | LL | / let Some(ref x @ ref y) = foo.opt_x else { LL | | return None; @@ -240,7 +240,7 @@ LL | | }; | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:491:5 + --> tests/ui/question_mark.rs:496:5 | LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -248,7 +248,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:495:5 + --> tests/ui/question_mark.rs:500:5 | LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -256,7 +256,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:517:5 + --> tests/ui/question_mark.rs:522:5 | LL | / if arg.is_none() { LL | | @@ -265,7 +265,7 @@ LL | | } | |_____^ help: replace it with: `arg?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:521:15 + --> tests/ui/question_mark.rs:526:15 | LL | let val = match arg { | _______________^ @@ -276,7 +276,7 @@ LL | | }; | |_____^ help: try instead: `arg?` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:531:5 + --> tests/ui/question_mark.rs:536:5 | LL | / let Some(a) = *a else { LL | | return None; From f7d8558003d5821868feef3fe1858fb422a5afc4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 22 Apr 2025 00:44:44 +0200 Subject: [PATCH 028/302] Add rustdoc-gui test to ensure sidebars share the same image --- tests/rustdoc-gui/sidebar.goml | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 38160cc49d08..9c66b84165f8 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -199,6 +199,42 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3}) drag-and-drop: ((205, 100), (108, 100)) assert-position: (".sidebar-crate > h2 > a", {"x": -3}) +// Check that the mobile sidebar and the source sidebar use the same icon. +store-css: (".mobile-topbar .sidebar-menu-toggle::before", {"content": image_url}) +// Then we go to a source page. +click: ".main-heading .src" +assert-css: ("#sidebar-button a::before", {"content": |image_url|}) +// Check that hover events work as expected. +store-css: ("#sidebar-button a", {"background-color": sidebar_background}) +move-cursor-to: "#sidebar-button a" +store-css: ("#sidebar-button a:hover", {"background-color": sidebar_background_hover}) +assert: |sidebar_background| != |sidebar_background_hover| +click: "#sidebar-button a" +wait-for: "html.src-sidebar-expanded" +assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|}) +move-cursor-to: "#settings-menu" +assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|}) +// Closing sidebar. +click: "#sidebar-button a" +wait-for: "html:not(.src-sidebar-expanded)" +// Now we check the same when the sidebar button is moved alongside the search. +set-window-size: (500, 500) +store-css: ("#sidebar-button a:hover", {"background-color": not_sidebar_background_hover}) +move-cursor-to: "#settings-menu" +store-css: ("#sidebar-button a:not(:hover)", {"background-color": not_sidebar_background}) +// The sidebar background is supposed to be the same as the main background. +assert-css: ("body", {"background-color": |not_sidebar_background|}) +assert: |not_sidebar_background| != |not_sidebar_background_hover| && |not_sidebar_background| != |sidebar_background| +// The hover background is supposed to be the same as the sidebar background. +assert: |not_sidebar_background_hover| == |sidebar_background| +click: "#sidebar-button a" +wait-for: "html.src-sidebar-expanded" +// And now the background colors are supposed to be the same as the sidebar since the sidebar has +// been open. +assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|}) +move-cursor-to: "h2" +assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|}) + // Configuration option to show TOC in sidebar. set-local-storage: {"rustdoc-hide-toc": "true"} go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" From 4ff55588d33366d0572c1865b43dec8ac00237b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Apr 2025 17:37:55 +1100 Subject: [PATCH 029/302] Pass `Analysis` to `visit_*` instead of `Results`. Every `Results` contains an `Analysis`, but these methods only need the `Analysis`. No point passing them more data than they need. --- compiler/rustc_borrowck/src/lib.rs | 6 ++-- .../src/framework/direction.rs | 34 ++++++++++--------- .../src/framework/graphviz.rs | 16 ++++----- .../src/framework/visitor.rs | 8 ++--- compiler/rustc_mir_dataflow/src/points.rs | 4 +-- compiler/rustc_mir_transform/src/coroutine.rs | 4 +-- .../src/dataflow_const_prop.rs | 34 +++++++------------ 7 files changed, 50 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 83a9827e8f81..4ba238696e29 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -705,7 +705,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, stmt: &Statement<'tcx>, location: Location, @@ -781,7 +781,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, @@ -894,7 +894,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_primary_terminator_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index b8c26dad59f4..5f34650d460f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -222,17 +222,18 @@ impl Direction for Backward { let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_early_terminator_effect(state, term, loc); - vis.visit_after_early_terminator_effect(results, state, term, loc); - results.analysis.apply_primary_terminator_effect(state, term, loc); - vis.visit_after_primary_terminator_effect(results, state, term, loc); + let analysis = &mut results.analysis; + analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(analysis, state, term, loc); + analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(analysis, state, term, loc); for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { let loc = Location { block, statement_index }; - results.analysis.apply_early_statement_effect(state, stmt, loc); - vis.visit_after_early_statement_effect(results, state, stmt, loc); - results.analysis.apply_primary_statement_effect(state, stmt, loc); - vis.visit_after_primary_statement_effect(results, state, stmt, loc); + analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(analysis, state, stmt, loc); + analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(analysis, state, stmt, loc); } vis.visit_block_start(state); @@ -402,20 +403,21 @@ impl Direction for Forward { vis.visit_block_start(state); + let analysis = &mut results.analysis; for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; - results.analysis.apply_early_statement_effect(state, stmt, loc); - vis.visit_after_early_statement_effect(results, state, stmt, loc); - results.analysis.apply_primary_statement_effect(state, stmt, loc); - vis.visit_after_primary_statement_effect(results, state, stmt, loc); + analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(analysis, state, stmt, loc); + analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(analysis, state, stmt, loc); } let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_early_terminator_effect(state, term, loc); - vis.visit_after_early_terminator_effect(results, state, term, loc); - results.analysis.apply_primary_terminator_effect(state, term, loc); - vis.visit_after_primary_terminator_effect(results, state, term, loc); + analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(analysis, state, term, loc); + analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(analysis, state, term, loc); vis.visit_block_end(state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index b5e9a0b89324..14389afff6e7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -729,49 +729,49 @@ where fn visit_after_early_statement_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, &results.analysis)); + before.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } fn visit_after_primary_statement_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { - self.after.push(diff_pretty(state, &self.prev_state, &results.analysis)); + self.after.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } fn visit_after_early_terminator_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, &results.analysis)); + before.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } fn visit_after_primary_terminator_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { - self.after.push(diff_pretty(state, &self.prev_state, &results.analysis)); + self.after.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index c9fdf46c4f5b..07360eb68d18 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -38,7 +38,7 @@ where /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -48,7 +48,7 @@ where /// Called after the "primary" effect of the given statement is applied to `state`. fn visit_after_primary_statement_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -58,7 +58,7 @@ where /// Called after the "early" effect of the given terminator is applied to `state`. fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -70,7 +70,7 @@ where /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_after_primary_terminator_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 21590ff1bbad..806853ae1e4c 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -127,7 +127,7 @@ where { fn visit_after_primary_statement_effect<'mir>( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, state: &A::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, @@ -141,7 +141,7 @@ where fn visit_after_primary_terminator_effect<'mir>( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, state: &A::Domain, _terminator: &'mir mir::Terminator<'tcx>, location: Location, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 0eed46c72f99..8174db853995 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -880,7 +880,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> { fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _statement: &Statement<'tcx>, loc: Location, @@ -890,7 +890,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _terminator: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index a2103a004d2d..12f76d0db1e8 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -23,7 +23,7 @@ use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; +use rustc_mir_dataflow::{Analysis, ResultsVisitor}; use rustc_span::DUMMY_SP; use tracing::{debug, debug_span, instrument}; @@ -959,10 +959,10 @@ fn try_write_constant<'tcx>( } impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { - #[instrument(level = "trace", skip(self, results, statement))] + #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_early_statement_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -972,8 +972,8 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.ecx, - map: &results.analysis.map, + ecx: &mut analysis.ecx, + map: &analysis.map, } .visit_rvalue(rvalue, location); } @@ -981,10 +981,10 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> } } - #[instrument(level = "trace", skip(self, results, statement))] + #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_primary_statement_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -994,12 +994,9 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> // Don't overwrite the assignment if it already uses a constant (to keep the span). } StatementKind::Assign(box (place, _)) => { - if let Some(value) = self.try_make_constant( - &mut results.analysis.ecx, - place, - state, - &results.analysis.map, - ) { + if let Some(value) = + self.try_make_constant(&mut analysis.ecx, place, state, &analysis.map) + { self.patch.assignments.insert(location, value); } } @@ -1009,18 +1006,13 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> fn visit_after_early_terminator_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, terminator: &Terminator<'tcx>, location: Location, ) { - OperandCollector { - state, - visitor: self, - ecx: &mut results.analysis.ecx, - map: &results.analysis.map, - } - .visit_terminator(terminator, location); + OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map } + .visit_terminator(terminator, location); } } From 92799b6f89d2d9bbfcb9b11d1bac57899d0bc435 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 18 Apr 2025 10:46:20 +1000 Subject: [PATCH 030/302] Separate `Analysis` and `Results`. `Results` contains and `Analysis` and an `EntryStates`. The unfortunate thing about this is that the analysis needs to be mutable everywhere (`&mut Analysis`) which forces the `Results` to be mutable everywhere, even though `EntryStates` is immutable everywhere. To fix this, this commit renames `Results` as `AnalysisAndResults`, renames `EntryStates` as `Results`, and separates the analysis and results as much as possible. (`AnalysisAndResults` doesn't get much use, it's mostly there to facilitate method chaining of `iterate_to_fixpoint`.) `Results` is immutable everywhere, which: - is a bit clearer on how the data is used, - avoids an unnecessary clone of entry states in `locals_live_across_suspend_points`, and - moves the results outside the `RefCell` in Formatter. The commit also reformulates `ResultsHandle` as the generic `CowMut`, which is simpler than `ResultsHandle` because it doesn't need the `'tcx` lifetime and the trait bounds. It also which sits nicely alongside the new use of `Cow` in `ResultsCursor`. --- compiler/rustc_borrowck/src/lib.rs | 20 ++--- .../src/framework/cursor.rs | 78 +++++++++++-------- .../src/framework/direction.rs | 18 ++--- .../src/framework/graphviz.rs | 32 ++++---- .../rustc_mir_dataflow/src/framework/mod.rs | 30 ++++--- .../src/framework/results.rs | 57 +++----------- .../rustc_mir_dataflow/src/framework/tests.rs | 6 +- .../src/framework/visitor.rs | 23 +++++- compiler/rustc_mir_dataflow/src/lib.rs | 4 +- compiler/rustc_mir_dataflow/src/points.rs | 6 +- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 20 ++--- compiler/rustc_mir_transform/src/coroutine.rs | 47 +++++++---- .../src/dataflow_const_prop.rs | 11 +-- compiler/rustc_mir_transform/src/dest_prop.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 5 +- src/doc/rustc-dev-guide/src/mir/dataflow.md | 3 +- 16 files changed, 188 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4ba238696e29..bf6512ee2332 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -47,7 +47,7 @@ use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; -use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; +use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use smallvec::SmallVec; @@ -461,11 +461,13 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. mbcx.report_region_errors(nll_errors); - let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); + let (mut flow_analysis, flow_entry_states) = + get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut flow_results, + &mut flow_analysis, + &flow_entry_states, &mut mbcx, ); @@ -525,7 +527,7 @@ fn get_flow_results<'a, 'tcx>( move_data: &'a MoveData<'tcx>, borrow_set: &'a BorrowSet<'tcx>, regioncx: &RegionInferenceContext<'tcx>, -) -> Results<'tcx, Borrowck<'a, 'tcx>> { +) -> (Borrowck<'a, 'tcx>, Results) { // We compute these three analyses individually, but them combine them into // a single results so that `mbcx` can visit them all together. let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint( @@ -550,14 +552,14 @@ fn get_flow_results<'a, 'tcx>( ever_inits: ever_inits.analysis, }; - assert_eq!(borrows.entry_states.len(), uninits.entry_states.len()); - assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len()); - let entry_states: EntryStates<'_, Borrowck<'_, '_>> = - itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states) + assert_eq!(borrows.results.len(), uninits.results.len()); + assert_eq!(borrows.results.len(), ever_inits.results.len()); + let results: Results<_> = + itertools::izip!(borrows.results, uninits.results, ever_inits.results) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .collect(); - Results { analysis, entry_states } + (analysis, results) } pub(crate) struct BorrowckInferCtxt<'tcx> { diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index d5005768b80b..3f6e7a066192 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -1,5 +1,6 @@ //! Random access inspection of the results of a dataflow analysis. +use std::borrow::Cow; use std::cmp::Ordering; use std::ops::{Deref, DerefMut}; @@ -9,38 +10,30 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either -/// mutable or immutably. This type allows all of the above. It's similar to `Cow`. -pub enum ResultsHandle<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - BorrowedMut(&'a mut Results<'tcx, A>), - Owned(Results<'tcx, A>), +/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either +/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow` +/// doesn't allow mutable borrowing. +enum CowMut<'a, T> { + BorrowedMut(&'a mut T), + Owned(T), } -impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A> -where - A: Analysis<'tcx>, -{ - type Target = Results<'tcx, A>; +impl Deref for CowMut<'_, T> { + type Target = T; - fn deref(&self) -> &Results<'tcx, A> { + fn deref(&self) -> &T { match self { - ResultsHandle::BorrowedMut(borrowed) => borrowed, - ResultsHandle::Owned(owned) => owned, + CowMut::BorrowedMut(borrowed) => borrowed, + CowMut::Owned(owned) => owned, } } } -impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A> -where - A: Analysis<'tcx>, -{ - fn deref_mut(&mut self) -> &mut Results<'tcx, A> { +impl DerefMut for CowMut<'_, T> { + fn deref_mut(&mut self) -> &mut T { match self { - ResultsHandle::BorrowedMut(borrowed) => borrowed, - ResultsHandle::Owned(owned) => owned, + CowMut::BorrowedMut(borrowed) => borrowed, + CowMut::Owned(owned) => owned, } } } @@ -60,7 +53,8 @@ where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - results: ResultsHandle<'mir, 'tcx, A>, + analysis: CowMut<'mir, A>, + results: Cow<'mir, Results>, state: A::Domain, pos: CursorPosition, @@ -88,11 +82,15 @@ where self.body } - /// Returns a new cursor that can inspect `results`. - pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self { - let bottom_value = results.analysis.bottom_value(body); + fn new( + body: &'mir mir::Body<'tcx>, + analysis: CowMut<'mir, A>, + results: Cow<'mir, Results>, + ) -> Self { + let bottom_value = analysis.bottom_value(body); ResultsCursor { body, + analysis, results, // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that @@ -107,6 +105,24 @@ where } } + /// Returns a new cursor that takes ownership of and inspects analysis results. + pub fn new_owning( + body: &'mir mir::Body<'tcx>, + analysis: A, + results: Results, + ) -> Self { + Self::new(body, CowMut::Owned(analysis), Cow::Owned(results)) + } + + /// Returns a new cursor that borrows and inspects analysis results. + pub fn new_borrowing( + body: &'mir mir::Body<'tcx>, + analysis: &'mir mut A, + results: &'mir Results, + ) -> Self { + Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results)) + } + /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled. #[cfg(test)] pub(crate) fn allow_unreachable(&mut self) { @@ -116,7 +132,7 @@ where /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { - &self.results.analysis + &self.analysis } /// Resets the cursor to hold the entry set for the given basic block. @@ -128,7 +144,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.clone_from(self.results.entry_set_for_block(block)); + self.state.clone_from(&self.results[block]); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -220,7 +236,7 @@ where let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - &mut self.results.analysis, + &mut *self.analysis, &mut self.state, target.block, block_data, @@ -236,7 +252,7 @@ where /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) { - f(&mut self.results.analysis, &mut self.state); + f(&mut self.analysis, &mut self.state); self.state_needs_reset = true; } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 5f34650d460f..e955e38ad10f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::{ }; use super::visitor::ResultsVisitor; -use super::{Analysis, Effect, EffectIndex, Results}; +use super::{Analysis, Effect, EffectIndex}; pub trait Direction { const IS_FORWARD: bool; @@ -36,13 +36,13 @@ pub trait Direction { A: Analysis<'tcx>; /// Called by `ResultsVisitor` to recompute the analysis domain values for - /// all locations in a basic block (starting from the entry value stored - /// in `Results`) and to visit them with `vis`. + /// all locations in a basic block (starting from `entry_state` and to + /// visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>; @@ -211,18 +211,15 @@ impl Direction for Backward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - state.clone_from(results.entry_set_for_block(block)); - vis.visit_block_end(state); let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - let analysis = &mut results.analysis; analysis.apply_early_terminator_effect(state, term, loc); vis.visit_after_early_terminator_effect(analysis, state, term, loc); analysis.apply_primary_terminator_effect(state, term, loc); @@ -394,16 +391,13 @@ impl Direction for Forward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - state.clone_from(results.entry_set_for_block(block)); - vis.visit_block_start(state); - let analysis = &mut results.analysis; for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; analysis.apply_early_statement_effect(state, stmt, loc); diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 14389afff6e7..a7d5422a3d72 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -21,7 +21,9 @@ use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; -use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor}; +use super::{ + Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor, visit_results, +}; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; @@ -32,7 +34,8 @@ use crate::errors::{ pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, pass_name: Option<&'static str>, ) -> std::io::Result<()> where @@ -77,7 +80,7 @@ where let mut buf = Vec::new(); - let graphviz = Formatter::new(body, results, style); + let graphviz = Formatter::new(body, analysis, results, style); let mut render_opts = vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())]; if tcx.sess.opts.unstable_opts.graphviz_dark_mode { @@ -203,10 +206,11 @@ where { body: &'mir Body<'tcx>, // The `RefCell` is used because `::node_label` - // takes `&self`, but it needs to modify the results. This is also the + // takes `&self`, but it needs to modify the analysis. This is also the // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has // the operations that involve the mutation, i.e. within the `borrow_mut`. - results: RefCell<&'mir mut Results<'tcx, A>>, + analysis: RefCell<&'mir mut A>, + results: &'mir Results, style: OutputStyle, reachable: DenseBitSet, } @@ -217,11 +221,12 @@ where { fn new( body: &'mir Body<'tcx>, - results: &'mir mut Results<'tcx, A>, + analysis: &'mir mut A, + results: &'mir Results, style: OutputStyle, ) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { body, results: results.into(), style, reachable } + Formatter { body, analysis: analysis.into(), results, style, reachable } } } @@ -259,12 +264,12 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut results = self.results.borrow_mut(); + let analysis = &mut **self.analysis.borrow_mut(); - let diffs = StateDiffCollector::run(self.body, *block, *results, self.style); + let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style); let mut fmt = BlockFormatter { - cursor: results.as_results_cursor(self.body), + cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results), style: self.style, bg: Background::Light, }; @@ -692,7 +697,8 @@ impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, style: OutputStyle, ) -> Self where @@ -700,12 +706,12 @@ impl StateDiffCollector { D: DebugWithContext, { let mut collector = StateDiffCollector { - prev_state: results.analysis.bottom_value(body), + prev_state: analysis.bottom_value(body), after: vec![], before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; - results.visit_with(body, std::iter::once(block), &mut collector); + visit_results(body, std::iter::once(block), analysis, results, &mut collector); collector } } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 09f6cdb5c4a7..9cadec100b53 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -58,8 +58,9 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub use self::results::{EntryStates, Results}; -pub use self::visitor::{ResultsVisitor, visit_results}; +pub(crate) use self::results::AnalysisAndResults; +pub use self::results::Results; +pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds /// operations needed by all of them. @@ -247,17 +248,15 @@ pub trait Analysis<'tcx> { tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, - ) -> Results<'tcx, Self> + ) -> AnalysisAndResults<'tcx, Self> where Self: Sized, Self::Domain: DebugWithContext, { - let mut entry_states = - IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); - self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]); + let mut results = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut results[mir::START_BLOCK]); - if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body) - { + if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } @@ -280,10 +279,9 @@ pub trait Analysis<'tcx> { // every iteration. let mut state = self.bottom_value(body); while let Some(bb) = dirty_queue.pop() { - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_states[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_states[bb]); + // Set the state to the entry state of the block. This is equivalent to `state = + // results[bb].clone()`, but it saves an allocation, thus improving compile times. + state.clone_from(&results[bb]); Self::Direction::apply_effects_in_block( &mut self, @@ -292,7 +290,7 @@ pub trait Analysis<'tcx> { bb, &body[bb], |target: BasicBlock, state: &Self::Domain| { - let set_changed = entry_states[target].join(state); + let set_changed = results[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -300,16 +298,14 @@ pub trait Analysis<'tcx> { ); } - let mut results = Results { analysis: self, entry_states }; - if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &mut results, pass_name); + let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } } - results + AnalysisAndResults { analysis: self, results } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 93dfc06a878a..7b7e981d3a55 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -1,63 +1,30 @@ //! Dataflow analysis results. use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, traversal}; +use rustc_middle::mir::{BasicBlock, Body}; -use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results}; -use crate::framework::cursor::ResultsHandle; +use super::{Analysis, ResultsCursor}; -pub type EntryStates<'tcx, A> = IndexVec>::Domain>; +/// The results of a dataflow analysis that has converged to fixpoint. It only holds the domain +/// values at the entry of each basic block. Domain values in other parts of the block are +/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). +pub type Results = IndexVec; -/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the -/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly -/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). -#[derive(Clone)] -pub struct Results<'tcx, A> +/// Utility type used in a few places where it's convenient to bundle an analysis with its results. +pub struct AnalysisAndResults<'tcx, A> where A: Analysis<'tcx>, { pub analysis: A, - pub entry_states: EntryStates<'tcx, A>, + pub results: Results, } -impl<'tcx, A> Results<'tcx, A> +impl<'tcx, A> AnalysisAndResults<'tcx, A> where A: Analysis<'tcx>, { - /// Creates a `ResultsCursor` that mutably borrows the `Results`, which is appropriate when the - /// `Results` is also used outside the cursor. - pub fn as_results_cursor<'mir>( - &'mir mut self, - body: &'mir Body<'tcx>, - ) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new(body, ResultsHandle::BorrowedMut(self)) - } - - /// Creates a `ResultsCursor` that takes ownership of the `Results`. + /// Creates a `ResultsCursor` that takes ownership of `self`. pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new(body, ResultsHandle::Owned(self)) - } - - /// Gets the dataflow state for the given block. - pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { - &self.entry_states[block] - } - - pub fn visit_with<'mir>( - &mut self, - body: &'mir Body<'tcx>, - blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'tcx, A>, - ) { - visit_results(body, blocks, self, vis) - } - - pub fn visit_reachable_with<'mir>( - &mut self, - body: &'mir Body<'tcx>, - vis: &mut impl ResultsVisitor<'tcx, A>, - ) { - let blocks = traversal::reachable(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) + ResultsCursor::new_owning(body, self.analysis, self.results) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index ae0f1179e6fa..8602bb557652 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -79,7 +79,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { /// /// The `102` in the block's entry set is derived from the basic block index and ensures that the /// expected state is unique across all basic blocks. Remember, it is generated by -/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint. +/// `mock_results`, not from actually running `MockAnalysis` to fixpoint. struct MockAnalysis<'tcx, D> { body: &'tcx mir::Body<'tcx>, dir: PhantomData, @@ -96,7 +96,7 @@ impl MockAnalysis<'_, D> { ret } - fn mock_entry_states(&self) -> IndexVec> { + fn mock_results(&self) -> IndexVec> { let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); @@ -255,7 +255,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body); + AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body); cursor.allow_unreachable(); diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 07360eb68d18..fbb9e4108726 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::mir::{self, BasicBlock, Location, traversal}; use super::{Analysis, Direction, Results}; @@ -7,12 +7,13 @@ use super::{Analysis, Direction, Results}; pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - let mut state = results.analysis.bottom_value(body); + let mut state = analysis.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -22,10 +23,24 @@ pub fn visit_results<'mir, 'tcx, A>( assert!(reachable_blocks.contains(block)); let block_data = &body[block]; - A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); + state.clone_from(&results[block]); + A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis); } } +/// Like `visit_results`, but only for reachable blocks. +pub fn visit_reachable_results<'mir, 'tcx, A>( + body: &'mir mir::Body<'tcx>, + analysis: &mut A, + results: &Results, + vis: &mut impl ResultsVisitor<'tcx, A>, +) where + A: Analysis<'tcx>, +{ + let blocks = traversal::reachable(body).map(|(bb, _)| bb); + visit_results(body, blocks, analysis, results, vis) +} + /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in /// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain /// locations. diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index a0efc623b8e7..420c003fa239 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable, - Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_results, + Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, + ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 806853ae1e4c..70d1a34b5fb1 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -98,7 +98,8 @@ rustc_index::newtype_index! { pub fn save_as_intervals<'tcx, N, A>( elements: &DenseLocationMap, body: &mir::Body<'tcx>, - mut results: Results<'tcx, A>, + mut analysis: A, + results: Results, ) -> SparseIntervalMatrix where N: Idx, @@ -109,7 +110,8 @@ where visit_results( body, body.basic_blocks.reverse_postorder().iter().copied(), - &mut results, + &mut analysis, + &results, &mut visitor, ); visitor.values diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 399141aa9212..303fc767b9a3 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -39,23 +39,23 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = - MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_inits); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_uninits); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); + let flow_liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_liveness); } if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 8174db853995..18ff70809cbd 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -72,7 +72,9 @@ use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, always_storage_live_locals, }; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; +use rustc_mir_dataflow::{ + Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results, +}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Span, sym}; use rustc_target::spec::PanicStrategy; @@ -669,18 +671,29 @@ fn locals_live_across_suspend_points<'tcx>( .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); - // Calculate the MIR locals which have been previously - // borrowed (even if they are still active). - let borrowed_locals_results = - MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); - - let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); + // Calculate the MIR locals that have been previously borrowed (even if they are still active). + let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); + let mut borrowed_locals_analysis1 = borrowed_locals.analysis; + let mut borrowed_locals_analysis2 = borrowed_locals_analysis1.clone(); // trivial + let borrowed_locals_cursor1 = ResultsCursor::new_borrowing( + body, + &mut borrowed_locals_analysis1, + &borrowed_locals.results, + ); + let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing( + body, + &mut borrowed_locals_analysis2, + &borrowed_locals.results, + ); // Calculate the MIR locals that we need to keep storage around for. - let mut requires_storage_results = - MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) - .iterate_to_fixpoint(tcx, body, None); - let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body); + let mut requires_storage = + MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); + let mut requires_storage_cursor = ResultsCursor::new_borrowing( + body, + &mut requires_storage.analysis, + &requires_storage.results, + ); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = @@ -709,8 +722,8 @@ fn locals_live_across_suspend_points<'tcx>( // If a borrow is converted to a raw reference, we must also assume that it lives // forever. Note that the final liveness is still bounded by the storage liveness // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor.seek_before_primary_effect(loc); - live_locals.union(borrowed_locals_cursor.get()); + borrowed_locals_cursor2.seek_before_primary_effect(loc); + live_locals.union(borrowed_locals_cursor2.get()); } // Store the storage liveness for later use so we can restore the state @@ -752,7 +765,8 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - requires_storage_results, + &mut requires_storage.analysis, + &requires_storage.results, ); LivenessInfo { @@ -817,7 +831,8 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &'mir CoroutineSavedLocals, always_live_locals: DenseBitSet, - mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, + analysis: &mut MaybeRequiresStorage<'mir, 'tcx>, + results: &Results>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); @@ -837,7 +852,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), }; - requires_storage.visit_reachable_with(body, &mut visitor); + visit_reachable_results(body, analysis, results, &mut visitor); let local_conflicts = visitor.local_conflicts; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 12f76d0db1e8..99b95e7312bd 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -23,7 +23,7 @@ use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; -use rustc_mir_dataflow::{Analysis, ResultsVisitor}; +use rustc_mir_dataflow::{Analysis, ResultsVisitor, visit_reachable_results}; use rustc_span::DUMMY_SP; use tracing::{debug, debug_span, instrument}; @@ -61,13 +61,14 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. - let analysis = ConstAnalysis::new(tcx, body, map); - let mut results = - debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None)); + let mut const_ = debug_span!("analyze") + .in_scope(|| ConstAnalysis::new(tcx, body, map).iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); - debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor)); + debug_span!("collect").in_scope(|| { + visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor) + }); let mut patch = visitor.patch; debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body)); } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 7395ad496dbd..4c94a6c524e0 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -171,7 +171,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp")); let points = DenseLocationMap::new(body); - let mut live = save_as_intervals(&points, body, live); + let mut live = save_as_intervals(&points, body, live.analysis, live.results); // In order to avoid having to collect data for every single pair of locals in the body, we // do not allow doing more than one merge for places that are derived from the same local at diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 537f152938ef..0bf57f27c2ab 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -233,8 +233,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // When we encounter a DROP of some place P we only care // about the drop if `P` may be initialized. let move_data = MoveData::gather_moves(body, tcx, |_| true); - let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data); - let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + let mut maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); let mut block_drop_value_info = IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len()); for (&block, candidates) in &bid_per_block { diff --git a/src/doc/rustc-dev-guide/src/mir/dataflow.md b/src/doc/rustc-dev-guide/src/mir/dataflow.md index f31da5ca22ee..85e57dd839b8 100644 --- a/src/doc/rustc-dev-guide/src/mir/dataflow.md +++ b/src/doc/rustc-dev-guide/src/mir/dataflow.md @@ -148,8 +148,7 @@ whereas this code uses [`ResultsCursor`]: ```rust,ignore let mut results = MyAnalysis::new() - .into_engine(tcx, body, def_id) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None); .into_results_cursor(body); // Inspect the fixpoint state immediately before each `Drop` terminator. From 6e64338a49eea12ed257805ce299cfd45b082d04 Mon Sep 17 00:00:00 2001 From: bendn Date: Mon, 31 Mar 2025 15:50:56 +0700 Subject: [PATCH 031/302] Suggest {to,from}_ne_bytes for transmutations between arrays and integers, etc --- tests/ui/blocks_in_conditions.fixed | 8 +- tests/ui/blocks_in_conditions.rs | 8 +- tests/ui/blocks_in_conditions.stderr | 6 +- tests/ui/crashes/ice-1782.rs | 2 +- tests/ui/transmute.rs | 1 + tests/ui/transmute.stderr | 108 ++++++++++---------- tests/ui/transmute_float_to_int.fixed | 2 +- tests/ui/transmute_float_to_int.rs | 2 +- tests/ui/transmute_int_to_char.fixed | 2 +- tests/ui/transmute_int_to_char.rs | 2 +- tests/ui/transmute_int_to_char_no_std.fixed | 2 +- tests/ui/transmute_int_to_char_no_std.rs | 2 +- 12 files changed, 79 insertions(+), 66 deletions(-) diff --git a/tests/ui/blocks_in_conditions.fixed b/tests/ui/blocks_in_conditions.fixed index c82276b358e1..e696896538e5 100644 --- a/tests/ui/blocks_in_conditions.fixed +++ b/tests/ui/blocks_in_conditions.fixed @@ -1,7 +1,13 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] +#![allow( + unused, + unnecessary_transmutes, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/tests/ui/blocks_in_conditions.rs b/tests/ui/blocks_in_conditions.rs index 6a4a7c621068..8c8f3249b8a7 100644 --- a/tests/ui/blocks_in_conditions.rs +++ b/tests/ui/blocks_in_conditions.rs @@ -1,7 +1,13 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] +#![allow( + unused, + unnecessary_transmutes, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/tests/ui/blocks_in_conditions.stderr b/tests/ui/blocks_in_conditions.stderr index e57eca5dceef..41ff59c683e8 100644 --- a/tests/ui/blocks_in_conditions.stderr +++ b/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:25:5 + --> tests/ui/blocks_in_conditions.rs:31:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:37:8 + --> tests/ui/blocks_in_conditions.rs:43:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:43:8 + --> tests/ui/blocks_in_conditions.rs:49:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` diff --git a/tests/ui/crashes/ice-1782.rs b/tests/ui/crashes/ice-1782.rs index 4a1886c08af6..776b0a93bf7c 100644 --- a/tests/ui/crashes/ice-1782.rs +++ b/tests/ui/crashes/ice-1782.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(dead_code, unused_variables, invalid_null_arguments)] +#![allow(dead_code, unused_variables, invalid_null_arguments, unnecessary_transmutes)] #![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 8c8674ac356d..2b8b6c539ad3 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -3,6 +3,7 @@ #![allow( dead_code, clippy::borrow_as_ptr, + unnecessary_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 4219e09d2aba..1bb70151965c 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:32:27 + --> tests/ui/transmute.rs:33:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,61 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:35:25 + --> tests/ui/transmute.rs:36:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:38:27 + --> tests/ui/transmute.rs:39:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:46:27 + --> tests/ui/transmute.rs:47:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:49:27 + --> tests/ui/transmute.rs:50:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:52:27 + --> tests/ui/transmute.rs:53:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:55:27 + --> tests/ui/transmute.rs:56:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:58:27 + --> tests/ui/transmute.rs:59:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:61:31 + --> tests/ui/transmute.rs:62:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:66:31 + --> tests/ui/transmute.rs:67:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:98:24 + --> tests/ui/transmute.rs:99:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:101:24 + --> tests/ui/transmute.rs:102:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:104:31 + --> tests/ui/transmute.rs:105:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:107:29 + --> tests/ui/transmute.rs:108:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:114:28 + --> tests/ui/transmute.rs:115:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:121:31 + --> tests/ui/transmute.rs:122:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` @@ -107,97 +107,97 @@ LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:124:31 + --> tests/ui/transmute.rs:125:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:127:31 + --> tests/ui/transmute.rs:128:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:130:31 + --> tests/ui/transmute.rs:131:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:133:31 + --> tests/ui/transmute.rs:134:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:136:31 + --> tests/ui/transmute.rs:137:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:139:32 + --> tests/ui/transmute.rs:140:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:142:32 + --> tests/ui/transmute.rs:143:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:147:39 + --> tests/ui/transmute.rs:148:39 | LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:150:39 + --> tests/ui/transmute.rs:151:39 | LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:153:39 + --> tests/ui/transmute.rs:154:39 | LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:156:41 + --> tests/ui/transmute.rs:157:41 | LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:160:22 + --> tests/ui/transmute.rs:161:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:165:22 + --> tests/ui/transmute.rs:166:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:170:22 + --> tests/ui/transmute.rs:171:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:175:22 + --> tests/ui/transmute.rs:176:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:184:30 + --> tests/ui/transmute.rs:185:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -206,121 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:187:30 + --> tests/ui/transmute.rs:188:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:190:31 + --> tests/ui/transmute.rs:191:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:193:30 + --> tests/ui/transmute.rs:194:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:196:30 + --> tests/ui/transmute.rs:197:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:199:31 + --> tests/ui/transmute.rs:200:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:202:30 + --> tests/ui/transmute.rs:203:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:205:30 + --> tests/ui/transmute.rs:206:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:208:30 + --> tests/ui/transmute.rs:209:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:211:31 + --> tests/ui/transmute.rs:212:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:217:30 + --> tests/ui/transmute.rs:218:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:220:30 + --> tests/ui/transmute.rs:221:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:223:31 + --> tests/ui/transmute.rs:224:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:226:30 + --> tests/ui/transmute.rs:227:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:229:30 + --> tests/ui/transmute.rs:230:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:232:31 + --> tests/ui/transmute.rs:233:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:235:30 + --> tests/ui/transmute.rs:236:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:238:30 + --> tests/ui/transmute.rs:239:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:241:30 + --> tests/ui/transmute.rs:242:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:244:31 + --> tests/ui/transmute.rs:245:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:253:28 + --> tests/ui/transmute.rs:254:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -329,13 +329,13 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:256:32 + --> tests/ui/transmute.rs:257:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:259:30 + --> tests/ui/transmute.rs:260:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` diff --git a/tests/ui/transmute_float_to_int.fixed b/tests/ui/transmute_float_to_int.fixed index 1f97b997eaa0..844445907d7c 100644 --- a/tests/ui/transmute_float_to_int.fixed +++ b/tests/ui/transmute_float_to_int.fixed @@ -1,5 +1,5 @@ #![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] #![feature(f128)] #![feature(f16)] diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs index 788a7e1026c6..a1f3b15bbfee 100644 --- a/tests/ui/transmute_float_to_int.rs +++ b/tests/ui/transmute_float_to_int.rs @@ -1,5 +1,5 @@ #![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] #![feature(f128)] #![feature(f16)] diff --git a/tests/ui/transmute_int_to_char.fixed b/tests/ui/transmute_int_to_char.fixed index b5425a2e9e85..28644aa9ebbb 100644 --- a/tests/ui/transmute_int_to_char.fixed +++ b/tests/ui/transmute_int_to_char.fixed @@ -1,5 +1,5 @@ #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] fn int_to_char() { let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; diff --git a/tests/ui/transmute_int_to_char.rs b/tests/ui/transmute_int_to_char.rs index b24bb177c9fc..8c83ecc8914b 100644 --- a/tests/ui/transmute_int_to_char.rs +++ b/tests/ui/transmute_int_to_char.rs @@ -1,5 +1,5 @@ #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] fn int_to_char() { let _: char = unsafe { std::mem::transmute(0_u32) }; diff --git a/tests/ui/transmute_int_to_char_no_std.fixed b/tests/ui/transmute_int_to_char_no_std.fixed index e525751e306e..e6e09a2be4bf 100644 --- a/tests/ui/transmute_int_to_char_no_std.fixed +++ b/tests/ui/transmute_int_to_char_no_std.fixed @@ -1,7 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] use core::panic::PanicInfo; diff --git a/tests/ui/transmute_int_to_char_no_std.rs b/tests/ui/transmute_int_to_char_no_std.rs index 7cb508ceaf3b..0f2106df00e6 100644 --- a/tests/ui/transmute_int_to_char_no_std.rs +++ b/tests/ui/transmute_int_to_char_no_std.rs @@ -1,7 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] use core::panic::PanicInfo; From 6ee75c4a6e1e26ac04c825585a18f1645fd5385b Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 24 Apr 2025 11:31:33 +0100 Subject: [PATCH 032/302] Remove `weak` alias terminology --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7da5a530eaa3..5edb5c235703 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -853,7 +853,7 @@ impl TyCoercionStability { continue; }, ty::Param(_) if for_return => Self::Deref, - ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"), + ty::Alias(ty::Free | ty::Inherent, _) => unreachable!("should have been normalized away above"), ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow, ty::Infer(_) | ty::Error(_) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 67537a251da7..1f142bc3ba63 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -197,7 +197,7 @@ fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool inputs.iter().any(|input| { matches!( input.kind(), - ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() + ty::Alias(ty::AliasTyKind::Free, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() ) }) } From 736be8bbb1f620854e068570e7ec1fd3f1a6c139 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 24 Apr 2025 13:40:57 +0000 Subject: [PATCH 033/302] Consistently refer to the `?` operator --- clippy_lints/src/methods/mod.rs | 5 ++--- clippy_lints/src/methods/return_and_then.rs | 11 +++++++++-- clippy_lints/src/question_mark.rs | 8 ++++---- clippy_lints/src/question_mark_used.rs | 18 ++++++------------ clippy_utils/src/lib.rs | 5 ++--- tests/ui/question_mark_used.stderr | 2 +- tests/ui/return_and_then.stderr | 14 +++++++------- 7 files changed, 31 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ad374dee516c..10f4637d08f6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4370,11 +4370,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// - /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead. + /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using + /// the `?` operator instead. /// /// ### Why is this bad? - /// /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`. /// This can be replaced with the `?` operator, which is more concise and idiomatic. /// diff --git a/clippy_lints/src/methods/return_and_then.rs b/clippy_lints/src/methods/return_and_then.rs index e8861935d421..91643b0dfefd 100644 --- a/clippy_lints/src/methods/return_and_then.rs +++ b/clippy_lints/src/methods/return_and_then.rs @@ -55,7 +55,6 @@ pub(super) fn check<'tcx>( None => &body_snip, }; - let msg = "use the question mark operator instead of an `and_then` call"; let sugg = format!( "let {} = {}?;\n{}", arg_snip, @@ -63,5 +62,13 @@ pub(super) fn check<'tcx>( reindent_multiline(inner, false, indent_of(cx, expr.span)) ); - span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability); + span_lint_and_sugg( + cx, + RETURN_AND_THEN, + expr.span, + "use the `?` operator instead of an `and_then` call", + "try", + sugg, + applicability, + ); } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d318897443da..d193a534b65a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -27,10 +27,10 @@ use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that could be replaced by the question mark operator. + /// Checks for expressions that could be replaced by the `?` operator. /// /// ### Why is this bad? - /// Question mark usage is more idiomatic. + /// Using the `?` operator is shorter and more idiomatic. /// /// ### Example /// ```ignore @@ -47,7 +47,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub QUESTION_MARK, style, - "checks for expressions that could be replaced by the question mark operator" + "checks for expressions that could be replaced by the `?` operator" } pub struct QuestionMark { @@ -280,7 +280,7 @@ fn expr_return_none_or_err( /// } /// ``` /// -/// If it matches, it will suggest to use the question mark operator instead +/// If it matches, it will suggest to use the `?` operator instead fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) && !is_else_clause(cx.tcx, expr) diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index 0a974bf9d2f7..96ea485d7693 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that use the question mark operator and rejects them. + /// Checks for expressions that use the `?` operator and rejects them. /// /// ### Why restrict this? - /// Sometimes code wants to avoid the question mark operator because for instance a local + /// Sometimes code wants to avoid the `?` operator because for instance a local /// block requires a macro to re-throw errors to attach additional information to the /// error. /// @@ -27,7 +27,7 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, - "complains if the question mark operator is used" + "checks if the `?` operator is used" } declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); @@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { } #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - QUESTION_MARK_USED, - expr.span, - "question mark operator was used", - |diag| { - diag.help("consider using a custom macro or match expression"); - }, - ); + span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| { + diag.help("consider using a custom macro or match expression"); + }); } } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 264b9b0406d0..34535a03fcd4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3101,7 +3101,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { sm.span_take_while(span, |&ch| ch == ' ' || ch == ';') } -/// Returns whether the given let pattern and else body can be turned into a question mark +/// Returns whether the given let pattern and else body can be turned into the `?` operator /// /// For this example: /// ```ignore @@ -3124,8 +3124,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// ``` /// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because -/// the question mark operator is applicable here. Callers have to check whether we are in a -/// constant or not. +/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not. pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( cx: &LateContext<'_>, pat: &'a Pat<'hir>, diff --git a/tests/ui/question_mark_used.stderr b/tests/ui/question_mark_used.stderr index 53cb59c02166..82f0d3250407 100644 --- a/tests/ui/question_mark_used.stderr +++ b/tests/ui/question_mark_used.stderr @@ -1,4 +1,4 @@ -error: question mark operator was used +error: the `?` operator was used --> tests/ui/question_mark_used.rs:11:5 | LL | other_function()?; diff --git a/tests/ui/return_and_then.stderr b/tests/ui/return_and_then.stderr index cc611c3dba67..a7acbe7b3401 100644 --- a/tests/ui/return_and_then.stderr +++ b/tests/ui/return_and_then.stderr @@ -1,4 +1,4 @@ -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:5:9 | LL | / opt.and_then(|n| { @@ -20,7 +20,7 @@ LL + ret += n; LL + if n > 1 { Some(ret) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:14:9 | LL | opt.and_then(|n| test_opt_block(Some(n))) @@ -32,7 +32,7 @@ LL ~ let n = opt?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:19:9 | LL | gen_option(1).and_then(|n| test_opt_block(Some(n))) @@ -44,7 +44,7 @@ LL ~ let n = gen_option(1)?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:24:9 | LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) }) @@ -56,7 +56,7 @@ LL ~ let n = opt?; LL + if n > 1 { Ok(n + 1) } else { Err(n) } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:29:9 | LL | opt.and_then(|n| test_res_block(Ok(n))) @@ -68,7 +68,7 @@ LL ~ let n = opt?; LL + test_res_block(Ok(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:35:9 | LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) @@ -80,7 +80,7 @@ LL ~ let x = Some("")?; LL + if x.len() > 2 { Some(3) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:41:9 | LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) { From fc12b5b6d8f5ed80ba07e2a43b3a08b07d8482d3 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 22 Apr 2025 15:44:11 +0500 Subject: [PATCH 034/302] fix-issue-14665 --- clippy_lints/src/manual_div_ceil.rs | 6 +-- tests/ui/manual_div_ceil.fixed | 23 +++++++++++ tests/ui/manual_div_ceil.rs | 23 +++++++++++ tests/ui/manual_div_ceil.stderr | 62 +++++++++++++++++++++-------- 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 444ecd5d2bb9..ed0cce754b95 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -199,9 +199,9 @@ fn build_suggestion( } else { format!("{dividend_sugg_str}{type_suffix}") }; - let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability); - let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"); + let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0); span_lint_and_sugg( cx, diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed index 57fe8917afe8..58ee6978fc12 100644 --- a/tests/ui/manual_div_ceil.fixed +++ b/tests/ui/manual_div_ceil.fixed @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = 33u32.div_ceil(eight!()); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs index ec343513e5ce..aa0d81b22a0e 100644 --- a/tests/ui/manual_div_ceil.rs +++ b/tests/ui/manual_div_ceil.rs @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = (x + 7) / 8; + //~^ manual_div_ceil + let _ = (7 + x) / 8; + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = (33u32 + 7) / eight!(); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr index 8e14ab274269..9be5a19bf391 100644 --- a/tests/ui/manual_div_ceil.stderr +++ b/tests/ui/manual_div_ceil.stderr @@ -1,5 +1,5 @@ error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:9:13 + --> tests/ui/manual_div_ceil.rs:25:13 | LL | let _ = (x + (y - 1)) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` @@ -8,94 +8,122 @@ LL | let _ = (x + (y - 1)) / y; = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:11:13 + --> tests/ui/manual_div_ceil.rs:27:13 | LL | let _ = ((y - 1) + x) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:13:13 + --> tests/ui/manual_div_ceil.rs:29:13 | LL | let _ = (x + y - 1) / y; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:16:13 + --> tests/ui/manual_div_ceil.rs:32:13 | LL | let _ = (7_u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:18:13 + --> tests/ui/manual_div_ceil.rs:34:13 | LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:39:13 + --> tests/ui/manual_div_ceil.rs:6:17 + | +LL | let _ = (x + 7) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:8:17 + | +LL | let _ = (7 + x) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:56:13 + | +LL | let _ = (33u32 + 7) / eight!(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:62:13 | LL | let _ = (2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:43:13 + --> tests/ui/manual_div_ceil.rs:66:13 | LL | let _ = (2048usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:47:13 + --> tests/ui/manual_div_ceil.rs:70:13 | LL | let _ = (2048_usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:51:13 + --> tests/ui/manual_div_ceil.rs:74:13 | LL | let _ = (x + 4 - 1) / 4; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:54:18 + --> tests/ui/manual_div_ceil.rs:77:18 | LL | let _: u32 = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:56:20 + --> tests/ui/manual_div_ceil.rs:79:20 | LL | let _: usize = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:58:18 + --> tests/ui/manual_div_ceil.rs:81:18 | LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:61:13 + --> tests/ui/manual_div_ceil.rs:84:13 | LL | let _ = (2048 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:64:13 + --> tests/ui/manual_div_ceil.rs:87:13 | LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:70:13 + --> tests/ui/manual_div_ceil.rs:93:13 | LL | let _ = (x + 7) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:72:13 + --> tests/ui/manual_div_ceil.rs:95:13 | LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` -error: aborting due to 16 previous errors +error: aborting due to 19 previous errors From 7b337f6e259ce3ae19e1c0c22c8ff493ecb4a8a3 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 23 Apr 2025 13:24:01 +0000 Subject: [PATCH 035/302] Replace some `Symbol::as_str` usage --- clippy_lints/src/assigning_clones.rs | 11 +-- .../attrs/blanket_clippy_restriction_lints.rs | 8 +- clippy_lints/src/attrs/deprecated_cfg_attr.rs | 2 +- clippy_lints/src/attrs/deprecated_semver.rs | 3 +- .../src/casts/cast_abs_to_unsigned.rs | 3 +- .../src/casts/cast_possible_truncation.rs | 4 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 5 +- clippy_lints/src/crate_in_macro_def.rs | 5 +- clippy_lints/src/floating_point_arithmetic.rs | 4 +- clippy_lints/src/from_raw_with_void_ptr.rs | 5 +- clippy_lints/src/from_str_radix_10.rs | 5 +- clippy_lints/src/implicit_hasher.rs | 21 ++-- clippy_lints/src/infinite_iter.rs | 9 +- clippy_lints/src/iter_without_into_iter.rs | 5 +- clippy_lints/src/len_zero.rs | 8 +- clippy_lints/src/loops/same_item_push.rs | 5 +- clippy_lints/src/manual_hash_one.rs | 7 +- clippy_lints/src/manual_is_ascii_check.rs | 6 +- clippy_lints/src/manual_option_as_slice.rs | 6 +- .../src/methods/double_ended_iterator_last.rs | 6 +- clippy_lints/src/methods/filter_map.rs | 4 +- .../methods/needless_character_iteration.rs | 6 +- clippy_lints/src/methods/needless_collect.rs | 6 +- .../src/methods/read_line_without_trim.rs | 7 +- clippy_lints/src/methods/str_split.rs | 3 +- .../src/methods/unnecessary_filter_map.rs | 5 +- .../src/methods/unnecessary_to_owned.rs | 12 +-- clippy_lints/src/minmax.rs | 13 +-- clippy_lints/src/missing_fields_in_debug.rs | 6 +- .../src/mixed_read_write_in_expression.rs | 4 +- clippy_lints/src/needless_for_each.rs | 6 +- .../src/non_octal_unix_permissions.rs | 6 +- clippy_lints/src/non_zero_suggestions.rs | 4 +- clippy_lints/src/operators/float_cmp.rs | 6 +- .../src/permissions_set_readonly_false.rs | 4 +- clippy_lints/src/ptr_offset_with_cast.rs | 4 +- clippy_lints/src/question_mark.rs | 7 +- .../src/slow_vector_initialization.rs | 9 +- clippy_lints/src/strings.rs | 6 +- clippy_lints/src/to_digit_is_some.rs | 6 +- clippy_lints/src/transmute/eager_transmute.rs | 6 +- clippy_lints/src/uninit_vec.rs | 8 +- clippy_lints/src/unused_self.rs | 11 +-- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/write.rs | 12 +-- clippy_lints_internal/src/lib.rs | 8 +- .../src/{interning_literals.rs => symbols.rs} | 99 ++++++++++++++++--- clippy_utils/src/higher.rs | 6 +- clippy_utils/src/lib.rs | 4 +- clippy_utils/src/sym.rs | 44 +++++++++ tests/ui-internal/symbol_as_str.fixed | 21 ++++ tests/ui-internal/symbol_as_str.rs | 21 ++++ tests/ui-internal/symbol_as_str.stderr | 76 ++++++++++++++ tests/ui-internal/symbol_as_str_unfixable.rs | 15 +++ .../symbol_as_str_unfixable.stderr | 40 ++++++++ 55 files changed, 448 insertions(+), 179 deletions(-) rename clippy_lints_internal/src/{interning_literals.rs => symbols.rs} (52%) create mode 100644 tests/ui-internal/symbol_as_str.fixed create mode 100644 tests/ui-internal/symbol_as_str.rs create mode 100644 tests/ui-internal/symbol_as_str.stderr create mode 100644 tests/ui-internal/symbol_as_str_unfixable.rs create mode 100644 tests/ui-internal/symbol_as_str_unfixable.stderr diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 9acff676d4f6..8b8b42bbf722 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { @@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && ctxt.is_root() && let which_trait = match fn_name { sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, - _ if fn_name.as_str() == "to_owned" - && is_diag_trait_item(cx, fn_id, sym::ToOwned) - && self.msrv.meets(cx, msrvs::CLONE_INTO) => + sym::to_owned + if is_diag_trait_item(cx, fn_id, sym::ToOwned) + && self.msrv.meets(cx, msrvs::CLONE_INTO) => { CloneTrait::ToOwned }, @@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { CloneTrait::Clone => assoc.name() == sym::clone_from, - CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", + CloneTrait::ToOwned => assoc.name() == sym::clone_into, } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 457692ed5dc5..4d64eec25d27 100644 --- a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,17 +1,15 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::sym; use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, Level, LintContext}; +use rustc_span::DUMMY_SP; use rustc_span::symbol::Symbol; -use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { - if let Some(lint_name) = extract_clippy_lint(lint) - && lint_name.as_str() == "restriction" - && name != sym::allow - { + if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) { span_lint_and_help( cx, BLANKET_CLIPPY_RESTRICTION_LINTS, diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index 7fab97d3ea14..0edb50be8c77 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met } fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { - if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { + if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) { span_lint_and_sugg( cx, DEPRECATED_CLIPPY_CFG_ATTR, diff --git a/clippy_lints/src/attrs/deprecated_semver.rs b/clippy_lints/src/attrs/deprecated_semver.rs index 50943b36809d..bd6459d6f9db 100644 --- a/clippy_lints/src/attrs/deprecated_semver.rs +++ b/clippy_lints/src/attrs/deprecated_semver.rs @@ -1,5 +1,6 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; use rustc_ast::{LitKind, MetaItemLit}; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -7,7 +8,7 @@ use semver::Version; pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind - && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok()) + && (is == sym::TBD || Version::parse(is.as_str()).is_ok()) { return; } diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 164d3540253a..ba31a51f738a 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,7 +20,7 @@ pub(super) fn check( if let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind - && method_path.ident.name.as_str() == "abs" + && method_path.ident.name == sym::abs && msrv.meets(cx, msrvs::UNSIGNED_ABS) { let span = if from.bit_width() == to.bit_width() { diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 8742f5f1a0e0..e92879b853d7 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,9 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use clippy_utils::{expr_or_init, sym}; use rustc_abi::IntegerType; use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{DefKind, Res}; @@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b nbits }, ExprKind::MethodCall(method, _value, [], _) => { - if method.ident.name.as_str() == "signum" { + if method.ident.name == sym::signum { 0 // do not lint if cast comes from a `signum` function } else { nbits diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 3fca0f897077..01020f3eee21 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::CAST_PTR_ALIGNMENT; @@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind - && method_path.ident.name.as_str() == "cast" + && method_path.ident.name == sym::cast && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args // There probably is no obvious reason to do this, just to be consistent with `as` cases. diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index c2aac7ca090b..19f62e8bf79c 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{Span, kw}; declare_clippy_lint! { /// ### What it does @@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { fn is_crate_keyword(tt: &TokenTree) -> Option { if let TokenTree::Token( Token { - kind: TokenKind::Ident(symbol, _), + kind: TokenKind::Ident(kw::Crate, _), span, }, _, ) = tt - && symbol.as_str() == "crate" { Some(*span) } else { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index d5f0659f8427..553a00ed868d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate, - numeric_literal, peel_blocks, sugg, + numeric_literal, peel_blocks, sugg, sym, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = expr.kind && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind - && path.ident.name.as_str() == "exp" + && path.ident.name == sym::exp && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) && (F32(1.0) == value || F64(1.0) == value) diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index c8828c936157..5e2e2c9dbf72 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_def_id; use clippy_utils::ty::is_c_void; +use clippy_utils::{path_def_id, sym}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -41,7 +40,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name.as_str() == "from_raw" + && seg.ident.name == sym::from_raw && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() && let ty::RawPtr(ty, _) = arg_kind diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 25b087e8484f..b816963cc825 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::{is_in_const_context, is_integer_literal}; +use clippy_utils::{is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { // check if the second part of the path indeed calls the associated // function `from_str_radix` - && pathseg.ident.name.as_str() == "from_str_radix" + && pathseg.ident.name == sym::from_str_radix // check if the first part of the path is some integer primitive && let TyKind::Path(ty_qpath) = &ty.kind diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index d2545e57652a..4c17834c3adf 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; use rustc_span::Span; -use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if let ExprKind::Call(fun, args) = e.kind && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind + && matches!(method.ident.name, sym::new | sym::with_capacity) && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind && let Some(ty_did) = ty_path.res.opt_def_id() { @@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { return; } - if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { - if method.ident.name == sym::new { + match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) { + (Some(sym::HashMap), sym::new) => { self.suggestions.insert(e.span, "HashMap::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashMap), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } - } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { - if method.ident.name == sym::new { + }, + (Some(sym::HashSet), sym::new) => { self.suggestions.insert(e.span, "HashSet::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashSet), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } + }, + _ => {}, } } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 427a1f825555..c4e10837bf19 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::higher; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::{higher, sym}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .and(cap); } } - if method.ident.name.as_str() == "flat_map" + if method.ident.name == sym::flat_map && args.len() == 1 && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { @@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name.as_str() == "last" && args.is_empty() { + if method.ident.name == sym::last && args.is_empty() { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) @@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if not_double_ended { return is_infinite(cx, receiver); } - } else if method.ident.name.as_str() == "collect" { + } else if method.ident.name == sym::collect { let ty = cx.typeck_results().expr_ty(expr); if matches!( get_type_diagnostic_name(cx, ty), diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 173232c511a5..900b20aa9cfb 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection}; +use clippy_utils::{get_parent_as_impl, sym}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -141,7 +140,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { - if item.ident.name.as_str() == "IntoIter" { + if item.ident.name == sym::IntoIter { Some(cx.tcx.hir_impl_item(item.id).expect_type().span) } else { None diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8c71d34c95f6..aded31971cec 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym}; +use clippy_utils::{ + fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym, +}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method - if let Some(name) = get_item_name(cx, method) - && name.as_str() == "is_empty" - { + if parent_item_name(cx, method) == Some(sym::is_empty) { return; } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 661b4b590d8f..388034c39f52 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{msrvs, path_to_local, std_or_core}; +use clippy_utils::{msrvs, path_to_local, std_or_core, sym}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::SyntaxContext; -use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( @@ -187,8 +186,8 @@ fn get_vec_push<'tcx>( // Extract method being called and figure out the parameters for the method call && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind // Check that the method being called is push() on a Vec + && path.ident.name == sym::push && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec) - && path.ident.name.as_str() == "push" { return Some((self_expr, pushed_item, semi_stmt.span.ctxt())); } diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index f71264a93ca8..b3ee45cc0209 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; -use clippy_utils::{is_trait_method, path_to_local_id}; +use clippy_utils::{is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -66,7 +65,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Some(init) = local.init && !init.span.from_expansion() && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind - && seg.ident.name.as_str() == "build_hasher" + && seg.ident.name == sym::build_hasher && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id) && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id) @@ -94,7 +93,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id) && !finish_expr.span.from_expansion() && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind - && seg.ident.name.as_str() == "finish" + && seg.ident.name == sym::finish && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE) { diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 8ab49bd2ea8e..ac8c88f02057 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; +use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym}; use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind, use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind - && path.ident.name.as_str() == "contains" + && path.ident.name == sym::contains && let Some(higher::Range { start: Some(start), end: Some(end), diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs index e4ad3953b671..b365dbf088f5 100644 --- a/clippy_lints/src/manual_option_as_slice.rs +++ b/clippy_lints/src/manual_option_as_slice.rs @@ -1,14 +1,14 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::msrvs::Msrv; -use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs}; +use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -76,7 +76,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice { } }, ExprKind::MethodCall(seg, callee, [], _) => { - if seg.ident.name.as_str() == "unwrap_or_default" { + if seg.ident.name == sym::unwrap_or_default { check_map(cx, callee, span, self.msrv); } }, diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index e666f31217cc..6d841853fbe5 100644 --- a/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait}; -use clippy_utils::{is_mutable, is_trait_method, path_to_local}; +use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Instance; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::DOUBLE_ENDED_ITERATOR_LAST; @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last) // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id && let self_ty = cx.typeck_results().expr_ty(self_expr) diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index da123f13d46f..4dd54cf19745 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -233,12 +233,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" { + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some { Some(Self::IsSome { receiver, side_effect_expr_span, }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" { + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok { Some(Self::IsOk { receiver, side_effect_expr_span, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 743aacf05885..f528f7f065c6 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -9,7 +9,7 @@ use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::CHAR_IS_ASCII; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { while let ExprKind::AddrOf(_, _, e) = expr.kind { @@ -32,7 +32,7 @@ fn handle_expr( // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is // `is_ascii`, then only `.all()` should warn. if revert != is_all - && method.ident.name.as_str() == "is_ascii" + && method.ident.name == sym::is_ascii && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char @@ -102,7 +102,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && let body = cx.tcx.hir_body(body) && let Some(first_param) = body.params.first() && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind - && method.ident.name.as_str() == "chars" + && method.ident.name == sym::chars && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() && *str_ty.kind() == ty::Str { diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 6efaba525e3e..cd22583b8a25 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -9,7 +9,7 @@ use clippy_utils::ty::{ }; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, - path_to_local_id, + path_to_local_id, sym, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; @@ -20,8 +20,8 @@ use rustc_hir::{ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_span::Span; use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -339,7 +339,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if args.is_empty() - && method_name.ident.name.as_str() == "collect" + && method_name.ident.name == sym::collect && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs index fe999a3b5f8f..407f2e80aff2 100644 --- a/clippy_lints/src/methods/read_line_without_trim.rs +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,17 +1,16 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::READ_LINE_WITHOUT_TRIM; @@ -44,7 +43,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< if let Some(parent) = get_parent_expr(cx, expr) { let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind { if args.is_empty() - && segment.ident.name.as_str() == "parse" + && segment.ident.name == sym::parse && let parse_result_ty = cx.typeck_results().expr_ty(parent) && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) && let ty::Adt(_, substs) = parse_result_ty.kind() @@ -58,7 +57,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< "calling `.parse()` on a string without trimming the trailing newline character", "checking", )) - } else if segment.ident.name.as_str() == "ends_with" + } else if segment.ident.name == sym::ends_with && recv.span == expr.span && let [arg] = args && expr_is_string_literal_without_trailing_newline(arg) diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs index 3586e11f56ab..fb4ac7b3613d 100644 --- a/clippy_lints/src/methods/str_split.rs +++ b/clippy_lints/src/methods/str_split.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; +use clippy_utils::sym; use clippy_utils::visitors::is_const_evaluatable; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' && !is_const_evaluatable(cx, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind && (matches!(split_lit.node, LitKind::Char('\n')) - || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n"))) + || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _))) { let mut app = Applicability::MaybeIncorrect; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index f920f306bc1e..79ed352193fd 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; @@ -95,7 +94,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc (true, true) }, hir::ExprKind::MethodCall(segment, recv, [arg], _) => { - if segment.ident.name.as_str() == "then_some" + if segment.ident.name == sym::then_some && cx.typeck_results().expr_ty(recv).is_bool() && path_to_local_id(arg, arg_id) { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 206b0a8ae3cd..87bb8d46a1d6 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_ use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs, - return_ty, + return_ty, sym, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) - && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) - && fn_name.as_str() == "split" + && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) && let Some(receiver_snippet) = receiver.span.get_source_text(cx) && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) { @@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool { /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - (method_name.as_str() == "cloned" || method_name.as_str() == "copied") - && is_diag_trait_item(cx, method_def_id, sym::Iterator) + matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator) } /// Returns true if the named method can be used to convert the receiver to its "owned" @@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: /// Returns true if the named method is `Cow::into_owned`. fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) + method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow) } /// Returns true if the named method is `ToString::to_string` and it's called on a type that diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index ed89b3b34386..64eafc0ebccd 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,10 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_trait_method; +use clippy_utils::{is_trait_method, sym}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { @@ -79,12 +78,10 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { - if path.ident.name.as_str() == "max" { - fetch_const(cx, Some(receiver), args, MinMax::Max) - } else if path.ident.name.as_str() == "min" { - fetch_const(cx, Some(receiver), args, MinMax::Min) - } else { - None + match path.ident.name { + sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max), + sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min), + _ => None, } } else { None diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 1932d2d5f978..be7dd74fd62b 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Visitable, for_each_expr}; +use clippy_utils::{is_path_lang_item, sym}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -116,7 +116,7 @@ fn should_lint<'tcx>( if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name.as_str() == "finish_non_exhaustive" + } else if path.ident.name == sym::finish_non_exhaustive && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) { has_finish_non_exhaustive = true; diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 0e0855859628..d9f4fb271fb4 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.cx, e) - && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" + && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) { return; } diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 90b27f5dbac8..7dd96f1f037f 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::has_iter_method; +use clippy_utils::{is_trait_method, sym}; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { iter_recv.kind, ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) ) - && method_name.ident.name.as_str() == "for_each" + && method_name.ident.name == sym::for_each && is_trait_method(cx, expr, sym::Iterator) // Checks the type of the `iter` method receiver is NOT a user defined type. && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 852c3885f568..23a1622f30ff 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() - && ((path.ident.name.as_str() == "mode" + && ((path.ident.name == sym::mode && matches!( cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder) )) - || (path.ident.name.as_str() == "set_mode" + || (path.ident.name == sym::set_mode && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index 635f5678e2a6..1b8ab1bdedf8 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit && let ExprKind::Path(qpath) = &func.kind && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind - && rcv_path.ident.name.as_str() == "get" + && rcv_path.ident.name == sym::get { let fn_name = cx.tcx.item_name(def_id); let target_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index 01dc6a27c33e..ded161c8576a 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; +use clippy_utils::{parent_item_name, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>( return; } - if let Some(name) = get_item_name(cx, expr) { + if let Some(name) = parent_item_name(cx, expr) { let name = name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { return; @@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind - && method_name.ident.name.as_str() == "signum" + && method_name.ident.name == sym::signum // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) { diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index dc142b6e1577..da56a785007c 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node - && path.ident.name.as_str() == "set_readonly" + && path.ident.name == sym::set_readonly && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) { span_lint_and_then( diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 7f74a2fff9f2..d8d813f9846d 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::SpanRangeExt; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::fmt; declare_clippy_lint! { @@ -97,7 +97,7 @@ fn expr_as_ptr_offset_call<'tcx>( if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); } - if path_segment.ident.name.as_str() == "wrapping_offset" { + if path_segment.ident.name == sym::wrapping_offset { return Some((arg_0, arg_1, Method::WrappingOffset)); } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d318897443da..a41afbb800f6 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, - span_contains_cfg, span_contains_comment, + span_contains_cfg, span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; @@ -22,7 +22,6 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; declare_clippy_lint! { @@ -207,8 +206,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ is_type_diagnostic_item(cx, caller_ty, smbl) && expr_return_none_or_err(smbl, cx, if_then, caller, None) && match smbl { - sym::Option => call_sym.as_str() == "is_none", - sym::Result => call_sym.as_str() == "is_err", + sym::Option => call_sym == sym::is_none, + sym::Result => call_sym == sym::is_err, _ => false, } }, diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index d26288adb391..30a5fe4db27e 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, - span_contains_comment, + span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -248,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "extend" + && path.ident.name == sym::extend && self.is_repeat_take(extend_arg) { self.slow_expression = Some(InitializationType::Extend(expr)); @@ -260,7 +259,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "resize" + && path.ident.name == sym::resize // Check that is filled with 0 && is_integer_literal(fill_arg, 0) { @@ -282,7 +281,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool { if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind - && take_path.ident.name.as_str() == "take" + && take_path.ident.name == sym::take // Check that take is applied to `repeat(0)` && self.is_repeat_zero(recv) { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 43a3e6961051..af4d0d541f17 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if !e.span.in_external_macro(cx.sess().source_map()) && let ExprKind::MethodCall(path, receiver, ..) = &e.kind - && path.ident.name.as_str() == "as_bytes" + && path.ident.name == sym::as_bytes && let ExprKind::Lit(lit) = &receiver.kind && let LitKind::Str(lit_content, _) = &lit.node { @@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if let ExprKind::MethodCall(path, recv, [], _) = &e.kind - && path.ident.name.as_str() == "into_bytes" + && path.ident.name == sym::into_bytes && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind && matches!(path.ident.name.as_str(), "to_owned" | "to_string") && let ExprKind::Lit(lit) = &recv.kind @@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind - && path.ident.name.as_str() == "split_whitespace" + && path.ident.name == sym::split_whitespace && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 9993e6ae18b9..bb969bc802fe 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -38,11 +38,11 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind - && is_some_path.ident.name.as_str() == "is_some" + && is_some_path.ident.name == sym::is_some { let match_result = match &to_digit_expr.kind { hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { - if to_digits_path.ident.name.as_str() == "to_digit" + if to_digits_path.ident.name == sym::to_digit && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg) && *char_arg_ty.kind() == ty::Char { diff --git a/clippy_lints/src/transmute/eager_transmute.rs b/clippy_lints/src/transmute/eager_transmute.rs index 81c0a57083e8..1ccab62708b1 100644 --- a/clippy_lints/src/transmute/eager_transmute.rs +++ b/clippy_lints/src/transmute/eager_transmute.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_normalizable; -use clippy_utils::{eq_expr_value, path_to_local}; +use clippy_utils::{eq_expr_value, path_to_local, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; @@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs) }, ExprKind::MethodCall(path, receiver, [arg], _) - if path.ident.name.as_str() == "contains" + if path.ident.name == sym::contains // ... `contains` called on some kind of range && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def() && let lang_items = cx.tcx.lang_items() @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr) && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind && cx.typeck_results().expr_ty(receiver).is_bool() - && path.ident.name.as_str() == "then_some" + && path.ident.name == sym::then_some && is_local_with_projections(transmutable) && binops_with_local(cx, transmutable, receiver) && is_normalizable(cx, cx.param_env, from_ty) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 7803d5115c97..cee4a53f03cb 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { @@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec) - && path.ident.name.as_str() == "reserve" + && path.ident.name == sym::reserve } /// Returns self if the expression is `Vec::set_len()` @@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt ExprKind::MethodCall(path, self_expr, [arg], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) - && path.ident.name.as_str() == "set_len" + && path.ident.name == sym::set_len && !is_integer_literal(arg, 0) { Some((self_expr, expr.span)) diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index d0067b1a65e7..12da891a71b1 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::sym; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { - if let Some(macro_call) = root_macro_call_first_node(cx, e) { - if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) + { + ControlFlow::Break(()) } else { ControlFlow::Continue(()) } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index ce82b56eb946..ba140788bb54 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -208,7 +208,7 @@ fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id) && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind { - path.ident.name.as_str() == "as_mut" + path.ident.name == sym::as_mut } else { false } @@ -278,7 +278,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt if let ExprKind::MethodCall(path, recv, [], _) = expr.kind { if path.ident.name == sym::as_ref { (recv, Some(AsRefKind::AsRef)) - } else if path.ident.name.as_str() == "as_mut" { + } else if path.ident.name == sym::as_mut { (recv, Some(AsRefKind::AsMut)) } else { (expr, None) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 11c14c147776..f24c127c4521 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::is_in_test; use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::{is_in_test, sym}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { } fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else { + let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else { return; }; @@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma return; }; - if format_args.template.len() == 1 && last.as_str() == "\n" { + if format_args.template.len() == 1 && last == sym::LF { // print!("\n"), write!(f, "\n") diag.multipart_suggestion( @@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma } fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..] - && literal.as_str() == "\n" - { + if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] { let mut span = format_args.span; let lint = if name == "writeln" { diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index 1c42f4112f9a..b02d378619ca 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -2,6 +2,7 @@ #![allow( clippy::missing_docs_in_private_items, clippy::must_use_candidate, + clippy::symbol_as_str, rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] @@ -31,12 +32,12 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; -mod interning_literals; mod invalid_paths; mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; +mod symbols; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -45,7 +46,6 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, - interning_literals::INTERNING_LITERALS, invalid_paths::INVALID_PATHS, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -54,6 +54,8 @@ static LINTS: &[&Lint] = &[ msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, produce_ice::PRODUCE_ICE, + symbols::INTERNING_LITERALS, + symbols::SYMBOL_AS_STR, unnecessary_def_path::UNNECESSARY_DEF_PATH, unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, ]; @@ -65,7 +67,7 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); - store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); diff --git a/clippy_lints_internal/src/interning_literals.rs b/clippy_lints_internal/src/symbols.rs similarity index 52% rename from clippy_lints_internal/src/interning_literals.rs rename to clippy_lints_internal/src/symbols.rs index 6cee37442349..c64e5821916b 100644 --- a/clippy_lints_internal/src/interning_literals.rs +++ b/clippy_lints_internal/src/symbols.rs @@ -1,7 +1,7 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, paths}; +use clippy_utils::{def_path_def_ids, match_def_path, paths}; +use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,8 +11,8 @@ use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; +use rustc_span::{Span, sym}; declare_tool_lint! { /// ### What it does @@ -36,15 +36,37 @@ declare_tool_lint! { report_in_external_macro: true } +declare_tool_lint! { + /// ### What it does + /// Checks for calls to `Symbol::as_str` + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs` + /// + /// ### Example + /// ```rust,ignore + /// symbol.as_str() == "foo" + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// symbol == sym::foo + /// ``` + pub clippy::SYMBOL_AS_STR, + Warn, + "calls to `Symbol::as_str`", + report_in_external_macro: true +} + #[derive(Default)] -pub struct InterningDefinedSymbol { +pub struct Symbols { // Maps the symbol to the import path symbol_map: FxHashMap, } -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]); +impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]); -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { +impl<'tcx> LateLintPass<'tcx> for Symbols { fn check_crate(&mut self, cx: &LateContext<'_>) { let modules = [ ("kw", &paths::KW_MODULE[..]), @@ -77,7 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { if let ExprKind::Call(func, [arg]) = &expr.kind && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Str(name, _) = lit.node { span_lint_and_then( cx, @@ -85,18 +108,62 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { expr.span, "interning a string literal", |diag| { - let value = Symbol::intern(&arg).as_u32(); - let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) { - ("use the preinterned symbol", format!("{prefix}::{name}")) - } else { - ( - "add the symbol to `clippy_utils/src/sym.rs` and use it", - format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")), - ) - }; + let (message, path) = suggestion(&mut self.symbol_map, name); diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); }, ); } + + if let ExprKind::Binary(_, lhs, rhs) = expr.kind { + check_binary(cx, lhs, rhs, &mut self.symbol_map); + check_binary(cx, rhs, lhs, &mut self.symbol_map); + } + } +} + +fn check_binary( + cx: &LateContext<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + symbols: &mut FxHashMap, +) { + if let Some(removal_span) = as_str_span(cx, lhs) + && let ExprKind::Lit(lit) = rhs.kind + && let LitKind::Str(name, _) = lit.node + { + span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| { + let (message, path) = suggestion(symbols, name); + diag.multipart_suggestion_verbose( + message, + vec![(removal_span, String::new()), (rhs.span, path)], + Applicability::MachineApplicable, + ); + }); + } +} + +fn suggestion(symbols: &mut FxHashMap, name: Symbol) -> (&'static str, String) { + if let Some((prefix, name)) = symbols.get(&name.as_u32()) { + ("use the preinterned symbol", format!("{prefix}::{name}")) + } else { + ( + "add the symbol to `clippy_utils/src/sym.rs` and use it", + format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")), + ) + } +} + +/// ```ignore +/// symbol.as_str() +/// // ^^^^^^^^ +/// ``` +fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + if let ExprKind::MethodCall(_, recv, [], _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR) + { + Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi())) + } else { + None } } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index d4e66ebd8e1f..dbb993482902 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::is_expn_of; use crate::ty::is_type_diagnostic_item; +use crate::{is_expn_of, sym}; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr}; use rustc_lint::LateContext; -use rustc_span::{Span, sym, symbol}; +use rustc_span::{Span, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. @@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - return Some(VecInitKind::New); } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); - } else if name.ident.name.as_str() == "with_capacity" { + } else if name.ident.name == sym::with_capacity { let arg = args.first()?; return match ConstEvalCtxt::new(cx).eval_simple(arg) { Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 264b9b0406d0..d20e1ae6c0b5 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1412,7 +1412,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } /// Gets the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id; match cx.tcx.hir_node_by_def_id(parent_id) { Node::Item(item) => item.kind.ident().map(|ident| ident.name), @@ -2088,7 +2088,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name) + path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) } /// Returns the list of condition expressions and the list of blocks in a diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 1a30b473d106..38f077134c03 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -30,33 +30,75 @@ macro_rules! generate { } generate! { + abs, as_bytes, as_deref_mut, as_deref, as_mut, Binary, + build_hasher, + cargo_clippy: "cargo-clippy", Cargo_toml: "Cargo.toml", + cast, + chars, CLIPPY_ARGS, CLIPPY_CONF_DIR, + clone_into, cloned, + collect, contains, copied, + CRLF: "\r\n", Current, + ends_with, + exp, + extend, + finish_non_exhaustive, + finish, + flat_map, + for_each, + from_raw, + from_str_radix, get, insert, int_roundings, + into_bytes, + into_owned, IntoIter, + is_ascii, is_empty, + is_err, + is_none, is_ok, is_some, + last, + LF: "\n", LowerExp, LowerHex, + max, + min, + mode, msrv, Octal, or_default, + parse, + push, regex, + reserve, + resize, + restriction, rustfmt_skip, + set_len, + set_mode, + set_readonly, + signum, + split_whitespace, + split, Start, + take, + TBD, + then_some, + to_digit, to_owned, unused_extern_crates, unwrap_err, @@ -66,4 +108,6 @@ generate! { V4, V6, Weak, + with_capacity, + wrapping_offset, } diff --git a/tests/ui-internal/symbol_as_str.fixed b/tests/ui-internal/symbol_as_str.fixed new file mode 100644 index 000000000000..3e26732836ca --- /dev/null +++ b/tests/ui-internal/symbol_as_str.fixed @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s == sym::f32; + //~^ symbol_as_str + s == sym::proc_dash_macro; + //~^ symbol_as_str + s == kw::SelfLower; + //~^ symbol_as_str + s == sym::msrv; + //~^ symbol_as_str + s == sym::Cargo_toml; + //~^ symbol_as_str + sym::get == s; + //~^ symbol_as_str +} diff --git a/tests/ui-internal/symbol_as_str.rs b/tests/ui-internal/symbol_as_str.rs new file mode 100644 index 000000000000..334c32d18983 --- /dev/null +++ b/tests/ui-internal/symbol_as_str.rs @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s.as_str() == "f32"; + //~^ symbol_as_str + s.as_str() == "proc-macro"; + //~^ symbol_as_str + s.as_str() == "self"; + //~^ symbol_as_str + s.as_str() == "msrv"; + //~^ symbol_as_str + s.as_str() == "Cargo.toml"; + //~^ symbol_as_str + "get" == s.as_str(); + //~^ symbol_as_str +} diff --git a/tests/ui-internal/symbol_as_str.stderr b/tests/ui-internal/symbol_as_str.stderr new file mode 100644 index 000000000000..39f81f3833c4 --- /dev/null +++ b/tests/ui-internal/symbol_as_str.stderr @@ -0,0 +1,76 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:9:5 + | +LL | s.as_str() == "f32"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: use the preinterned symbol + | +LL - s.as_str() == "f32"; +LL + s == sym::f32; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:11:5 + | +LL | s.as_str() == "proc-macro"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "proc-macro"; +LL + s == sym::proc_dash_macro; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:13:5 + | +LL | s.as_str() == "self"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "self"; +LL + s == kw::SelfLower; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:15:5 + | +LL | s.as_str() == "msrv"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "msrv"; +LL + s == sym::msrv; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:17:5 + | +LL | s.as_str() == "Cargo.toml"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "Cargo.toml"; +LL + s == sym::Cargo_toml; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:19:14 + | +LL | "get" == s.as_str(); + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - "get" == s.as_str(); +LL + sym::get == s; + | + +error: aborting due to 6 previous errors + diff --git a/tests/ui-internal/symbol_as_str_unfixable.rs b/tests/ui-internal/symbol_as_str_unfixable.rs new file mode 100644 index 000000000000..635f28007e9a --- /dev/null +++ b/tests/ui-internal/symbol_as_str_unfixable.rs @@ -0,0 +1,15 @@ +//@no-rustfix: paths that don't exist yet +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::Symbol; + +fn f(s: Symbol) { + s.as_str() == "xyz123"; + //~^ symbol_as_str + s.as_str() == "with-dash"; + //~^ symbol_as_str + s.as_str() == "with.dot"; + //~^ symbol_as_str +} diff --git a/tests/ui-internal/symbol_as_str_unfixable.stderr b/tests/ui-internal/symbol_as_str_unfixable.stderr new file mode 100644 index 000000000000..5349983ca519 --- /dev/null +++ b/tests/ui-internal/symbol_as_str_unfixable.stderr @@ -0,0 +1,40 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:9:5 + | +LL | s.as_str() == "xyz123"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "xyz123"; +LL + s == sym::xyz123; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:11:5 + | +LL | s.as_str() == "with-dash"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with-dash"; +LL + s == sym::with_dash; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:13:5 + | +LL | s.as_str() == "with.dot"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with.dot"; +LL + s == sym::with_dot; + | + +error: aborting due to 3 previous errors + From 593775a83b80bed7f749a38adea6afa420884434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bernier?= Date: Fri, 18 Apr 2025 00:27:08 -0400 Subject: [PATCH 036/302] Add PGO support to install Enable PGO optimizations when installing rust-analyzer with the --pgo flag. This mirrors functionality already available in dist command, allowing developers to create optimized local builds. Example: cargo xtask install --server --pgo clap-rs/clap PGO code has been extracted to a dedicated module for reuse. --- src/tools/rust-analyzer/xtask/src/dist.rs | 109 ++----------------- src/tools/rust-analyzer/xtask/src/flags.rs | 52 +++++---- src/tools/rust-analyzer/xtask/src/install.rs | 28 ++++- src/tools/rust-analyzer/xtask/src/main.rs | 1 + src/tools/rust-analyzer/xtask/src/pgo.rs | 105 ++++++++++++++++++ src/tools/rust-analyzer/xtask/src/util.rs | 12 ++ 6 files changed, 175 insertions(+), 132 deletions(-) create mode 100644 src/tools/rust-analyzer/xtask/src/pgo.rs diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs index b3d6f06b073f..dbfecdbe1121 100644 --- a/src/tools/rust-analyzer/xtask/src/dist.rs +++ b/src/tools/rust-analyzer/xtask/src/dist.rs @@ -1,9 +1,6 @@ use anyhow::Context; use flate2::{Compression, write::GzEncoder}; -use std::env::consts::EXE_EXTENSION; -use std::ffi::OsStr; use std::{ - env, fs::File, io::{self, BufWriter}, path::{Path, PathBuf}, @@ -12,11 +9,11 @@ use time::OffsetDateTime; use xshell::{Cmd, Shell, cmd}; use zip::{DateTime, ZipWriter, write::SimpleFileOptions}; -use crate::flags::PgoTrainingCrate; use crate::{ date_iso, - flags::{self, Malloc}, + flags::{self, Malloc, PgoTrainingCrate}, project_root, + util::detect_target, }; const VERSION_STABLE: &str = "0.3"; @@ -28,7 +25,7 @@ impl flags::Dist { let stable = sh.var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release"; let project_root = project_root(); - let target = Target::get(&project_root); + let target = Target::get(&project_root, sh); let allocator = self.allocator(); let dist = project_root.join("dist"); sh.remove_path(&dist)?; @@ -113,9 +110,9 @@ fn dist_server( let command = if linux_target && zig { "zigbuild" } else { "build" }; let pgo_profile = if let Some(train_crate) = pgo { - Some(gather_pgo_profile( + Some(crate::pgo::gather_pgo_profile( sh, - build_command(sh, command, &target_name, features), + crate::pgo::build_command(sh, command, &target_name, features), &target_name, train_crate, )?) @@ -151,85 +148,6 @@ fn build_command<'a>( ) } -/// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented -/// Rust Analyzer on itself to gather a PGO profile. -fn gather_pgo_profile<'a>( - sh: &'a Shell, - ra_build_cmd: Cmd<'a>, - target: &str, - train_crate: PgoTrainingCrate, -) -> anyhow::Result { - let pgo_dir = std::path::absolute("rust-analyzer-pgo")?; - // Clear out any stale profiles - if pgo_dir.is_dir() { - std::fs::remove_dir_all(&pgo_dir)?; - } - std::fs::create_dir_all(&pgo_dir)?; - - // Figure out a path to `llvm-profdata` - let target_libdir = cmd!(sh, "rustc --print=target-libdir") - .read() - .context("cannot resolve target-libdir from rustc")?; - let target_bindir = PathBuf::from(target_libdir).parent().unwrap().join("bin"); - let llvm_profdata = target_bindir.join("llvm-profdata").with_extension(EXE_EXTENSION); - - // Build RA with PGO instrumentation - let cmd_gather = - ra_build_cmd.env("RUSTFLAGS", format!("-Cprofile-generate={}", pgo_dir.to_str().unwrap())); - cmd_gather.run().context("cannot build rust-analyzer with PGO instrumentation")?; - - let (train_path, label) = match &train_crate { - PgoTrainingCrate::RustAnalyzer => (PathBuf::from("."), "itself"), - PgoTrainingCrate::GitHub(repo) => { - (download_crate_for_training(sh, &pgo_dir, repo)?, repo.as_str()) - } - }; - - // Run RA either on itself or on a downloaded crate - eprintln!("Training RA on {label}..."); - cmd!( - sh, - "target/{target}/release/rust-analyzer analysis-stats -q --run-all-ide-things {train_path}" - ) - .run() - .context("cannot generate PGO profiles")?; - - // Merge profiles into a single file - let merged_profile = pgo_dir.join("merged.profdata"); - let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| { - let entry = entry.ok()?; - if entry.path().extension() == Some(OsStr::new("profraw")) { - Some(entry.path().to_str().unwrap().to_owned()) - } else { - None - } - }); - cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context( - "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?", - )?; - - Ok(merged_profile) -} - -/// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it. -fn download_crate_for_training(sh: &Shell, pgo_dir: &Path, repo: &str) -> anyhow::Result { - let mut it = repo.splitn(2, '@'); - let repo = it.next().unwrap(); - let revision = it.next(); - - // FIXME: switch to `--revision` here around 2035 or so - let revision = - if let Some(revision) = revision { &["--branch", revision] as &[&str] } else { &[] }; - - let normalized_path = repo.replace("/", "-"); - let target_path = pgo_dir.join(normalized_path); - cmd!(sh, "git clone --depth 1 https://github.com/{repo} {revision...} {target_path}") - .run() - .with_context(|| "cannot download PGO training crate from {repo}")?; - - Ok(target_path) -} - fn gzip(src_path: &Path, dest_path: &Path) -> anyhow::Result<()> { let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); let mut input = io::BufReader::new(File::open(src_path)?); @@ -283,21 +201,8 @@ struct Target { } impl Target { - fn get(project_root: &Path) -> Self { - let name = match env::var("RA_TARGET") { - Ok(target) => target, - _ => { - if cfg!(target_os = "linux") { - "x86_64-unknown-linux-gnu".to_owned() - } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc".to_owned() - } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin".to_owned() - } else { - panic!("Unsupported OS, maybe try setting RA_TARGET") - } - } - }; + fn get(project_root: &Path, sh: &Shell) -> Self { + let name = detect_target(sh); let (name, libc_suffix) = match name.split_once('.') { Some((l, r)) => (l.to_owned(), Some(r.to_owned())), None => (name, None), diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs index 700806d178c3..2fd471b35c7e 100644 --- a/src/tools/rust-analyzer/xtask/src/flags.rs +++ b/src/tools/rust-analyzer/xtask/src/flags.rs @@ -4,6 +4,25 @@ use std::{fmt, str::FromStr}; use crate::install::{ClientOpt, ProcMacroServerOpt, ServerOpt}; +#[derive(Debug, Clone)] +pub enum PgoTrainingCrate { + // Use RA's own sources for PGO training + RustAnalyzer, + // Download a Rust crate from `https://github.com/{0}` and use it for PGO training. + GitHub(String), +} + +impl FromStr for PgoTrainingCrate { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "rust-analyzer" => Ok(Self::RustAnalyzer), + url => Ok(Self::GitHub(url.to_owned())), + } + } +} + xflags::xflags! { src "./src/flags.rs" @@ -29,6 +48,9 @@ xflags::xflags! { /// build in release with debug info set to 2. optional --dev-rel + + /// Apply PGO optimizations + optional --pgo pgo: PgoTrainingCrate } cmd fuzz-tests {} @@ -109,18 +131,16 @@ pub enum XtaskCmd { Tidy(Tidy), } -#[derive(Debug)] -pub struct Tidy {} - #[derive(Debug)] pub struct Install { pub client: bool, pub code_bin: Option, pub server: bool, - pub proc_macro_server: bool, pub mimalloc: bool, pub jemalloc: bool, + pub proc_macro_server: bool, pub dev_rel: bool, + pub pgo: Option, } #[derive(Debug)] @@ -143,25 +163,6 @@ pub struct RustcPush { pub branch: Option, } -#[derive(Debug)] -pub enum PgoTrainingCrate { - // Use RA's own sources for PGO training - RustAnalyzer, - // Download a Rust crate from `https://github.com/{0}` and use it for PGO training. - GitHub(String), -} - -impl FromStr for PgoTrainingCrate { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "rust-analyzer" => Ok(Self::RustAnalyzer), - url => Ok(Self::GitHub(url.to_owned())), - } - } -} - #[derive(Debug)] pub struct Dist { pub mimalloc: bool, @@ -195,6 +196,9 @@ pub struct Codegen { pub check: bool, } +#[derive(Debug)] +pub struct Tidy; + impl Xtask { #[allow(dead_code)] pub fn from_env_or_exit() -> Self { @@ -324,7 +328,7 @@ impl Install { } else { Malloc::System }; - Some(ServerOpt { malloc, dev_rel: self.dev_rel }) + Some(ServerOpt { malloc, dev_rel: self.dev_rel, pgo: self.pgo.clone() }) } pub(crate) fn proc_macro_server(&self) -> Option { if !self.proc_macro_server { diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs index 4e2093f0691b..f0cc445dfa23 100644 --- a/src/tools/rust-analyzer/xtask/src/install.rs +++ b/src/tools/rust-analyzer/xtask/src/install.rs @@ -5,7 +5,10 @@ use std::{env, path::PathBuf, str}; use anyhow::{Context, bail, format_err}; use xshell::{Shell, cmd}; -use crate::flags::{self, Malloc}; +use crate::{ + flags::{self, Malloc, PgoTrainingCrate}, + util::detect_target, +}; impl flags::Install { pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> { @@ -35,6 +38,7 @@ const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium pub(crate) struct ServerOpt { pub(crate) malloc: Malloc, pub(crate) dev_rel: bool, + pub(crate) pgo: Option, } pub(crate) struct ProcMacroServerOpt { @@ -135,21 +139,33 @@ fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> { let features = opts.malloc.to_features(); let profile = if opts.dev_rel { "dev-rel" } else { "release" }; - let cmd = cmd!( + let mut install_cmd = cmd!( sh, "cargo install --path crates/rust-analyzer --profile={profile} --locked --force --features force-always-assert {features...}" ); - cmd.run()?; + + if let Some(train_crate) = opts.pgo { + let build_cmd = cmd!( + sh, + "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --profile={profile} --locked --features force-always-assert {features...}" + ); + + let target = detect_target(sh); + let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?; + install_cmd = crate::pgo::apply_pgo_to_cmd(install_cmd, &profile); + } + + install_cmd.run()?; Ok(()) } fn install_proc_macro_server(sh: &Shell, opts: ProcMacroServerOpt) -> anyhow::Result<()> { let profile = if opts.dev_rel { "dev-rel" } else { "release" }; - let cmd = cmd!( + cmd!( sh, "cargo +nightly install --path crates/proc-macro-srv-cli --profile={profile} --locked --force --features sysroot-abi" - ); - cmd.run()?; + ).run()?; + Ok(()) } diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs index 52ea896c734d..aaa8d0e1d4d4 100644 --- a/src/tools/rust-analyzer/xtask/src/main.rs +++ b/src/tools/rust-analyzer/xtask/src/main.rs @@ -22,6 +22,7 @@ mod codegen; mod dist; mod install; mod metrics; +mod pgo; mod publish; mod release; mod tidy; diff --git a/src/tools/rust-analyzer/xtask/src/pgo.rs b/src/tools/rust-analyzer/xtask/src/pgo.rs new file mode 100644 index 000000000000..7f7b3311d962 --- /dev/null +++ b/src/tools/rust-analyzer/xtask/src/pgo.rs @@ -0,0 +1,105 @@ +//! PGO (Profile-Guided Optimization) utilities. + +use anyhow::Context; +use std::env::consts::EXE_EXTENSION; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use xshell::{Cmd, Shell, cmd}; + +use crate::flags::PgoTrainingCrate; + +/// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented +/// Rust Analyzer on itself to gather a PGO profile. +pub(crate) fn gather_pgo_profile<'a>( + sh: &'a Shell, + ra_build_cmd: Cmd<'a>, + target: &str, + train_crate: PgoTrainingCrate, +) -> anyhow::Result { + let pgo_dir = std::path::absolute("rust-analyzer-pgo")?; + // Clear out any stale profiles + if pgo_dir.is_dir() { + std::fs::remove_dir_all(&pgo_dir)?; + } + std::fs::create_dir_all(&pgo_dir)?; + + // Figure out a path to `llvm-profdata` + let target_libdir = cmd!(sh, "rustc --print=target-libdir") + .read() + .context("cannot resolve target-libdir from rustc")?; + let target_bindir = PathBuf::from(target_libdir).parent().unwrap().join("bin"); + let llvm_profdata = target_bindir.join("llvm-profdata").with_extension(EXE_EXTENSION); + + // Build RA with PGO instrumentation + let cmd_gather = + ra_build_cmd.env("RUSTFLAGS", format!("-Cprofile-generate={}", pgo_dir.to_str().unwrap())); + cmd_gather.run().context("cannot build rust-analyzer with PGO instrumentation")?; + + let (train_path, label) = match &train_crate { + PgoTrainingCrate::RustAnalyzer => (PathBuf::from("."), "itself"), + PgoTrainingCrate::GitHub(repo) => { + (download_crate_for_training(sh, &pgo_dir, repo)?, repo.as_str()) + } + }; + + // Run RA either on itself or on a downloaded crate + eprintln!("Training RA on {label}..."); + cmd!( + sh, + "target/{target}/release/rust-analyzer analysis-stats -q --run-all-ide-things {train_path}" + ) + .run() + .context("cannot generate PGO profiles")?; + + // Merge profiles into a single file + let merged_profile = pgo_dir.join("merged.profdata"); + let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| { + let entry = entry.ok()?; + if entry.path().extension() == Some(OsStr::new("profraw")) { + Some(entry.path().to_str().unwrap().to_owned()) + } else { + None + } + }); + cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context( + "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?", + )?; + + Ok(merged_profile) +} + +/// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it. +fn download_crate_for_training(sh: &Shell, pgo_dir: &Path, repo: &str) -> anyhow::Result { + let mut it = repo.splitn(2, '@'); + let repo = it.next().unwrap(); + let revision = it.next(); + + // FIXME: switch to `--revision` here around 2035 or so + let revision = + if let Some(revision) = revision { &["--branch", revision] as &[&str] } else { &[] }; + + let normalized_path = repo.replace("/", "-"); + let target_path = pgo_dir.join(normalized_path); + cmd!(sh, "git clone --depth 1 https://github.com/{repo} {revision...} {target_path}") + .run() + .with_context(|| "cannot download PGO training crate from {repo}")?; + + Ok(target_path) +} + +/// Helper function to create a build command for rust-analyzer +pub(crate) fn build_command<'a>( + sh: &'a Shell, + command: &str, + target_name: &str, + features: &[&str], +) -> Cmd<'a> { + cmd!( + sh, + "cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release" + ) +} + +pub(crate) fn apply_pgo_to_cmd<'a>(cmd: Cmd<'a>, profile_path: &Path) -> Cmd<'a> { + cmd.env("RUSTFLAGS", format!("-Cprofile-use={}", profile_path.to_str().unwrap())) +} diff --git a/src/tools/rust-analyzer/xtask/src/util.rs b/src/tools/rust-analyzer/xtask/src/util.rs index 39f52938c8c6..a740ad6afdcb 100644 --- a/src/tools/rust-analyzer/xtask/src/util.rs +++ b/src/tools/rust-analyzer/xtask/src/util.rs @@ -1,5 +1,7 @@ use std::path::{Path, PathBuf}; +use xshell::{Shell, cmd}; + pub(crate) fn list_rust_files(dir: &Path) -> Vec { let mut res = list_files(dir); res.retain(|it| { @@ -29,3 +31,13 @@ pub(crate) fn list_files(dir: &Path) -> Vec { } res } + +pub(crate) fn detect_target(sh: &Shell) -> String { + match std::env::var("RA_TARGET") { + Ok(target) => target, + _ => match cmd!(sh, "rustc --print=host-tuple").read() { + Ok(target) => target, + Err(e) => panic!("Failed to detect target: {}\nPlease set RA_TARGET explicitly", e), + }, + } +} From 44232a67c320c8df31e2b82ae15d2ec7c83ec759 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 25 Apr 2025 17:43:12 +0800 Subject: [PATCH 037/302] Add ui test parser/issues/invalid-parse-format-issue-139104.rs Signed-off-by: xizheyin --- .../invalid-parse-format-issue-139104.rs | 8 +++ .../invalid-parse-format-issue-139104.stderr | 66 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/ui/parser/issues/invalid-parse-format-issue-139104.rs create mode 100644 tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs new file mode 100644 index 000000000000..40af62623560 --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -0,0 +1,8 @@ +fn main() { + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` +} diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr new file mode 100644 index 000000000000..d0a8d0998a48 --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -0,0 +1,66 @@ +error: invalid format string: tuple index access isn't supported + --> $DIR/invalid-parse-format-issue-139104.rs:2:16 + | +LL | println!("{foo:_1.4}", foo = 3.14); + | ^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL - println!("{foo:_1.4}", foo = 3.14); +LL + println!("{0}", foo:_1.4, foo = 3.14); + | + +error: invalid format string: tuple index access isn't supported + --> $DIR/invalid-parse-format-issue-139104.rs:3:16 + | +LL | println!("{foo:1.4_1.4}", foo = 3.14); + | ^^^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL - println!("{foo:1.4_1.4}", foo = 3.14); +LL + println!("{0}", foo:1.4_1.4, foo = 3.14); + | + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:4:23 + | +LL | println!("xxx{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:5:22 + | +LL | println!("{foo:_1.4", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:6:23 + | +LL | println!("xxx{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `0` + --> $DIR/invalid-parse-format-issue-139104.rs:7:21 + | +LL | println!("xxx{ 0", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: aborting due to 6 previous errors + From 64867c68f4eb537215e65268903803f44f1fe6b6 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 25 Apr 2025 17:53:40 +0800 Subject: [PATCH 038/302] Check if format argument is identifier to avoid error err-emit Signed-off-by: xizheyin --- compiler/rustc_parse_format/src/lib.rs | 135 ++++++++++++------ .../invalid-parse-format-issue-139104.rs | 10 +- .../invalid-parse-format-issue-139104.stderr | 52 ++----- 3 files changed, 109 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index c59e6cb5c33f..c356a97a55a2 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -100,6 +100,30 @@ pub struct Argument<'a> { pub format: FormatSpec<'a>, } +impl<'a> Argument<'a> { + pub fn is_identifier(&self) -> bool { + matches!(self.position, Position::ArgumentNamed(_)) + && matches!( + self.format, + FormatSpec { + fill: None, + fill_span: None, + align: AlignUnknown, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, + precision: CountImplied, + precision_span: None, + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }, + ) + } +} + /// Specification for the formatting of an argument in the format string. #[derive(Copy, Clone, Debug, PartialEq)] pub struct FormatSpec<'a> { @@ -894,52 +918,73 @@ impl<'a> Parser<'a> { } fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); - // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any - // deeper nesting, or another type of expression, like method calls, are not supported - if !self.consume('}') { - return; - } - if let ArgumentNamed(_) = arg.position { - match field.position { - ArgumentNamed(_) => { - self.errors.insert( - 0, - ParseError { - description: "field access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - ArgumentIs(_) => { - self.errors.insert( - 0, - ParseError { - description: "tuple index access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - _ => {} - }; + // If the argument is an identifier, it may be a field access. + if arg.is_identifier() { + if let Some(end) = self.consume_pos('.') { + let byte_pos = self.to_span_index(end); + let start = InnerOffset(byte_pos.0 + 1); + let field = self.argument(start); + // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any + // deeper nesting, or another type of expression, like method calls, are not supported + if !self.consume('}') { + return; + } + if let ArgumentNamed(_) = arg.position { + match field.position { + ArgumentNamed(_) => { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + ArgumentIs(_) => { + self.errors.insert( + 0, + ParseError { + description: "tuple index access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + _ => {} + }; + } } + } else if matches!(arg.position, ArgumentNamed(_) | ArgumentIs(_)) { + let arg_name = match arg.position { + ArgumentNamed(arg_name) => &format!("`{arg_name}`"), + ArgumentIs(arg_index) => &format!("at index `{arg_index}`"), + _ => unreachable!(), + }; + + self.errors.insert( + 0, + ParseError { + description: format!("invalid format string for argument {}", arg_name), + note: None, + label: format!("invalid format specifier for this argument"), + span: InnerSpan::new(arg.position_span.start, arg.position_span.end), + secondary_label: None, + suggestion: Suggestion::None, + }, + ); } } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs index 40af62623560..0809235bb6dd 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -1,8 +1,8 @@ fn main() { - println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported - println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` - println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("xxx{0:_1.4}", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr index d0a8d0998a48..ceae8d051e5e 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -1,56 +1,32 @@ -error: invalid format string: tuple index access isn't supported +error: invalid format string: invalid format string for argument `foo` --> $DIR/invalid-parse-format-issue-139104.rs:2:16 | LL | println!("{foo:_1.4}", foo = 3.14); - | ^^^^^^^^ not supported in format string - | -help: consider using a positional formatting argument instead - | -LL - println!("{foo:_1.4}", foo = 3.14); -LL + println!("{0}", foo:_1.4, foo = 3.14); - | + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: tuple index access isn't supported +error: invalid format string: invalid format string for argument `foo` --> $DIR/invalid-parse-format-issue-139104.rs:3:16 | LL | println!("{foo:1.4_1.4}", foo = 3.14); - | ^^^^^^^^^^^ not supported in format string - | -help: consider using a positional formatting argument instead - | -LL - println!("{foo:1.4_1.4}", foo = 3.14); -LL + println!("{0}", foo:1.4_1.4, foo = 3.14); - | + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:4:23 +error: invalid format string: invalid format string for argument at index `0` + --> $DIR/invalid-parse-format-issue-139104.rs:4:19 | -LL | println!("xxx{0:_1.4", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` +LL | println!("xxx{0:_1.4}", 1.11); + | ^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:5:22 +error: invalid format string: invalid format string for argument `foo` + --> $DIR/invalid-parse-format-issue-139104.rs:5:16 | LL | println!("{foo:_1.4", foo = 3.14); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:6:23 +error: invalid format string: invalid format string for argument at index `0` + --> $DIR/invalid-parse-format-issue-139104.rs:6:19 | LL | println!("xxx{0:_1.4", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` + | ^ invalid format specifier for this argument in format string error: invalid format string: expected `}`, found `0` --> $DIR/invalid-parse-format-issue-139104.rs:7:21 From 148c9a198170f79de992ba6d56a859c99c64685c Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sun, 20 Apr 2025 10:51:19 +0900 Subject: [PATCH 039/302] Fix error message for static references or mutable references --- tests/ui/checked_unwrap/simple_conditionals.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index bdac1e42309d..ad3c420270c1 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -236,7 +236,7 @@ LL | if result.is_ok() { LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: creating a shared reference to mutable static is discouraged +error: creating a shared reference to mutable static --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | LL | if X.is_some() { From 163fb854a2346a26ade9e09ec13ef10a3145ee25 Mon Sep 17 00:00:00 2001 From: sayantn Date: Fri, 11 Apr 2025 19:57:05 +0530 Subject: [PATCH 040/302] Add the `avx10.1` and `avx10.2` target features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 3 +++ compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 20 +++++++++++++++++++ tests/ui/check-cfg/and-more-diagnostic.rs | 2 +- tests/ui/check-cfg/target_feature.stderr | 2 ++ .../feature-gate-avx10_target_feature.rs | 6 ++++++ .../feature-gate-avx10_target_feature.stderr | 13 ++++++++++++ 8 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/ui/feature-gates/feature-gate-avx10_target_feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 36e35f81392b..8afd34829e31 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -294,6 +294,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, + ("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")), + ("x86", "avx10.2") if get_version().0 < 20 => None, + ("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")), (_, s) => Some(LLVMFeature::new(s)), } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index cbc121e3632a..490641b9884a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -389,6 +389,8 @@ declare_features! ( (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows `async` trait bound modifier. (unstable, async_trait_bounds, "1.85.0", Some(62290)), + /// Allows using Intel AVX10 target features and intrinsics + (unstable, avx10_target_feature, "CURRENT_RUSTC_VERSION", Some(138843)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 32a5aff0cb32..4483cf14c619 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -540,6 +540,7 @@ symbols! { autodiff, automatically_derived, avx, + avx10_target_feature, avx512_target_feature, avx512bw, avx512f, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..6fa8af2e0fff 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -391,6 +391,26 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("avx", Stable, &["sse4.2"]), + ( + "avx10.1", + Unstable(sym::avx10_target_feature), + &[ + "avx512bf16", + "avx512bitalg", + "avx512bw", + "avx512cd", + "avx512dq", + "avx512f", + "avx512fp16", + "avx512ifma", + "avx512vbmi", + "avx512vbmi2", + "avx512vl", + "avx512vnni", + "avx512vpopcntdq", + ], + ), + ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), ("avx2", Stable, &["avx"]), ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]), diff --git a/tests/ui/check-cfg/and-more-diagnostic.rs b/tests/ui/check-cfg/and-more-diagnostic.rs index 977f55e8a6d1..5422829c5b31 100644 --- a/tests/ui/check-cfg/and-more-diagnostic.rs +++ b/tests/ui/check-cfg/and-more-diagnostic.rs @@ -5,7 +5,7 @@ //@ no-auto-check-cfg //@ compile-flags: --check-cfg=cfg() //@ normalize-stderr: "and \d+ more" -> "and X more" -//@ normalize-stderr: "`[a-zA-Z0-9_-]+`" -> "`xxx`" +//@ normalize-stderr: "`[a-zA-Z0-9_\.-]+`" -> "`xxx`" fn main() { cfg!(target_feature = "zebra"); diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 4f7b8345e86a..9d072d27255f 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -29,6 +29,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `amx-transpose` `atomics` `avx` +`avx10.1` +`avx10.2` `avx2` `avx512bf16` `avx512bitalg` diff --git a/tests/ui/feature-gates/feature-gate-avx10_target_feature.rs b/tests/ui/feature-gates/feature-gate-avx10_target_feature.rs new file mode 100644 index 000000000000..8557e67d1f41 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-avx10_target_feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "avx10.1")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr b/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr new file mode 100644 index 000000000000..e45ea3524ca7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `avx10.1` is currently unstable + --> $DIR/feature-gate-avx10_target_feature.rs:2:18 + | +LL | #[target_feature(enable = "avx10.1")] + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138843 for more information + = help: add `#![feature(avx10_target_feature)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 3f72ffa80e93e22e3834eed50e3c7158e12281e3 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Thu, 17 Apr 2025 20:30:34 +0800 Subject: [PATCH 041/302] fix: `unnecessary_cast` suggests extra brackets when in macro --- clippy_lints/src/casts/unnecessary_cast.rs | 55 +++++++++++++++++----- tests/ui/unnecessary_cast.fixed | 16 ++++++- tests/ui/unnecessary_cast.rs | 14 ++++++ tests/ui/unnecessary_cast.stderr | 22 ++++++++- 4 files changed, 91 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index ae994e94a32b..8e8c55cf3832 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -8,7 +8,9 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; +use rustc_span::{Symbol, sym}; use std::ops::ControlFlow; use super::UNNECESSARY_CAST; @@ -142,6 +144,33 @@ pub(super) fn check<'tcx>( } if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) { + enum MaybeParenOrBlock { + Paren, + Block, + Nothing, + } + + fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::AddrOf(..)) + || cx + .typeck_results() + .expr_adjustments(expr) + .first() + .is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_))) + } + + fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + const ALLOWED_MACROS: &[Symbol] = &[ + sym::format_args_macro, + sym::assert_eq_macro, + sym::debug_assert_eq_macro, + sym::assert_ne_macro, + sym::debug_assert_ne_macro, + ]; + matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if + cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym))) + } + if let Some(id) = path_to_local(cast_expr) && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span) { @@ -150,15 +179,15 @@ pub(super) fn check<'tcx>( return false; } - // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof - // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us - // changing the precedence of operators if the cast expression is followed by an operation - // with higher precedence than the unary operator (`(*x as T).foo()` would become - // `*x.foo()`, which changes what the `*` applies on). - // The same is true if the expression encompassing the cast expression is a unary - // expression or an addressof expression. - let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) - || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + // Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates + // a reference to the temporary while the latter creates a reference to the original value. + let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) { + Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => { + MaybeParenOrBlock::Block + }, + Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren, + _ => MaybeParenOrBlock::Nothing, + }; span_lint_and_sugg( cx, @@ -166,10 +195,10 @@ pub(super) fn check<'tcx>( expr.span, format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", - if needs_block { - format!("{{ {cast_str} }}") - } else { - cast_str + match surrounding { + MaybeParenOrBlock::Paren => format!("({cast_str})"), + MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"), + MaybeParenOrBlock::Nothing => cast_str, }, Applicability::MachineApplicable, ); diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index ba167e79a308..91ff4b9ee771 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -266,7 +266,21 @@ mod fixable { // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as // `*x.pow(2)` which tries to dereference the return value rather than `x`. fn issue_11968(x: &usize) -> usize { - { *x }.pow(2) + (*x).pow(2) + //~^ unnecessary_cast + } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x); + //~^ unnecessary_cast + + let _ = (5i32 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64; //~^ unnecessary_cast } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 0f90a8b05965..5444a914db16 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -269,4 +269,18 @@ mod fixable { (*x as usize).pow(2) //~^ unnecessary_cast } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x as usize); + //~^ unnecessary_cast + + let _ = (5i32 as i64 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64 as i64; + //~^ unnecessary_cast + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index c83770c1a299..3e3c5eb81c10 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`) --> tests/ui/unnecessary_cast.rs:269:9 | LL | (*x as usize).pow(2) - | ^^^^^^^^^^^^^ help: try: `{ *x }` + | ^^^^^^^^^^^^^ help: try: `(*x)` -error: aborting due to 41 previous errors +error: casting to the same type is unnecessary (`usize` -> `usize`) + --> tests/ui/unnecessary_cast.rs:277:31 + | +LL | assert_eq!(vec.len(), x as usize); + | ^^^^^^^^^^ help: try: `x` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:280:17 + | +LL | let _ = (5i32 as i64 as i64).abs(); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:283:17 + | +LL | let _ = 5i32 as i64 as i64; + | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` + +error: aborting due to 44 previous errors From ad6934791280f521ca4176b5a2d7ee5609ec4b80 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 30 Mar 2025 15:05:59 +0800 Subject: [PATCH 042/302] fix: `equatable_if_let` suggests wrongly when involving reference --- clippy_lints/src/equatable_if_let.rs | 34 +++++++++++++++++++++++++- tests/ui/equatable_if_let.fixed | 36 ++++++++++++++++++++++++++++ tests/ui/equatable_if_let.rs | 36 ++++++++++++++++++++++++++++ tests/ui/equatable_if_let.stderr | 20 +++++++++++++++- 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 3afb687040f4..72f5eaf8a4bc 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T } } +/// Check if the pattern has any type mismatch that would prevent it from being used in an equality +/// check. This can happen if the expr has a reference type and the corresponding pattern is a +/// literal. +fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + let mut result = false; + pat.walk(|p| { + if result { + return false; + } + + if p.span.in_external_macro(cx.sess().source_map()) { + return true; + } + + let adjust_pat = match p.kind { + PatKind::Or([p, ..]) => p, + _ => p, + }; + + if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) + && adjustments.first().is_some_and(|first| first.source.is_ref()) + { + result = true; + return false; + } + + true + }); + + result +} + impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind @@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) { + if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { let pat_str = match let_expr.pat.kind { PatKind::Struct(..) => format!( "({})", diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 166b1387ba26..ce8b67f9ca7b 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if matches!(cs.iter().next(), Some('i')) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if matches!(cs.iter().next(), Some(1)) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if matches!(get_enum(), Some(MyEnum::B)) { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 09c2483ae6d4..ff09533f2651 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if let Some('i') = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if let Some(1) = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if let Some(MyEnum::B) = get_enum() { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index 81e0e15a5c74..dd1832ad68b2 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality LL | if let inline!("abc") = "abc" { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` -error: aborting due to 14 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:109:12 + | +LL | if let Some('i') = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:117:12 + | +LL | if let Some(1) = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:135:12 + | +LL | if let Some(MyEnum::B) = get_enum() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` + +error: aborting due to 17 previous errors From 2b701e00f12e41ed2d9a75b6fd14fb20640d159d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 26 Apr 2025 21:10:43 +0300 Subject: [PATCH 043/302] Escape raw names in labels properly --- .../rust-analyzer/crates/hir-expand/src/name.rs | 15 ++++++++++----- .../ide-completion/src/tests/expression.rs | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index d43ef38f291d..37290edae4ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -191,7 +191,7 @@ impl Name { // FIXME: Remove this in favor of `display`, see fixme on `as_str` #[doc(hidden)] pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ { - Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) } + Display { name: self, edition } } pub fn symbol(&self) -> &Symbol { @@ -201,15 +201,20 @@ impl Name { struct Display<'a> { name: &'a Name, - needs_escaping: bool, + edition: Edition, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.needs_escaping { - write!(f, "r#")?; + let mut symbol = self.name.symbol.as_str(); + if let Some(s) = symbol.strip_prefix('\'') { + f.write_str("'")?; + symbol = s; } - fmt::Display::fmt(self.name.symbol.as_str(), f) + if is_raw_identifier(symbol, self.edition) { + f.write_str("r#")?; + } + f.write_str(symbol) } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b30ac43bf8fb..27d6bc7b14f2 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2110,3 +2110,19 @@ fn foo() { "#]], ); } + +#[test] +fn escaped_label() { + check( + r#" +fn main() { + 'r#break: { + break '$0; + } +} + "#, + expect![[r#" + lb 'r#break + "#]], + ); +} From 8118676a08fa00ce5a8ffac6427c95c4df9a2e9b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 26 Apr 2025 21:20:43 +0300 Subject: [PATCH 044/302] Don't escape `'static` As it is a valid lifetime without escaping. It does need to be escaped as a label, but we have no way to distinguish that. --- src/tools/rust-analyzer/crates/hir-expand/src/name.rs | 8 ++++++++ .../crates/ide-completion/src/completions/lifetime.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 37290edae4ec..217d991d110d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -207,6 +207,14 @@ struct Display<'a> { impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut symbol = self.name.symbol.as_str(); + + if symbol == "'static" { + // FIXME: '`static` can also be a label, and there it does need escaping. + // But knowing where it is will require adding a parameter to `display()`, + // and that is an infectious change. + return f.write_str(symbol); + } + if let Some(s) = symbol.strip_prefix('\'') { f.write_str("'")?; symbol = s; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index b02f079b7213..8902cd09cec0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -116,13 +116,13 @@ fn foo<'lifetime>(foo: &'a$0) {} check( r#" struct Foo; -impl<'impl> Foo { +impl<'r#impl> Foo { fn foo<'func>(&'a$0 self) {} } "#, expect![[r#" lt 'func - lt 'impl + lt 'r#impl lt 'static "#]], ); From 5d8fb778729a86a8ad2a772f77158e906e14172a Mon Sep 17 00:00:00 2001 From: yanglsh Date: Thu, 17 Apr 2025 20:53:59 +0800 Subject: [PATCH 045/302] fix: `unused_unit` suggests wrongly when unit never type fallback --- clippy_lints/src/lib.rs | 1 + clippy_lints/src/unused_unit.rs | 155 ++++++++++++++---------- tests/ui/unused_unit.edition2021.fixed | 146 ++++++++++++++++++++++ tests/ui/unused_unit.edition2021.stderr | 128 +++++++++++++++++++ tests/ui/unused_unit.edition2024.fixed | 146 ++++++++++++++++++++++ tests/ui/unused_unit.edition2024.stderr | 122 +++++++++++++++++++ tests/ui/unused_unit.fixed | 21 ++++ tests/ui/unused_unit.rs | 26 +++- tests/ui/unused_unit.stderr | 32 ++--- 9 files changed, 698 insertions(+), 79 deletions(-) create mode 100644 tests/ui/unused_unit.edition2021.fixed create mode 100644 tests/ui/unused_unit.edition2021.stderr create mode 100644 tests/ui/unused_unit.edition2024.fixed create mode 100644 tests/ui/unused_unit.edition2024.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5fa8f6f4bf3d..bc7fc60827a0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -729,6 +729,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); + store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf))); store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index d5309aade7aa..9859ddfdf7bd 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,11 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; -use rustc_ast::visit::FnKind; -use rustc_ast::{ClosureBinder, ast}; +use clippy_utils::{is_never_expr, is_unit_expr}; +use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{ + AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term, + Ty, TyKind, +}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; +use rustc_span::edition::Edition; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does @@ -34,27 +41,89 @@ declare_clippy_lint! { declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]); -impl EarlyLintPass for UnusedUnit { - fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { - if let ast::FnRetTy::Ty(ref ty) = kind.decl().output - && let ast::TyKind::Tup(ref vals) = ty.kind - && vals.is_empty() - && !ty.span.from_expansion() - && get_def(span) == get_def(ty.span) +impl<'tcx> LateLintPass<'tcx> for UnusedUnit { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + def_id: LocalDefId, + ) { + if let FnRetTy::Return(hir_ty) = decl.output + && is_unit_ty(hir_ty) + && !hir_ty.span.from_expansion() + && get_def(span) == get_def(hir_ty.span) { // implicit types in closure signatures are forbidden when `for<...>` is present - if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { + if let FnKind::Closure = kind + && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id) + && let ExprKind::Closure(closure) = expr.kind + && !closure.bound_generic_params.is_empty() + { return; } - lint_unneeded_unit_return(cx, ty, span); + // unit never type fallback is no longer supported since Rust 2024. For more information, + // see + if cx.tcx.sess.edition() >= Edition::Edition2024 + && let ExprKind::Block(block, _) = body.value.kind + && let Some(expr) = block.expr + && is_never_expr(cx, expr).is_some() + { + return; + } + + lint_unneeded_unit_return(cx, hir_ty.span, span); } } - fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if let Some(stmt) = block.stmts.last() - && let ast::StmtKind::Expr(ref expr) = stmt.kind + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind && is_unit_expr(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + expr.span, + "unneeded `()`", + "remove the `()`", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { + let segments = &poly.trait_ref.path.segments; + + if segments.len() == 1 + && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && let Some(args) = segments[0].args + && args.parenthesized == GenericArgsParentheses::ParenSugar + && let constraints = &args.constraints + && constraints.len() == 1 + && constraints[0].ident.name == sym::Output + && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind + && args.span_ext.hi() != poly.span.hi() + && !hir_ty.span.from_expansion() + && is_unit_ty(hir_ty) + { + lint_unneeded_unit_return(cx, hir_ty.span, poly.span); + } + } +} + +impl EarlyLintPass for UnusedUnit { + /// Check for unit expressions in blocks. This is left in the early pass because some macros + /// expand its inputs as-is, making it invisible to the late pass. See #4076. + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + if let Some(stmt) = block.stmts.last() + && let StmtKind::Expr(expr) = &stmt.kind + && let rustc_ast::ExprKind::Tup(inner) = &expr.kind + && inner.is_empty() && let ctxt = block.span.ctxt() && stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt @@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit { ); } } +} - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - match e.kind { - ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { - if is_unit_expr(expr) && !expr.span.from_expansion() { - span_lint_and_sugg( - cx, - UNUSED_UNIT, - expr.span, - "unneeded `()`", - "remove the `()`", - String::new(), - Applicability::MachineApplicable, - ); - } - }, - _ => (), - } - } - - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { - let segments = &poly.trait_ref.path.segments; - - if segments.len() == 1 - && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) - && let Some(args) = &segments[0].args - && let ast::GenericArgs::Parenthesized(generic_args) = &**args - && let ast::FnRetTy::Ty(ty) = &generic_args.output - && ty.kind.is_unit() - { - lint_unneeded_unit_return(cx, ty, generic_args.span); - } - } +fn is_unit_ty(ty: &Ty<'_>) -> bool { + matches!(ty.kind, TyKind::Tup([])) } // get the def site @@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option { } } -// is this expr a `()` unit? -fn is_unit_expr(expr: &ast::Expr) -> bool { - if let ast::ExprKind::Tup(ref vals) = expr.kind { - vals.is_empty() - } else { - false - } -} - -fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { +fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { let (ret_span, appl) = - span.with_hi(ty.span.hi()) + span.with_hi(ty_span.hi()) .get_source_text(cx) - .map_or((ty.span, Applicability::MaybeIncorrect), |src| { - position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + .map_or((ty_span, Applicability::MaybeIncorrect), |src| { + position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| { ( #[expect(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)), Applicability::MachineApplicable, ) }) diff --git a/tests/ui/unused_unit.edition2021.fixed b/tests/ui/unused_unit.edition2021.fixed new file mode 100644 index 000000000000..93dd58b8e9d7 --- /dev/null +++ b/tests/ui/unused_unit.edition2021.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/tests/ui/unused_unit.edition2021.stderr b/tests/ui/unused_unit.edition2021.stderr new file mode 100644 index 000000000000..13cc20d4d7ad --- /dev/null +++ b/tests/ui/unused_unit.edition2021.stderr @@ -0,0 +1,128 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:136:15 + | +LL | run(|| -> () { todo!() }); + | ^^^^^^ help: remove the `-> ()` + +error: aborting due to 20 previous errors + diff --git a/tests/ui/unused_unit.edition2024.fixed b/tests/ui/unused_unit.edition2024.fixed new file mode 100644 index 000000000000..987d901b97df --- /dev/null +++ b/tests/ui/unused_unit.edition2024.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/tests/ui/unused_unit.edition2024.stderr b/tests/ui/unused_unit.edition2024.stderr new file mode 100644 index 000000000000..a79e70e066bd --- /dev/null +++ b/tests/ui/unused_unit.edition2024.stderr @@ -0,0 +1,122 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: aborting due to 19 previous errors + diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index e3c02681c9fd..6668bf90c092 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -120,3 +120,24 @@ mod issue9949 { () } } + +#[clippy::msrv = "1.85"] +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + fn bar() { + run(|| -> () { todo!() }); + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index 4353026c594c..b7645f7b6a26 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -1,4 +1,6 @@ - +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested @@ -120,3 +122,25 @@ mod issue9949 { () } } + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/tests/ui/unused_unit.stderr b/tests/ui/unused_unit.stderr index 172fe0655028..366f2142095f 100644 --- a/tests/ui/unused_unit.stderr +++ b/tests/ui/unused_unit.stderr @@ -1,8 +1,8 @@ -error: unneeded unit return type - --> tests/ui/unused_unit.rs:20:58 +error: unneeded unit expression + --> tests/ui/unused_unit.rs:35:9 | -LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^^ help: remove the `-> ()` +LL | () + | ^^ help: remove the final `()` | note: the lint level is defined here --> tests/ui/unused_unit.rs:13:9 @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:60:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:20:28 | @@ -22,6 +28,12 @@ error: unneeded unit return type LL | where G: Fn() -> () { | ^^^^^^ help: remove the `-> ()` +error: unneeded unit return type + --> tests/ui/unused_unit.rs:20:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:25:26 | @@ -34,12 +46,6 @@ error: unneeded unit return type LL | fn into(self) -> () { | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:35:9 - | -LL | () - | ^^ help: remove the final `()` - error: unneeded unit return type --> tests/ui/unused_unit.rs:41:29 | @@ -82,12 +88,6 @@ error: unneeded unit return type LL | fn return_unit() -> () { () } | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:60:26 - | -LL | fn return_unit() -> () { () } - | ^^ help: remove the final `()` - error: unneeded `()` --> tests/ui/unused_unit.rs:72:14 | From 8290766bbee6a9ce384d0e7527c46001392ed423 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 27 Apr 2025 07:14:04 +0000 Subject: [PATCH 046/302] bypass linker configuration and cross target check on `x check` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index e4503b264562..149a19d9d88c 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -114,7 +114,7 @@ impl Cargo { match cmd_kind { // No need to configure the target linker for these command types, // as they don't invoke rustc at all. - Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {} + Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder); } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 147b009d3f47..ceac24d4315c 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -96,6 +96,7 @@ pub fn find(build: &Build) { let targets: HashSet<_> = match build.config.cmd { // We don't need to check cross targets for these commands. crate::Subcommand::Clean { .. } + | crate::Subcommand::Check { .. } | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { From 5123ad590461b236a90426556ddb2f6fd95311af Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 27 Apr 2025 16:28:06 +0800 Subject: [PATCH 047/302] Fix `zombie_processes` FP inside closures --- clippy_lints/src/zombie_processes.rs | 5 ++++- tests/ui/zombie_processes.rs | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 39c1aab8967a..09f1084fe700 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id}; use rustc_ast::Mutability; use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { let mut vis = WaitFinder { cx, local_id, + body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id), state: VisitorState::WalkUpToLocal, early_return: None, missing_wait_branch: None, @@ -129,6 +131,7 @@ struct MaybeWait(Span); struct WaitFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, local_id: HirId, + body_id: LocalDefId, state: VisitorState, early_return: Option, // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help @@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { } } else { match ex.kind { - ExprKind::Ret(e) => { + ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => { visit_opt!(self, visit_expr, e); if self.early_return.is_none() { self.early_return = Some(ex.span); diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs index 25bbc02ffb76..395f9dd2defb 100644 --- a/tests/ui/zombie_processes.rs +++ b/tests/ui/zombie_processes.rs @@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus { let mut x = Command::new("").spawn().unwrap(); return x.wait().unwrap(); } + +mod issue14677 { + use std::io; + use std::process::Command; + + fn do_something Result<(), ()>>(f: F) { + todo!() + } + + fn foo() { + let mut child = Command::new("true").spawn().unwrap(); + let some_condition = true; + do_something(|| { + if some_condition { + return Err(()); + } + Ok(()) + }); + child.kill().unwrap(); + child.wait().unwrap(); + } +} From 7669d5011977eef757bb4cd9437b6aef50f4b3f6 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 28 Apr 2025 06:49:38 +0300 Subject: [PATCH 048/302] add a FIXME Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/cargo.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 149a19d9d88c..5d3f7c9cc76b 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -112,8 +112,7 @@ impl Cargo { let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); match cmd_kind { - // No need to configure the target linker for these command types, - // as they don't invoke rustc at all. + // No need to configure the target linker for these command types. Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder); @@ -205,6 +204,8 @@ impl Cargo { self } + // FIXME(onur-ozkan): Add coverage to make sure modifications to this function + // doesn't cause cache invalidations (e.g., #130108). fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo { let target = self.target; let compiler = self.compiler; From bca637ce5d1745ecee0d510dfed5bc24dd30d194 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Feb 2025 09:46:46 +0000 Subject: [PATCH 049/302] Add or-patterns to pattern types --- clippy_utils/src/hir_utils.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index fe1fd70a9fa7..17368a7530d7 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1117,6 +1117,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(s); self.hash_const_arg(e); }, + TyPatKind::Or(variants) => { + for variant in variants.iter() { + self.hash_ty_pat(variant) + } + }, TyPatKind::Err(_) => {}, } } From 7e064c3072adff6e97581a34393ca6abedd4a335 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 28 Apr 2025 10:39:36 +0200 Subject: [PATCH 050/302] Add expression fill mode variant for filling with underscore expressions --- .../hir-def/src/nameres/mod_resolution.rs | 2 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 3 +- .../crates/hir-expand/src/lib.rs | 3 +- .../crates/ide-assists/src/assist_config.rs | 3 +- .../src/handlers/add_missing_impl_members.rs | 1 + .../src/handlers/add_missing_match_arms.rs | 23 +++++++- .../src/handlers/destructure_tuple_binding.rs | 2 +- .../src/handlers/generate_function.rs | 19 ++++++- .../replace_derive_with_manual_impl.rs | 15 +++-- .../crates/ide-assists/src/tests.rs | 5 ++ .../crates/ide-assists/src/utils.rs | 16 +++++- .../crates/ide-completion/src/item.rs | 2 +- .../crates/ide-db/src/assists.rs | 12 ++++ .../src/handlers/missing_fields.rs | 15 +++-- .../src/handlers/typed_hole.rs | 42 ++++++++++---- .../crates/ide-diagnostics/src/lib.rs | 13 +---- .../crates/ide-diagnostics/src/tests.rs | 55 ++----------------- .../rust-analyzer/crates/ide/src/doc_links.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 5 +- .../rust-analyzer/crates/ide/src/moniker.rs | 2 +- .../rust-analyzer/crates/ide/src/status.rs | 4 +- .../crates/ide/src/view_crate_graph.rs | 2 +- .../crates/proc-macro-srv/build.rs | 2 +- .../query-group-macro/tests/logger_db.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 10 ++-- .../crates/rust-analyzer/src/cli/scip.rs | 6 +- .../crates/rust-analyzer/src/config.rs | 16 ++++-- .../crates/syntax/src/ast/make.rs | 3 + src/tools/rust-analyzer/crates/tt/src/lib.rs | 6 +- .../xtask/src/codegen/grammar.rs | 2 +- .../xtask/src/codegen/parser_inline_tests.rs | 4 +- 31 files changed, 172 insertions(+), 125 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index d6c9f5a00c91..0c50f13edfb6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -86,7 +86,7 @@ impl ModDir { let dir_path = if root_dir_owner { DirPath::empty() } else { - DirPath::new(format!("{}/", name)) + DirPath::new(format!("{name}/")) }; if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) { return Ok(( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 29b7b33fd0fb..2219a55a84be 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -752,8 +752,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { err: Some(ExpandError::other( tt.delimiter.open, format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, TOKEN_LIMIT, + "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}", ), )), }) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index f0a9a2ad52c8..ad35f7000a14 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -206,8 +206,7 @@ impl ExpandErrorKind { }, None => RenderedExpandError { message: format!( - "internal error: proc-macro map is missing error entry for crate {:?}", - def_crate + "internal error: proc-macro map is missing error entry for crate {def_crate:?}" ), error: true, kind: RenderedExpandError::GENERAL_KIND, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs index 2de0013bb126..fb569f8cdae0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs @@ -5,7 +5,7 @@ //! assists if we are allowed to. use hir::ImportPathConfig; -use ide_db::{SnippetCap, imports::insert_use::InsertUseConfig}; +use ide_db::{SnippetCap, assists::ExprFillDefaultMode, imports::insert_use::InsertUseConfig}; use crate::AssistKind; @@ -21,6 +21,7 @@ pub struct AssistConfig { pub term_search_fuel: u64, pub term_search_borrowck: bool, pub code_action_grouping: bool, + pub expr_fill_default: ExprFillDefaultMode, } impl AssistConfig { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 887ec5aeec9a..6a55f39e6934 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -150,6 +150,7 @@ fn add_missing_impl_members_inner( let new_impl_def = edit.make_mut(impl_def.clone()); let first_new_item = add_trait_assoc_items_to_impl( &ctx.sema, + ctx.config, &missing_items, trait_, &new_impl_def, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 8c1c83e3f716..05d21cb97933 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -3,6 +3,7 @@ use std::iter::{self, Peekable}; use either::Either; use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym}; use ide_db::RootDatabase; +use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; @@ -216,7 +217,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // filter out hidden patterns because they're handled by the catch-all arm !hidden }) - .map(|(pat, _)| make.match_arm(pat, None, make::ext::expr_todo())); + .map(|(pat, _)| { + make.match_arm( + pat, + None, + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }, + ) + }); let mut arms: Vec<_> = match_arm_list .arms() @@ -246,7 +257,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); - let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo()); + let arm = make.match_arm( + make.wildcard_pat().into(), + None, + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }, + ); arms.push(arm); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index adf0f0997b39..f09389f8302f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -142,7 +142,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option name, - None => name_generator.suggest_name(&format!("_{}", id)), + None => name_generator.suggest_name(&format!("_{id}")), } .to_string() }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 824380253ae5..ba2b84a42c75 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -4,6 +4,7 @@ use hir::{ }; use ide_db::{ FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap, + assists::ExprFillDefaultMode, defs::{Definition, NameRefClass}, famous_defs::FamousDefs, helpers::is_editable_crate, @@ -276,7 +277,11 @@ impl FunctionBuilder { target_module, &mut necessary_generic_params, ); - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; fn_body = make::block_expr(vec![], Some(placeholder_expr)); }; @@ -331,7 +336,11 @@ impl FunctionBuilder { let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; let fn_body = make::block_expr(vec![], Some(placeholder_expr)); Some(Self { @@ -444,7 +453,11 @@ fn make_fn_body_as_new_function( let adt_info = adt_info.as_ref()?; let path_self = make::ext::ident_path("Self"); - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() { match strukt.kind(ctx.db()) { StructKind::Record => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 6dcdf5edbd63..806c8fba9ea4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -9,7 +9,7 @@ use syntax::{ }; use crate::{ - AssistId, + AssistConfig, AssistId, assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::{ DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items, @@ -128,8 +128,14 @@ fn add_assist( acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| { let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax()); let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false); - let impl_def_with_items = - impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path); + let impl_def_with_items = impl_def_from_trait( + &ctx.sema, + ctx.config, + adt, + &annotated_name, + trait_, + replace_trait_path, + ); update_attribute(builder, old_derives, old_tree, old_trait_path, attr); let trait_path = make::ty_path(replace_trait_path.clone()); @@ -217,6 +223,7 @@ fn add_assist( fn impl_def_from_trait( sema: &hir::Semantics<'_, ide_db::RootDatabase>, + config: &AssistConfig, adt: &ast::Adt, annotated_name: &ast::Name, trait_: Option, @@ -241,7 +248,7 @@ fn impl_def_from_trait( let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone())); let first_assoc_item = - add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope); + add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope); // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 0593e6930dca..5e6889792db6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -4,6 +4,7 @@ use expect_test::expect; use hir::Semantics; use ide_db::{ EditionedFileId, FileRange, RootDatabase, SnippetCap, + assists::ExprFillDefaultMode, base_db::SourceDatabase, imports::insert_use::{ImportGranularity, InsertUseConfig}, source_change::FileSystemEdit, @@ -35,6 +36,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { @@ -54,6 +56,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: false, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { @@ -73,6 +76,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { @@ -92,6 +96,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 0471998f0b14..ef6914fda1d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -8,6 +8,7 @@ use hir::{ }; use ide_db::{ RootDatabase, + assists::ExprFillDefaultMode, famous_defs::FamousDefs, path_transform::PathTransform, syntax_helpers::{node_ext::preorder_expr, prettify_macro_expansion}, @@ -27,7 +28,10 @@ use syntax::{ ted, }; -use crate::assist_context::{AssistContext, SourceChangeBuilder}; +use crate::{ + AssistConfig, + assist_context::{AssistContext, SourceChangeBuilder}, +}; mod gen_trait_fn_body; pub(crate) mod ref_field_expr; @@ -174,6 +178,7 @@ pub fn filter_assoc_items( /// inserted. pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, + config: &AssistConfig, original_items: &[InFile], trait_: hir::Trait, impl_: &ast::Impl, @@ -219,7 +224,14 @@ pub fn add_trait_assoc_items_to_impl( match &item { ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { let body = AstNodeEdit::indent( - &make::block_expr(None, Some(make::ext::expr_todo())), + &make::block_expr( + None, + Some(match config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }), + ), new_indent_level, ); ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax()) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index e208b9fd41ae..19cdef30bd96 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -135,7 +135,7 @@ impl fmt::Debug for CompletionItem { }, CompletionItemRefMode::Dereference => "*", }; - s.field("ref_match", &format!("{}@{offset:?}", prefix)); + s.field("ref_match", &format!("{prefix}@{offset:?}")); } if self.trigger_call_info { s.field("trigger_call_info", &true); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs index 90ae4a3b5b3a..384eb57c0fd5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs @@ -169,3 +169,15 @@ impl AssistResolveStrategy { #[derive(Clone, Debug)] pub struct GroupLabel(pub String); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ExprFillDefaultMode { + Todo, + Default, + Underscore, +} +impl Default for ExprFillDefaultMode { + fn default() -> Self { + Self::Todo + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 6b02111016c0..9aea2b1056d2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -5,9 +5,13 @@ use hir::{ sym, }; use ide_db::{ - FxHashMap, assists::Assist, famous_defs::FamousDefs, - imports::import_assets::item_for_path_search, source_change::SourceChange, - syntax_helpers::tree_diff::diff, text_edit::TextEdit, + FxHashMap, + assists::{Assist, ExprFillDefaultMode}, + famous_defs::FamousDefs, + imports::import_assets::item_for_path_search, + source_change::SourceChange, + syntax_helpers::tree_diff::diff, + text_edit::TextEdit, use_trivial_constructor::use_trivial_constructor, }; use stdx::format_to; @@ -102,8 +106,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option make::ext::expr_todo(), - crate::ExprFillDefaultMode::Default => { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => { get_default_constructor(ctx, d, ty).unwrap_or_else(make::ext::expr_todo) } }; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 277aff2e08f4..1e7f00c23313 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -1,3 +1,5 @@ +use std::ops::Not; + use hir::{ ClosureStyle, HirDisplay, ImportPathConfig, db::ExpandDatabase, @@ -60,9 +62,13 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option let mut formatter = |_: &hir::Type| String::from("_"); - let assists: Vec = paths + let assists: Vec = d + .expected + .is_unknown() + .not() + .then(|| "todo!()".to_owned()) .into_iter() - .filter_map(|path| { + .chain(paths.into_iter().filter_map(|path| { path.gen_source_code( &scope, &mut formatter, @@ -75,7 +81,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option ctx.display_target, ) .ok() - }) + })) .unique() .map(|code| Assist { id: AssistId::quick_fix("typed-hole"), @@ -95,9 +101,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option #[cfg(test)] mod tests { - use crate::tests::{ - check_diagnostics, check_fixes_unordered, check_has_fix, check_has_single_fix, - }; + use crate::tests::{check_diagnostics, check_fixes_unordered, check_has_fix}; #[test] fn unknown() { @@ -119,9 +123,9 @@ fn main() { if _ {} //^ 💡 error: invalid `_` expression, expected type `bool` let _: fn() -> i32 = _; - //^ error: invalid `_` expression, expected type `fn() -> i32` + //^ 💡 error: invalid `_` expression, expected type `fn() -> i32` let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion* - //^ error: invalid `_` expression, expected type `fn()` + //^ 💡 error: invalid `_` expression, expected type `fn()` } "#, ); @@ -147,7 +151,7 @@ fn main() { fn main() { let mut x = t(); x = _; - //^ error: invalid `_` expression, expected type `&str` + //^ 💡 error: invalid `_` expression, expected type `&str` x = ""; } fn t() -> T { loop {} } @@ -308,7 +312,7 @@ fn main() { #[test] fn ignore_impl_func_with_incorrect_return() { - check_has_single_fix( + check_fixes_unordered( r#" struct Bar {} trait Foo { @@ -323,7 +327,8 @@ fn main() { let a: i32 = 1; let c: Bar = _$0; }"#, - r#" + vec![ + r#" struct Bar {} trait Foo { type Res; @@ -337,6 +342,21 @@ fn main() { let a: i32 = 1; let c: Bar = Bar { }; }"#, + r#" +struct Bar {} +trait Foo { + type Res; + fn foo(&self) -> Self::Res; +} +impl Foo for i32 { + type Res = Self; + fn foo(&self) -> Self::Res { 1 } +} +fn main() { + let a: i32 = 1; + let c: Bar = todo!(); +}"#, + ], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 11efedd8a59d..607721d611d7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -92,7 +92,7 @@ use hir::{ }; use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, - assists::{Assist, AssistId, AssistResolveStrategy}, + assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode}, base_db::{ReleaseChannel, RootQueryDb as _}, generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup}, imports::insert_use::InsertUseConfig, @@ -219,17 +219,6 @@ impl Diagnostic { } } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ExprFillDefaultMode { - Todo, - Default, -} -impl Default for ExprFillDefaultMode { - fn default() -> Self { - Self::Todo - } -} - #[derive(Debug, Clone)] pub struct DiagnosticsConfig { /// Whether native diagnostics are enabled. diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 13d08d46dedd..4e4bd47e1c2f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -3,14 +3,16 @@ mod overly_long_real_world_cases; use ide_db::{ - LineIndexDatabase, RootDatabase, assists::AssistResolveStrategy, base_db::SourceDatabase, + LineIndexDatabase, RootDatabase, + assists::{AssistResolveStrategy, ExprFillDefaultMode}, + base_db::SourceDatabase, }; use itertools::Itertools; use stdx::trim_indent; use test_fixture::WithFixture; use test_utils::{MiniCore, assert_eq_text, extract_annotations}; -use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity}; +use crate::{DiagnosticsConfig, Severity}; /// Takes a multi-file input fixture with annotated cursor positions, /// and checks that: @@ -160,55 +162,6 @@ pub(crate) fn check_has_fix( assert!(fix.is_some(), "no diagnostic with desired fix"); } -#[track_caller] -pub(crate) fn check_has_single_fix( - #[rust_analyzer::rust_fixture] ra_fixture_before: &str, - #[rust_analyzer::rust_fixture] ra_fixture_after: &str, -) { - let after = trim_indent(ra_fixture_after); - - let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let mut conf = DiagnosticsConfig::test_sample(); - conf.expr_fill_default = ExprFillDefaultMode::Default; - let mut n_fixes = 0; - let fix = super::full_diagnostics( - &db, - &conf, - &AssistResolveStrategy::All, - file_position.file_id.file_id(&db), - ) - .into_iter() - .find(|d| { - d.fixes - .as_ref() - .and_then(|fixes| { - n_fixes += fixes.len(); - fixes.iter().find(|fix| { - if !fix.target.contains_inclusive(file_position.offset) { - return false; - } - let actual = { - let source_change = fix.source_change.as_ref().unwrap(); - let file_id = *source_change.source_file_edits.keys().next().unwrap(); - let mut actual = db.file_text(file_id).text(&db).to_string(); - - for (edit, snippet_edit) in source_change.source_file_edits.values() { - edit.apply(&mut actual); - if let Some(snippet_edit) = snippet_edit { - snippet_edit.apply(&mut actual); - } - } - actual - }; - after == actual - }) - }) - .is_some() - }); - assert!(fix.is_some(), "no diagnostic with desired fix"); - assert!(n_fixes == 1, "Too many fixes suggested"); -} - /// Checks that there's a diagnostic *without* fix at `$0`. pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index ebbd68bcdf74..f0247f32d7ec 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -599,7 +599,7 @@ fn filename_and_frag_for_def( Some(name) => { match m.attrs(db).by_key(sym::doc).find_string_value_in_tt(sym::keyword) { Some(kw) => { - format!("keyword.{}.html", kw) + format!("keyword.{kw}.html") } None => format!("{}/index.html", name.as_str()), } diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index a13be6c4927f..e7f5fcbf69f3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -123,9 +123,9 @@ pub use ide_completion::{ CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope, }; -pub use ide_db::text_edit::{Indel, TextEdit}; pub use ide_db::{ FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind, + assists::ExprFillDefaultMode, base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId}, documentation::Documentation, label::Label, @@ -134,8 +134,9 @@ pub use ide_db::{ search::{ReferenceCategory, SearchScope}, source_change::{FileSystemEdit, SnippetEdit, SourceChange}, symbol_index::Query, + text_edit::{Indel, TextEdit}, }; -pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode}; +pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig}; pub use ide_ssr::SsrError; pub use span::Edition; pub use syntax::{TextRange, TextSize}; diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 4a06cd919fc3..795c1f2ca3c0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -451,7 +451,7 @@ mod tests { assert_eq!(x.len(), 1); match x.into_iter().next().unwrap() { MonikerResult::Local { enclosing_moniker } => { - panic!("Unexpected local enclosed in {:?}", enclosing_moniker); + panic!("Unexpected local enclosed in {enclosing_moniker:?}"); } MonikerResult::Moniker(x) => { assert_eq!(identifier, x.identifier.to_string()); diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs index 55a0db2d8204..cfcd76d2aa3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/status.rs +++ b/src/tools/rust-analyzer/crates/ide/src/status.rs @@ -51,8 +51,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { buf, "Crate: {}\n", match display_name { - Some(it) => format!("{it}({:?})", crate_id), - None => format!("{:?}", crate_id), + Some(it) => format!("{it}({crate_id:?})"), + None => format!("{crate_id:?}"), } ); format_to!(buf, " Root module file id: {}\n", root_file_id.index()); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs index 4696fef3209a..7985279679c4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs @@ -80,7 +80,7 @@ impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> { fn node_id(&'a self, n: &Crate) -> Id<'a> { let id = n.as_id().as_u32(); - Id::new(format!("_{:?}", id)).unwrap() + Id::new(format!("_{id:?}")).unwrap() } fn node_shape(&'a self, _node: &Crate) -> Option> { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs index 07a10aaae578..97c0c4bda7df 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs @@ -12,5 +12,5 @@ fn main() { let version_string = std::str::from_utf8(&output.stdout[..]) .expect("rustc --version output must be UTF-8") .trim(); - println!("cargo::rustc-env=RUSTC_VERSION={}", version_string); + println!("cargo::rustc-env=RUSTC_VERSION={version_string}"); } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs index 5cf9be36f70c..0bb86467c78b 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs @@ -40,7 +40,7 @@ impl LoggerDb { /// it is meant to be run from outside any tracked functions. pub(crate) fn assert_logs(&self, expected: expect_test::Expect) { let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap()); - expected.assert_eq(&format!("{:#?}", logs)); + expected.assert_eq(&format!("{logs:#?}")); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index a62005e3c085..c50df4b6d45e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -175,7 +175,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(dep_loc), UsizeWithUnderscore(dep_item_trees), ); - eprintln!(" dependency item stats: {}", dep_item_stats); + eprintln!(" dependency item stats: {dep_item_stats}"); // FIXME(salsa-transition): bring back stats for ParseQuery (file size) // and ParseMacroExpansionQuery (macro expansion "file") size whenever we implement @@ -295,7 +295,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(workspace_loc), UsizeWithUnderscore(workspace_item_trees), ); - eprintln!(" usages: {}", workspace_item_stats); + eprintln!(" usages: {workspace_item_stats}"); eprintln!(" Dependencies:"); eprintln!( @@ -303,7 +303,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(dep_loc), UsizeWithUnderscore(dep_item_trees), ); - eprintln!(" declarations: {}", dep_item_stats); + eprintln!(" declarations: {dep_item_stats}"); let crate_def_map_time = crate_def_map_sw.elapsed(); eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time); @@ -1294,7 +1294,7 @@ impl fmt::Display for UsizeWithUnderscore { let num_str = self.0.to_string(); if num_str.len() <= 3 { - return write!(f, "{}", num_str); + return write!(f, "{num_str}"); } let mut result = String::new(); @@ -1307,7 +1307,7 @@ impl fmt::Display for UsizeWithUnderscore { } let result = result.chars().rev().collect::(); - write!(f, "{}", result) + write!(f, "{result}") } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 2062294f807c..d258c5d8191f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -265,10 +265,10 @@ impl flags::Scip { }; if !duplicate_symbol_errors.is_empty() { - eprintln!("{}", DUPLICATE_SYMBOLS_MESSAGE); + eprintln!("{DUPLICATE_SYMBOLS_MESSAGE}"); for (source_location, symbol) in duplicate_symbol_errors { - eprintln!("{}", source_location); - eprintln!(" Duplicate symbol: {}", symbol); + eprintln!("{source_location}"); + eprintln!(" Duplicate symbol: {symbol}"); eprintln!(); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index dd827949a9c2..9acbcc08a9dd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -9,13 +9,14 @@ use cfg::{CfgAtom, CfgDiff}; use hir::Symbol; use ide::{ AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig, - CompletionFieldsToResolve, DiagnosticsConfig, ExprFillDefaultMode, GenericParameterHints, - HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, - InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, - Snippet, SnippetScope, SourceRootId, + CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig, + HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, + JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, + SourceRootId, }; use ide_db::{ SnippetCap, + assists::ExprFillDefaultMode, imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, }; use itertools::{Either, Itertools}; @@ -1493,6 +1494,11 @@ impl Config { term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64, term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), code_action_grouping: self.code_action_group(), + expr_fill_default: match self.assist_expressionFillDefault(source_root) { + ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, + ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, + ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore, + }, } } @@ -1577,6 +1583,7 @@ impl Config { expr_fill_default: match self.assist_expressionFillDefault(source_root) { ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, + ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore, }, snippet_cap: self.snippet_cap(), insert_use: self.insert_use_config(source_root), @@ -2527,6 +2534,7 @@ where enum ExprFillDefaultDef { Todo, Default, + Underscore, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index d608a35effa1..9fe08c590461 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -69,6 +69,9 @@ pub mod ext { pub fn expr_todo() -> ast::Expr { expr_from_text("todo!()") } + pub fn expr_underscore() -> ast::Expr { + expr_from_text("_") + } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { expr_from_text(&format!("{ty}::default()")) } diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 36ccb67f3b8d..1dbc07c0929c 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -728,9 +728,9 @@ fn print_debug_subtree( }; write!(f, "{align}SUBTREE {delim} ",)?; - write!(f, "{:#?}", open)?; + write!(f, "{open:#?}")?; write!(f, " ")?; - write!(f, "{:#?}", close)?; + write!(f, "{close:#?}")?; for child in iter { writeln!(f)?; print_debug_token(f, level + 1, child)?; @@ -855,7 +855,7 @@ impl fmt::Display for Literal { } }?; if let Some(suffix) = &self.suffix { - write!(f, "{}", suffix)?; + write!(f, "{suffix}")?; } Ok(()) } diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs index 82df78c1a898..4b9c6edbe308 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs @@ -414,7 +414,7 @@ fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String { .map(|kind| to_pascal_case(kind)) .filter(|name| !defined_nodes.iter().any(|&it| it == name)) { - eprintln!("Warning: node {} not defined in AST source", node); + eprintln!("Warning: node {node} not defined in AST source"); drop(node); } diff --git a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs index f3b786b9d867..ae53771fe8e5 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs @@ -159,7 +159,7 @@ fn collect_tests(s: &str) -> Vec { (name.to_owned(), Some(edition.to_owned())) } [name] => (name.to_owned(), None), - _ => panic!("invalid test name: {:?}", name), + _ => panic!("invalid test name: {name:?}"), }; let text: String = edition .as_ref() @@ -212,7 +212,7 @@ fn existing_tests(dir: &Path, ok: TestKind) -> Result Date: Thu, 27 Mar 2025 14:20:25 +0100 Subject: [PATCH 051/302] std: get rid of `sys_common::process` Move the public `CommandEnvs` into the `process` module (and make it a wrapper type for an internal iterator type) and everything else into `sys::process` as per #117276. --- library/std/src/process.rs | 48 ++++++- .../process.rs => sys/process/env.rs} | 48 +------ library/std/src/sys/process/mod.rs | 59 ++++++++ library/std/src/sys/process/uefi.rs | 128 +++++++++--------- library/std/src/sys/process/unix/common.rs | 2 +- library/std/src/sys/process/unix/fuchsia.rs | 5 - library/std/src/sys/process/unix/unix.rs | 5 - .../std/src/sys/process/unix/unsupported.rs | 8 +- library/std/src/sys/process/unix/vxworks.rs | 5 - library/std/src/sys/process/unsupported.rs | 8 +- library/std/src/sys/process/windows.rs | 7 +- library/std/src/sys_common/mod.rs | 1 - 12 files changed, 182 insertions(+), 142 deletions(-) rename library/std/src/{sys_common/process.rs => sys/process/env.rs} (67%) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 76ce7bce81b1..df6b9a6e563c 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -168,8 +168,6 @@ use crate::num::NonZero; use crate::path::Path; use crate::sys::pipe::{AnonPipe, read2}; use crate::sys::process as imp; -#[stable(feature = "command_access", since = "1.57.0")] -pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, fs, str}; @@ -1073,7 +1071,7 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result { - let (status, stdout, stderr) = self.inner.output()?; + let (status, stdout, stderr) = imp::output(&mut self.inner)?; Ok(Output { status: ExitStatus(status), stdout, stderr }) } @@ -1174,7 +1172,7 @@ impl Command { /// ``` #[stable(feature = "command_access", since = "1.57.0")] pub fn get_envs(&self) -> CommandEnvs<'_> { - self.inner.get_envs() + CommandEnvs { iter: self.inner.get_envs() } } /// Returns the working directory for the child process. @@ -1264,6 +1262,48 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> { } } +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "command_access", since = "1.57.0")] +pub struct CommandEnvs<'a> { + iter: imp::CommandEnvs<'a>, +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> fmt::Debug for CommandEnvs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.fmt(f) + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys/process/env.rs similarity index 67% rename from library/std/src/sys_common/process.rs rename to library/std/src/sys/process/env.rs index 9f61d69d8587..e08b476540ef 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys/process/env.rs @@ -1,13 +1,9 @@ -#![allow(dead_code)] -#![unstable(feature = "process_internals", issue = "none")] - use crate::collections::BTreeMap; use crate::ffi::{OsStr, OsString}; -use crate::sys::pipe::read2; -use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes}; -use crate::{env, fmt, io}; +use crate::sys::process::EnvKey; +use crate::{env, fmt}; -// Stores a set of changes to an environment +/// Stores a set of changes to an environment #[derive(Clone, Default)] pub struct CommandEnv { clear: bool, @@ -92,30 +88,23 @@ impl CommandEnv { } } -/// An iterator over the command environment variables. -/// -/// This struct is created by -/// [`Command::get_envs`][crate::process::Command::get_envs]. See its -/// documentation for more. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "command_access", since = "1.57.0")] #[derive(Debug)] pub struct CommandEnvs<'a> { iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, } -#[stable(feature = "command_access", since = "1.57.0")] impl<'a> Iterator for CommandEnvs<'a> { type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } -#[stable(feature = "command_access", since = "1.57.0")] impl<'a> ExactSizeIterator for CommandEnvs<'a> { fn len(&self) -> usize { self.iter.len() @@ -124,30 +113,3 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> { self.iter.is_empty() } } - -pub fn wait_with_output( - mut process: Process, - mut pipes: StdioPipes, -) -> io::Result<(ExitStatus, Vec, Vec)> { - drop(pipes.stdin.take()); - - let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); - match (pipes.stdout.take(), pipes.stderr.take()) { - (None, None) => {} - (Some(out), None) => { - let res = out.read_to_end(&mut stdout); - res.unwrap(); - } - (None, Some(err)) => { - let res = err.read_to_end(&mut stderr); - res.unwrap(); - } - (Some(out), Some(err)) => { - let res = read2(out, &mut stdout, err, &mut stderr); - res.unwrap(); - } - } - - let status = process.wait()?; - Ok((status, stdout, stderr)) -} diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index 92cfac7f47cf..91c7005a3285 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -14,6 +14,65 @@ cfg_if::cfg_if! { } } +// This module is shared by all platforms, but nearly all platforms except for +// the "normal" UNIX ones leave some of this code unused. +#[cfg_attr(not(target_os = "linux"), allow(dead_code))] +mod env; + +pub use env::CommandEnvs; pub use imp::{ Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes, }; + +#[cfg(any( + all( + target_family = "unix", + not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )) + ), + target_os = "windows", +))] +pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec)> { + use crate::sys::pipe::read2; + + let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?; + + drop(pipes.stdin.take()); + let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); + match (pipes.stdout.take(), pipes.stderr.take()) { + (None, None) => {} + (Some(out), None) => { + let res = out.read_to_end(&mut stdout); + res.unwrap(); + } + (None, Some(err)) => { + let res = err.read_to_end(&mut stderr); + res.unwrap(); + } + (Some(out), Some(err)) => { + let res = read2(out, &mut stdout, err, &mut stderr); + res.unwrap(); + } + } + + let status = process.wait()?; + Ok((status, stdout, stderr)) +} + +#[cfg(not(any( + all( + target_family = "unix", + not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )) + ), + target_os = "windows", +)))] +pub use imp::output; diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 5f922292d054..4864c5869881 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -1,5 +1,6 @@ use r_efi::protocols::{simple_text_input, simple_text_output}; +use super::env::{CommandEnv, CommandEnvs}; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; @@ -10,7 +11,6 @@ use crate::sys::pal::helpers; use crate::sys::pal::os::error_string; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{fmt, io}; //////////////////////////////////////////////////////////////////////////////// @@ -139,72 +139,72 @@ impl Command { Stdio::MakePipe => unsupported(), } } +} - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; +pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + let mut cmd = uefi_command_internal::Image::load_image(&command.prog)?; - // UEFI adds the bin name by default - if !self.args.is_empty() { - let args = uefi_command_internal::create_args(&self.prog, &self.args); - cmd.set_args(args); - } - - // Setup Stdout - let stdout = self.stdout.unwrap_or(Stdio::MakePipe); - let stdout = Self::create_pipe(stdout)?; - if let Some(con) = stdout { - cmd.stdout_init(con) - } else { - cmd.stdout_inherit() - }; - - // Setup Stderr - let stderr = self.stderr.unwrap_or(Stdio::MakePipe); - let stderr = Self::create_pipe(stderr)?; - if let Some(con) = stderr { - cmd.stderr_init(con) - } else { - cmd.stderr_inherit() - }; - - // Setup Stdin - let stdin = self.stdin.unwrap_or(Stdio::Null); - let stdin = Self::create_stdin(stdin)?; - if let Some(con) = stdin { - cmd.stdin_init(con) - } else { - cmd.stdin_inherit() - }; - - let env = env_changes(&self.env); - - // Set any new vars - if let Some(e) = &env { - for (k, (_, v)) in e { - match v { - Some(v) => unsafe { crate::env::set_var(k, v) }, - None => unsafe { crate::env::remove_var(k) }, - } - } - } - - let stat = cmd.start_image()?; - - // Rollback any env changes - if let Some(e) = env { - for (k, (v, _)) in e { - match v { - Some(v) => unsafe { crate::env::set_var(k, v) }, - None => unsafe { crate::env::remove_var(k) }, - } - } - } - - let stdout = cmd.stdout()?; - let stderr = cmd.stderr()?; - - Ok((ExitStatus(stat), stdout, stderr)) + // UEFI adds the bin name by default + if !command.args.is_empty() { + let args = uefi_command_internal::create_args(&command.prog, &command.args); + cmd.set_args(args); } + + // Setup Stdout + let stdout = command.stdout.unwrap_or(Stdio::MakePipe); + let stdout = Command::create_pipe(stdout)?; + if let Some(con) = stdout { + cmd.stdout_init(con) + } else { + cmd.stdout_inherit() + }; + + // Setup Stderr + let stderr = command.stderr.unwrap_or(Stdio::MakePipe); + let stderr = Command::create_pipe(stderr)?; + if let Some(con) = stderr { + cmd.stderr_init(con) + } else { + cmd.stderr_inherit() + }; + + // Setup Stdin + let stdin = command.stdin.unwrap_or(Stdio::Null); + let stdin = Command::create_stdin(stdin)?; + if let Some(con) = stdin { + cmd.stdin_init(con) + } else { + cmd.stdin_inherit() + }; + + let env = env_changes(&command.env); + + // Set any new vars + if let Some(e) = &env { + for (k, (_, v)) in e { + match v { + Some(v) => unsafe { crate::env::set_var(k, v) }, + None => unsafe { crate::env::remove_var(k) }, + } + } + } + + let stat = cmd.start_image()?; + + // Rollback any env changes + if let Some(e) = env { + for (k, (v, _)) in e { + match v { + Some(v) => unsafe { crate::env::set_var(k, v) }, + None => unsafe { crate::env::remove_var(k) }, + } + } + } + + let stdout = cmd.stdout()?; + let stderr = cmd.stderr()?; + + Ok((ExitStatus(stat), stdout, stderr)) } impl From for Stdio { diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 8bc17f314911..a9c2510e6d45 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -12,7 +12,7 @@ use crate::sys::fs::File; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; +use crate::sys::process::env::{CommandEnv, CommandEnvs}; use crate::sys_common::{FromInner, IntoInner}; use crate::{fmt, io, ptr}; diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs index 0de32ecffd4b..fbe06c4799be 100644 --- a/library/std/src/sys/process/unix/fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -31,11 +31,6 @@ impl Command { Ok((Process { handle: Handle::new(process_handle) }, ours)) } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul() { return io::const_error!( diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index ae1c9558281e..1b3bd2de265d 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -162,11 +162,6 @@ impl Command { } } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - // WatchOS and TVOS headers mark the `fork`/`exec*` functions with // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the // `posix_spawn*` functions should be used instead. It isn't entirely clear diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs index 78d270923cfa..e86561a5c5c4 100644 --- a/library/std/src/sys/process/unix/unsupported.rs +++ b/library/std/src/sys/process/unix/unsupported.rs @@ -18,15 +18,15 @@ impl Command { unsupported() } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - unsupported() - } - pub fn exec(&mut self, _default: Stdio) -> io::Error { unsupported_err() } } +pub fn output(_: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() +} + //////////////////////////////////////////////////////////////////////////////// // Processes //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index b92446f0cf67..fab3b36ebf3f 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -112,11 +112,6 @@ impl Command { } } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - pub fn exec(&mut self, default: Stdio) -> io::Error { let ret = Command::spawn(self, default, false); match ret { diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs index fee81744f09e..469922c78aca 100644 --- a/library/std/src/sys/process/unsupported.rs +++ b/library/std/src/sys/process/unsupported.rs @@ -1,3 +1,4 @@ +use super::env::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; @@ -5,7 +6,6 @@ use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{fmt, io}; //////////////////////////////////////////////////////////////////////////////// @@ -104,10 +104,10 @@ impl Command { ) -> io::Result<(Process, StdioPipes)> { unsupported() } +} - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - unsupported() - } +pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() } impl From for Stdio { diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 4cfdf908c58d..4acd753eec91 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -5,6 +5,7 @@ mod tests; use core::ffi::c_void; +use super::env::{CommandEnv, CommandEnvs}; use crate::collections::BTreeMap; use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX}; use crate::ffi::{OsStr, OsString}; @@ -24,7 +25,6 @@ use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; use crate::sys_common::IntoInner; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{cmp, env, fmt, ptr}; //////////////////////////////////////////////////////////////////////////////// @@ -389,11 +389,6 @@ impl Command { )) } } - - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } } impl fmt::Debug for Command { diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 2a5de7f66661..b7f4656fa370 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod process; pub mod wstr; pub mod wtf8; From 99f00927cc1de78b812ddc422b2e425b1fdbf998 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 28 Apr 2025 11:55:26 +0200 Subject: [PATCH 052/302] fix: Address minor FIXME --- .../crates/hir-def/src/item_scope.rs | 19 ++++++++----------- .../hir-def/src/nameres/path_resolution.rs | 5 ++--- .../crates/hir-def/src/per_ns.rs | 12 +++++------- .../crates/hir-def/src/resolver.rs | 2 +- .../rust-analyzer/crates/hir/src/symbols.rs | 5 +++-- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index bece940950d8..5362c0588dbe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -167,7 +167,7 @@ pub struct ItemScope { // the resolutions of the imports of this scope use_imports_types: FxHashMap, use_imports_values: FxHashMap, - use_imports_macros: FxHashMap, + use_imports_macros: FxHashMap, use_decls: Vec, extern_crate_decls: Vec, @@ -242,7 +242,7 @@ impl ItemScope { self.types.iter().map(|(n, &i)| (n, i)) } - pub fn macros(&self) -> impl Iterator)> + '_ { + pub fn macros(&self) -> impl Iterator)> + '_ { self.macros.iter().map(|(n, &i)| (n, i)) } @@ -250,9 +250,9 @@ impl ItemScope { self.use_imports_types .keys() .copied() + .chain(self.use_imports_macros.keys().copied()) .filter_map(ImportOrExternCrate::import_or_glob) .chain(self.use_imports_values.keys().copied()) - .chain(self.use_imports_macros.keys().copied()) .filter_map(ImportOrGlob::into_import) .sorted() .dedup() @@ -263,7 +263,7 @@ impl ItemScope { let mut def_map; let mut scope = self; - while let Some(&m) = scope.use_imports_macros.get(&ImportOrGlob::Import(import)) { + while let Some(&m) = scope.use_imports_macros.get(&ImportOrExternCrate::Import(import)) { match m { ImportOrDef::Import(i) => { let module_id = i.use_.lookup(db).container; @@ -682,7 +682,6 @@ impl ItemScope { } _ => _ = glob_imports.macros.remove(&lookup), } - let import = import.and_then(ImportOrExternCrate::import_or_glob); let prev = std::mem::replace(&mut fld.import, import); if let Some(import) = import { self.use_imports_macros.insert( @@ -698,7 +697,6 @@ impl ItemScope { { if glob_imports.macros.remove(&lookup) { cov_mark::hit!(import_shadowed); - let import = import.and_then(ImportOrExternCrate::import_or_glob); let prev = std::mem::replace(&mut fld.import, import); if let Some(import) = import { self.use_imports_macros.insert( @@ -783,8 +781,9 @@ impl ItemScope { if let Some(Item { import, .. }) = def.macros { buf.push_str(" m"); match import { - Some(ImportOrGlob::Import(_)) => buf.push('i'), - Some(ImportOrGlob::Glob(_)) => buf.push('g'), + Some(ImportOrExternCrate::Import(_)) => buf.push('i'), + Some(ImportOrExternCrate::Glob(_)) => buf.push('g'), + Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'), None => (), } } @@ -893,9 +892,7 @@ impl PerNs { ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import), ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import), ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import), - ModuleDefId::MacroId(mac) => { - PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::import_or_glob)) - } + ModuleDefId::MacroId(mac) => PerNs::macros(mac, v, import), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index f8b2c73a8f68..a49155d878ca 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -673,12 +673,11 @@ impl DefMap { } fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs { - self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| { + self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { PerNs::macros( it, Visibility::Public, - // FIXME? - None, // extern_crate.map(ImportOrExternCrate::ExternCrate), + extern_crate.map(ImportOrExternCrate::ExternCrate), ) }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs index 1f7dd6f0c407..8721cd65dbac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs @@ -37,7 +37,8 @@ pub struct Item { pub type TypesItem = Item; pub type ValuesItem = Item; -pub type MacrosItem = Item; +// May be Externcrate for `[macro_use]`'d macros +pub type MacrosItem = Item; #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub struct PerNs { @@ -84,7 +85,7 @@ impl PerNs { } } - pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs { + pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs { PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) } } @@ -116,7 +117,7 @@ impl PerNs { self.macros.map(|it| it.def) } - pub fn take_macros_import(self) -> Option<(MacroId, Option)> { + pub fn take_macros_import(self) -> Option<(MacroId, Option)> { self.macros.map(|it| (it.def, it.import)) } @@ -158,9 +159,6 @@ impl PerNs { self.values .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))), ) - .chain( - self.macros - .map(|it| (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::from))), - ) + .chain(self.macros.map(|it| (ItemInNs::Macros(it.def), it.import))) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 9b9335f19116..552b4961f5e2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -493,7 +493,7 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, expected_macro_kind: Option, - ) -> Option<(MacroId, Option)> { + ) -> Option<(MacroId, Option)> { let (item_map, item_local_map, module) = self.item_scope_(); item_map .resolve_path( diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 41064d047a5a..3d944afb8b30 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -263,8 +263,9 @@ impl<'a> SymbolCollector<'a> { for (name, Item { def, vis, import }) in scope.macros() { if let Some(i) = import { match i { - ImportOrGlob::Import(i) => push_import(self, i, name, def.into(), vis), - ImportOrGlob::Glob(_) => (), + ImportOrExternCrate::Import(i) => push_import(self, i, name, def.into(), vis), + ImportOrExternCrate::Glob(_) => (), + ImportOrExternCrate::ExternCrate(_) => (), } continue; } From 2231efa27d12428f76e12990bb00948a26506947 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Tue, 8 Apr 2025 14:18:09 +0530 Subject: [PATCH 053/302] refactor: migrate `let_else_to_match` to editor Signed-off-by: Prajwal S N --- .../src/handlers/add_missing_match_arms.rs | 4 +- .../src/handlers/convert_let_else_to_match.rs | 299 ++++++++++-------- .../handlers/destructure_struct_binding.rs | 4 +- .../src/handlers/expand_rest_pattern.rs | 7 +- .../src/handlers/unmerge_match_arm.rs | 10 +- .../src/handlers/missing_fields.rs | 11 +- .../crates/syntax/src/ast/make.rs | 32 +- .../src/ast/syntax_factory/constructors.rs | 110 ++++++- 8 files changed, 335 insertions(+), 142 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 05d21cb97933..858d4369914a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -493,8 +493,8 @@ fn build_pat( hir::StructKind::Record => { let fields = fields .into_iter() - .map(|f| make.name_ref(f.name(db).as_str())) - .map(|name_ref| make.record_pat_field_shorthand(name_ref)); + .map(|f| make.ident_pat(false, false, make.name(f.name(db).as_str()))) + .map(|ident| make.record_pat_field_shorthand(ident.into())); let fields = make.record_pat_field_list(fields, None); make.record_pat_with_fields(path, fields).into() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index df92b07cba7c..ebfed9f9ca99 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -1,8 +1,9 @@ -use hir::Semantics; -use ide_db::RootDatabase; use syntax::T; use syntax::ast::RangeItem; -use syntax::ast::{AstNode, HasName, LetStmt, Name, Pat, edit::AstNodeEdit}; +use syntax::ast::edit::IndentLevel; +use syntax::ast::edit_in_place::Indent; +use syntax::ast::syntax_factory::SyntaxFactory; +use syntax::ast::{self, AstNode, HasName, LetStmt, Pat}; use crate::{AssistContext, AssistId, Assists}; @@ -25,155 +26,205 @@ use crate::{AssistContext, AssistId, Assists}; // } // ``` pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - // should focus on else token to trigger + // Should focus on the `else` token to trigger let let_stmt = ctx .find_token_syntax_at_offset(T![else]) .and_then(|it| it.parent()?.parent()) .or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?; let let_stmt = LetStmt::cast(let_stmt)?; - let let_else_block = let_stmt.let_else()?.block_expr()?; - let let_init = let_stmt.initializer()?; + let else_block = let_stmt.let_else()?.block_expr()?; + let else_expr = if else_block.statements().next().is_none() { + else_block.tail_expr()? + } else { + else_block.into() + }; + let init = let_stmt.initializer()?; + // Ignore let stmt with type annotation if let_stmt.ty().is_some() { - // don't support let with type annotation return None; } let pat = let_stmt.pat()?; - let mut binders = Vec::new(); - binders_in_pat(&mut binders, &pat, &ctx.sema)?; - let target = let_stmt.syntax().text_range(); + let make = SyntaxFactory::with_mappings(); + let mut idents = Vec::default(); + let pat_without_mut = remove_mut_and_collect_idents(&make, &pat, &mut idents)?; + let bindings = idents + .into_iter() + .filter_map(|ref pat| { + // Identifiers which resolve to constants are not bindings + if ctx.sema.resolve_bind_pat_to_const(pat).is_none() { + Some((pat.name()?, pat.ref_token().is_none() && pat.mut_token().is_some())) + } else { + None + } + }) + .collect::>(); + acc.add( AssistId::refactor_rewrite("convert_let_else_to_match"), - "Convert let-else to let and match", - target, - |edit| { - let indent_level = let_stmt.indent_level().0 as usize; - let indent = " ".repeat(indent_level); - let indent1 = " ".repeat(indent_level + 1); + if bindings.is_empty() { + "Convert let-else to match" + } else { + "Convert let-else to let and match" + }, + let_stmt.syntax().text_range(), + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); - let binders_str = binders_to_str(&binders, false); - let binders_str_mut = binders_to_str(&binders, true); + let binding_paths = bindings + .iter() + .map(|(name, _)| make.expr_path(make.ident_path(&name.to_string()))) + .collect::>(); - let init_expr = let_init.syntax().text(); - let mut pat_no_mut = pat.syntax().text().to_string(); - // remove the mut from the pattern - for (b, ismut) in binders.iter() { - if *ismut { - pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string()); - } + let binding_arm = make.match_arm( + pat_without_mut, + None, + // There are three possible cases: + // + // - No bindings: `None => {}` + // - Single binding: `Some(it) => it` + // - Multiple bindings: `Foo::Bar { a, b, .. } => (a, b)` + match binding_paths.len() { + 0 => make.expr_empty_block().into(), + + 1 => binding_paths[0].clone(), + _ => make.expr_tuple(binding_paths).into(), + }, + ); + let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr); + let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm])); + match_.reindent_to(IndentLevel::from_node(let_stmt.syntax())); + + if bindings.is_empty() { + editor.replace(let_stmt.syntax(), match_.syntax()); + } else { + let ident_pats = bindings + .into_iter() + .map(|(name, is_mut)| make.ident_pat(false, is_mut, name).into()) + .collect::>(); + let new_let_stmt = make.let_stmt( + if ident_pats.len() == 1 { + ident_pats[0].clone() + } else { + make.tuple_pat(ident_pats).into() + }, + None, + Some(match_.into()), + ); + editor.replace(let_stmt.syntax(), new_let_stmt.syntax()); } - let only_expr = let_else_block.statements().next().is_none(); - let branch2 = match &let_else_block.tail_expr() { - Some(tail) if only_expr => format!("{tail},"), - _ => let_else_block.syntax().text().to_string(), - }; - let replace = if binders.is_empty() { - format!( - "match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str} -{indent1}_ => {branch2} -{indent}}}" - ) - } else { - format!( - "let {binders_str_mut} = match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str}, -{indent1}_ => {branch2} -{indent}}};" - ) - }; - edit.replace(target, replace); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } -/// Gets a list of binders in a pattern, and whether they are mut. -fn binders_in_pat( - acc: &mut Vec<(Name, bool)>, - pat: &Pat, - sem: &Semantics<'_, RootDatabase>, -) -> Option<()> { - use Pat::*; - match pat { - IdentPat(p) => { - let ident = p.name()?; - let ismut = p.ref_token().is_none() && p.mut_token().is_some(); - // check for const reference - if sem.resolve_bind_pat_to_const(p).is_none() { - acc.push((ident, ismut)); - } +fn remove_mut_and_collect_idents( + make: &SyntaxFactory, + pat: &ast::Pat, + acc: &mut Vec, +) -> Option { + Some(match pat { + ast::Pat::IdentPat(p) => { + acc.push(p.clone()); + let non_mut_pat = make.ident_pat( + p.ref_token().is_some(), + p.ref_token().is_some() && p.mut_token().is_some(), + p.name()?, + ); if let Some(inner) = p.pat() { - binders_in_pat(acc, &inner, sem)?; + non_mut_pat.set_pat(remove_mut_and_collect_idents(make, &inner, acc)); } - Some(()) + non_mut_pat.into() } - BoxPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(()), - OrPat(p) => { - for p in p.pats() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) + ast::Pat::BoxPat(p) => { + make.box_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into() } - ParenPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - RangePat(p) => { - if let Some(st) = p.start() { - binders_in_pat(acc, &st, sem)? - } - if let Some(ed) = p.end() { - binders_in_pat(acc, &ed, sem)? - } - Some(()) + ast::Pat::OrPat(p) => make + .or_pat( + p.pats() + .map(|pat| remove_mut_and_collect_idents(make, &pat, acc)) + .collect::>>()?, + p.leading_pipe().is_some(), + ) + .into(), + ast::Pat::ParenPat(p) => { + make.paren_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into() } - RecordPat(p) => { - for f in p.record_pat_field_list()?.fields() { - let pat = f.pat()?; - binders_in_pat(acc, &pat, sem)?; + ast::Pat::RangePat(p) => make + .range_pat( + if let Some(start) = p.start() { + Some(remove_mut_and_collect_idents(make, &start, acc)?) + } else { + None + }, + if let Some(end) = p.end() { + Some(remove_mut_and_collect_idents(make, &end, acc)?) + } else { + None + }, + ) + .into(), + ast::Pat::RecordPat(p) => make + .record_pat_with_fields( + p.path()?, + make.record_pat_field_list( + p.record_pat_field_list()? + .fields() + .map(|field| { + remove_mut_and_collect_idents(make, &field.pat()?, acc).map(|pat| { + if let Some(name_ref) = field.name_ref() { + make.record_pat_field(name_ref, pat) + } else { + make.record_pat_field_shorthand(pat) + } + }) + }) + .collect::>>()?, + p.record_pat_field_list()?.rest_pat(), + ), + ) + .into(), + ast::Pat::RefPat(p) => { + let inner = p.pat()?; + if let ast::Pat::IdentPat(ident) = inner { + acc.push(ident); + p.clone_for_update().into() + } else { + make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into() } - Some(()) - } - RefPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - SlicePat(p) => { - for p in p.pats() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) - } - TuplePat(p) => { - for p in p.fields() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) - } - TupleStructPat(p) => { - for p in p.fields() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) } + ast::Pat::SlicePat(p) => make + .slice_pat( + p.pats() + .map(|pat| remove_mut_and_collect_idents(make, &pat, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::TuplePat(p) => make + .tuple_pat( + p.fields() + .map(|field| remove_mut_and_collect_idents(make, &field, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::TupleStructPat(p) => make + .tuple_struct_pat( + p.path()?, + p.fields() + .map(|field| remove_mut_and_collect_idents(make, &field, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::RestPat(_) + | ast::Pat::LiteralPat(_) + | ast::Pat::PathPat(_) + | ast::Pat::WildcardPat(_) + | ast::Pat::ConstBlockPat(_) => pat.clone(), // don't support macro pat yet - MacroPat(_) => None, - } -} - -fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String { - let vars = binders - .iter() - .map( - |(ident, ismut)| { - if *ismut && addmut { format!("mut {ident}") } else { ident.to_string() } - }, - ) - .collect::>() - .join(", "); - if binders.is_empty() { - String::from("{}") - } else if binders.len() == 1 { - vars - } else { - format!("({vars})") - } + ast::Pat::MacroPat(_) => return None, + }) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 800ef89ac6ed..b8c647ac8b71 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -196,7 +196,9 @@ fn destructure_pat( let fields = field_names.iter().map(|(old_name, new_name)| { // Use shorthand syntax if possible if old_name == new_name && !is_mut { - make.record_pat_field_shorthand(make.name_ref(old_name)) + make.record_pat_field_shorthand( + make.ident_pat(false, false, make.name(old_name)).into(), + ) } else { make.record_pat_field( make.name_ref(old_name), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 4e487e216264..b71de5e00c6a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -56,7 +56,12 @@ fn expand_record_rest_pattern( let new_field_list = make.record_pat_field_list(old_field_list.fields(), None); for (f, _) in missing_fields.iter() { let field = make.record_pat_field_shorthand( - make.name_ref(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()), + make.ident_pat( + false, + false, + make.name(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()), + ) + .into(), ); new_field_list.add_field(field); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 31ff47a05492..5aedff5cc775 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -53,8 +53,14 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |edit| { let pats_after = pipe_token .siblings_with_tokens(Direction::Next) - .filter_map(|it| ast::Pat::cast(it.into_node()?)); - let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some()); + .filter_map(|it| ast::Pat::cast(it.into_node()?)) + .collect::>(); + // It is guaranteed that `pats_after` has at least one element + let new_pat = if pats_after.len() == 1 { + pats_after[0].clone() + } else { + make::or_pat(pats_after, or_pat.leading_pipe().is_some()).into() + }; let new_match_arm = make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 9aea2b1056d2..a354d123f5ab 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -163,9 +163,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ast::WildcardPat { } pub fn rest_pat() -> ast::RestPat { - ast_from_text("fn f(..)") + ast_from_text("fn f() { let ..; }") } pub fn literal_pat(lit: &str) -> ast::LiteralPat { @@ -788,8 +788,8 @@ pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPat ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))")) } -pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))")) +pub fn record_pat_field_shorthand(pat: ast::Pat) -> ast::RecordPatField { + ast_from_text(&format!("fn f(S {{ {pat} }}: ()))")) } /// Returns a `IdentPat` if the path has just one segment, a `PathPat` otherwise. @@ -801,16 +801,38 @@ pub fn path_pat(path: ast::Path) -> ast::Pat { } /// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise. -pub fn or_pat(pats: impl IntoIterator, leading_pipe: bool) -> ast::Pat { +/// +/// Invariant: `pats` must be length > 1. +pub fn or_pat(pats: impl IntoIterator, leading_pipe: bool) -> ast::OrPat { let leading_pipe = if leading_pipe { "| " } else { "" }; let pats = pats.into_iter().join(" | "); return from_text(&format!("{leading_pipe}{pats}")); - fn from_text(text: &str) -> ast::Pat { + fn from_text(text: &str) -> ast::OrPat { ast_from_text(&format!("fn f({text}: ())")) } } +pub fn box_pat(pat: ast::Pat) -> ast::BoxPat { + ast_from_text(&format!("fn f(box {pat}: ())")) +} + +pub fn paren_pat(pat: ast::Pat) -> ast::ParenPat { + ast_from_text(&format!("fn f(({pat}): ())")) +} + +pub fn range_pat(start: Option, end: Option) -> ast::RangePat { + ast_from_text(&format!( + "fn f({}..{}: ())", + start.map(|e| e.to_string()).unwrap_or_default(), + end.map(|e| e.to_string()).unwrap_or_default() + )) +} + +pub fn ref_pat(pat: ast::Pat) -> ast::RefPat { + ast_from_text(&format!("fn f(&{pat}: ())")) +} + pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) -> ast::MatchArm { return match guard { Some(guard) => from_text(&format!("{pat} {guard} => {expr}")), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 1854000d3db2..3b205516c223 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -3,7 +3,7 @@ use crate::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, ast::{ self, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, - HasVisibility, make, + HasVisibility, RangeItem, make, }, syntax_editor::SyntaxMappingBuilder, }; @@ -254,12 +254,12 @@ impl SyntaxFactory { ast } - pub fn record_pat_field_shorthand(&self, name_ref: ast::NameRef) -> ast::RecordPatField { - let ast = make::record_pat_field_shorthand(name_ref.clone()).clone_for_update(); + pub fn record_pat_field_shorthand(&self, pat: ast::Pat) -> ast::RecordPatField { + let ast = make::record_pat_field_shorthand(pat.clone()).clone_for_update(); if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); - builder.map_node(name_ref.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); builder.finish(&mut mapping); } @@ -294,6 +294,76 @@ impl SyntaxFactory { make::rest_pat().clone_for_update() } + pub fn or_pat( + &self, + pats: impl IntoIterator, + leading_pipe: bool, + ) -> ast::OrPat { + let (pats, input) = iterator_input(pats); + let ast = make::or_pat(pats, leading_pipe).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.pats().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + + pub fn box_pat(&self, pat: ast::Pat) -> ast::BoxPat { + let ast = make::box_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn paren_pat(&self, pat: ast::Pat) -> ast::ParenPat { + let ast = make::paren_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn range_pat(&self, start: Option, end: Option) -> ast::RangePat { + let ast = make::range_pat(start.clone(), end.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(start) = start { + builder.map_node(start.syntax().clone(), ast.start().unwrap().syntax().clone()); + } + if let Some(end) = end { + builder.map_node(end.syntax().clone(), ast.end().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn ref_pat(&self, pat: ast::Pat) -> ast::RefPat { + let ast = make::ref_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn block_expr( &self, statements: impl IntoIterator, @@ -673,6 +743,38 @@ impl SyntaxFactory { ast } + pub fn let_else_stmt( + &self, + pattern: ast::Pat, + ty: Option, + initializer: ast::Expr, + diverging: ast::BlockExpr, + ) -> ast::LetStmt { + let ast = make::let_else_stmt( + pattern.clone(), + ty.clone(), + initializer.clone(), + diverging.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(input) = ty { + builder.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + builder.map_node( + initializer.syntax().clone(), + ast.initializer().unwrap().syntax().clone(), + ); + builder.map_node(diverging.syntax().clone(), ast.let_else().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn type_arg(&self, ty: ast::Type) -> ast::TypeArg { let ast = make::type_arg(ty.clone()).clone_for_update(); From 1b3374fb820aea675770223bcd398550f42d9553 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 28 Mar 2025 03:15:10 +0530 Subject: [PATCH 054/302] fix: migrate `unmerge_use` to syntax editor Also ensures that attributes on the use item are applied to the new use item when unmerging. Signed-off-by: Prajwal S N --- .../ide-assists/src/handlers/unmerge_use.rs | 59 ++++++++++++++----- .../src/ast/syntax_factory/constructors.rs | 14 +++++ .../crates/syntax/src/syntax_editor.rs | 1 + .../crates/syntax/src/syntax_editor/edits.rs | 50 +++++++++++++++- 4 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs index 805a7344494a..558e6e0697ea 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs @@ -1,7 +1,10 @@ use syntax::{ AstNode, SyntaxKind, - ast::{self, HasVisibility, edit_in_place::Removable, make}, - ted::{self, Position}, + ast::{ + self, HasAttrs, HasVisibility, edit::IndentLevel, edit_in_place::AttrsOwnerEdit, make, + syntax_factory::SyntaxFactory, + }, + syntax_editor::{Element, Position, Removable}, }; use crate::{ @@ -22,7 +25,7 @@ use crate::{ // use std::fmt::Display; // ``` pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let tree: ast::UseTree = ctx.find_node_at_offset::()?.clone_for_update(); + let tree = ctx.find_node_at_offset::()?; let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; if tree_list.use_trees().count() < 2 { @@ -30,12 +33,9 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< return None; } - let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; + let use_ = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; let path = resolve_full_path(&tree)?; - let old_parent_range = use_.syntax().parent()?.text_range(); - let new_parent = use_.syntax().parent()?; - // If possible, explain what is going to be done. let label = match tree.path().and_then(|path| path.first_segment()) { Some(name) => format!("Unmerge use of `{name}`"), @@ -44,16 +44,30 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< let target = tree.syntax().text_range(); acc.add(AssistId::refactor_rewrite("unmerge_use"), label, target, |builder| { - let new_use = make::use_( + let make = SyntaxFactory::with_mappings(); + let new_use = make.use_( use_.visibility(), - make::use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()), - ) - .clone_for_update(); + make.use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()), + ); + // Add any attributes that are present on the use tree + use_.attrs().for_each(|attr| { + new_use.add_attr(attr.clone_for_update()); + }); - tree.remove(); - ted::insert(Position::after(use_.syntax()), new_use.syntax()); - - builder.replace(old_parent_range, new_parent.to_string()); + let mut editor = builder.make_editor(use_.syntax()); + // Remove the use tree from the current use item + tree.remove(&mut editor); + // Insert a newline and indentation, followed by the new use item + editor.insert_all( + Position::after(use_.syntax()), + vec![ + make.whitespace(&format!("\n{}", IndentLevel::from_node(use_.syntax()))) + .syntax_element(), + new_use.syntax().syntax_element(), + ], + ); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } @@ -230,4 +244,19 @@ pub use std::fmt::Display; use std::process;", ); } + + #[test] + fn unmerge_use_item_with_attributes() { + check_assist( + unmerge_use, + r" +#[allow(deprecated)] +use foo::{bar, baz$0};", + r" +#[allow(deprecated)] +use foo::{bar}; +#[allow(deprecated)] +use foo::baz;", + ); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 1854000d3db2..1894a3218f85 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -107,6 +107,20 @@ impl SyntaxFactory { ast } + pub fn use_(&self, visibility: Option, use_tree: ast::UseTree) -> ast::Use { + make::use_(visibility, use_tree).clone_for_update() + } + + pub fn use_tree( + &self, + path: ast::Path, + use_tree_list: Option, + alias: Option, + add_star: bool, + ) -> ast::UseTree { + make::use_tree(path, use_tree_list, alias, add_star).clone_for_update() + } + pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path { let ast = make::path_unqualified(segment.clone()).clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 58200189c46b..31caf618be90 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -20,6 +20,7 @@ mod edit_algo; mod edits; mod mapping; +pub use edits::Removable; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 350cb3e2544f..d66ea8aa28cf 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -1,7 +1,8 @@ //! Structural editing for ast using `SyntaxEditor` use crate::{ - Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, + AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, + algo::neighbor, ast::{ self, AstNode, Fn, GenericParam, HasGenericParams, HasName, edit::IndentLevel, make, syntax_factory::SyntaxFactory, @@ -143,6 +144,53 @@ fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) -> Some(()) } +pub trait Removable: AstNode { + fn remove(&self, editor: &mut SyntaxEditor); +} + +impl Removable for ast::Use { + fn remove(&self, editor: &mut SyntaxEditor) { + let make = SyntaxFactory::without_mappings(); + + let next_ws = self + .syntax() + .next_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(next_ws) = next_ws { + let ws_text = next_ws.syntax().text(); + if let Some(rest) = ws_text.strip_prefix('\n') { + if rest.is_empty() { + editor.delete(next_ws.syntax()); + } else { + editor.replace(next_ws.syntax(), make.whitespace(rest)); + } + } + } + + editor.delete(self.syntax()); + } +} + +impl Removable for ast::UseTree { + fn remove(&self, editor: &mut SyntaxEditor) { + for dir in [Direction::Next, Direction::Prev] { + if let Some(next_use_tree) = neighbor(self, dir) { + let separators = self + .syntax() + .siblings_with_tokens(dir) + .skip(1) + .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); + for sep in separators { + editor.delete(sep); + } + break; + } + } + editor.delete(self.syntax()); + } +} + #[cfg(test)] mod tests { use parser::Edition; From 30eeab038115da3932a7932b82f14f0a563e6011 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 28 Mar 2025 15:12:21 +0530 Subject: [PATCH 055/302] chore: rename `unmerge_use` to `unmerge_imports` Signed-off-by: Prajwal S N --- .../{unmerge_use.rs => unmerge_imports.rs} | 56 +++++++++---------- .../crates/ide-assists/src/lib.rs | 4 +- .../crates/ide-assists/src/tests/generated.rs | 28 +++++----- 3 files changed, 44 insertions(+), 44 deletions(-) rename src/tools/rust-analyzer/crates/ide-assists/src/handlers/{unmerge_use.rs => unmerge_imports.rs} (82%) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs similarity index 82% rename from src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs rename to src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs index 558e6e0697ea..c066f41ca47b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs @@ -12,9 +12,9 @@ use crate::{ assist_context::{AssistContext, Assists}, }; -// Assist: unmerge_use +// Assist: unmerge_imports // -// Extracts single use item from use list. +// Extracts a use item from a use list into a standalone use list. // // ``` // use std::fmt::{Debug, Display$0}; @@ -24,12 +24,12 @@ use crate::{ // use std::fmt::{Debug}; // use std::fmt::Display; // ``` -pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn unmerge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let tree = ctx.find_node_at_offset::()?; let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; if tree_list.use_trees().count() < 2 { - cov_mark::hit!(skip_single_use_item); + cov_mark::hit!(skip_single_import); return None; } @@ -43,7 +43,7 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }; let target = tree.syntax().text_range(); - acc.add(AssistId::refactor_rewrite("unmerge_use"), label, target, |builder| { + acc.add(AssistId::refactor_rewrite("unmerge_imports"), label, target, |builder| { let make = SyntaxFactory::with_mappings(); let new_use = make.use_( use_.visibility(), @@ -94,22 +94,22 @@ mod tests { use super::*; #[test] - fn skip_single_use_item() { - cov_mark::check!(skip_single_use_item); + fn skip_single_import() { + cov_mark::check!(skip_single_import); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::Debug$0; ", ); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug$0}; ", ); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::Debug as Dbg$0; ", @@ -119,7 +119,7 @@ use std::fmt::Debug as Dbg$0; #[test] fn skip_single_glob_import() { check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::*$0; ", @@ -127,9 +127,9 @@ use std::fmt::*$0; } #[test] - fn unmerge_use_item() { + fn unmerge_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, Display$0}; ", @@ -140,7 +140,7 @@ use std::fmt::Display; ); check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, format$0, Display}; ", @@ -154,7 +154,7 @@ use std::fmt::format; #[test] fn unmerge_glob_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{*$0, Display}; ", @@ -166,9 +166,9 @@ use std::fmt::*; } #[test] - fn unmerge_renamed_use_item() { + fn unmerge_renamed_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, Display as Disp$0}; ", @@ -180,9 +180,9 @@ use std::fmt::Display as Disp; } #[test] - fn unmerge_indented_use_item() { + fn unmerge_indented_import() { check_assist( - unmerge_use, + unmerge_imports, r" mod format { use std::fmt::{Debug, Display$0 as Disp, format}; @@ -198,9 +198,9 @@ mod format { } #[test] - fn unmerge_nested_use_item() { + fn unmerge_nested_import() { check_assist( - unmerge_use, + unmerge_imports, r" use foo::bar::{baz::{qux$0, foobar}, barbaz}; ", @@ -210,7 +210,7 @@ use foo::bar::baz::qux; ", ); check_assist( - unmerge_use, + unmerge_imports, r" use foo::bar::{baz$0::{qux, foobar}, barbaz}; ", @@ -222,9 +222,9 @@ use foo::bar::baz::{qux, foobar}; } #[test] - fn unmerge_use_item_with_visibility() { + fn unmerge_import_with_visibility() { check_assist( - unmerge_use, + unmerge_imports, r" pub use std::fmt::{Debug, Display$0}; ", @@ -236,9 +236,9 @@ pub use std::fmt::Display; } #[test] - fn unmerge_use_item_on_self() { + fn unmerge_import_on_self() { check_assist( - unmerge_use, + unmerge_imports, r"use std::process::{Command, self$0};", r"use std::process::{Command}; use std::process;", @@ -246,9 +246,9 @@ use std::process;", } #[test] - fn unmerge_use_item_with_attributes() { + fn unmerge_import_with_attributes() { check_assist( - unmerge_use, + unmerge_imports, r" #[allow(deprecated)] use foo::{bar, baz$0};", diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index a157483a449c..627ed37b04e5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -222,8 +222,8 @@ mod handlers { mod toggle_async_sugar; mod toggle_ignore; mod toggle_macro_delimiter; + mod unmerge_imports; mod unmerge_match_arm; - mod unmerge_use; mod unnecessary_async; mod unqualify_method_call; mod unwrap_block; @@ -363,7 +363,7 @@ mod handlers { toggle_ignore::toggle_ignore, toggle_macro_delimiter::toggle_macro_delimiter, unmerge_match_arm::unmerge_match_arm, - unmerge_use::unmerge_use, + unmerge_imports::unmerge_imports, unnecessary_async::unnecessary_async, unqualify_method_call::unqualify_method_call, unwrap_block::unwrap_block, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 00a9d35c3107..54d060cc7909 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -3339,6 +3339,20 @@ sth!{ } ) } +#[test] +fn doctest_unmerge_imports() { + check_doc_test( + "unmerge_imports", + r#####" +use std::fmt::{Debug, Display$0}; +"#####, + r#####" +use std::fmt::{Debug}; +use std::fmt::Display; +"#####, + ) +} + #[test] fn doctest_unmerge_match_arm() { check_doc_test( @@ -3365,20 +3379,6 @@ fn handle(action: Action) { ) } -#[test] -fn doctest_unmerge_use() { - check_doc_test( - "unmerge_use", - r#####" -use std::fmt::{Debug, Display$0}; -"#####, - r#####" -use std::fmt::{Debug}; -use std::fmt::Display; -"#####, - ) -} - #[test] fn doctest_unnecessary_async() { check_doc_test( From 32bf2ac529495e105be95b82909a3105b3e4698e Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 28 Mar 2025 15:57:10 +0530 Subject: [PATCH 056/302] refactor: migrate `merge_imports` to syntax editor Co-authored-by: Tarek Signed-off-by: Prajwal S N --- .../ide-assists/src/handlers/merge_imports.rs | 70 +++++++------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index b7f7cb9cb01c..6bf7f5849148 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,14 +1,14 @@ use either::Either; use ide_db::imports::{ insert_use::{ImportGranularity, InsertUseConfig}, - merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees, try_normalize_use_tree}, + merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees}, }; -use itertools::Itertools; use syntax::{ AstNode, SyntaxElement, SyntaxNode, algo::neighbor, - ast::{self, edit_in_place::Removable}, - match_ast, ted, + ast::{self, syntax_factory::SyntaxFactory}, + match_ast, + syntax_editor::Removable, }; use crate::{ @@ -69,49 +69,32 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio (selection_range, edits?) }; - acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| { - let edits_mut: Vec = edits - .into_iter() - .map(|it| match it { - Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))), - Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))), - Replace(old, new) => Replace(builder.make_syntax_mut(old), new), - }) - .collect(); - for edit in edits_mut { - match edit { - Remove(it) => it.as_ref().either(Removable::remove, Removable::remove), - Replace(old, new) => { - ted::replace(old, &new); + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; - // If there's a selection and we're replacing a use tree in a tree list, - // normalize the parent use tree if it only contains the merged subtree. - if !ctx.has_empty_selection() { - let normalized_use_tree = ast::UseTree::cast(new) - .as_ref() - .and_then(ast::UseTree::parent_use_tree_list) - .and_then(|use_tree_list| { - if use_tree_list.use_trees().collect_tuple::<(_,)>().is_some() { - Some(use_tree_list.parent_use_tree()) - } else { - None - } - }) - .and_then(|target_tree| { - try_normalize_use_tree( - &target_tree, - ctx.config.insert_use.granularity.into(), - ) - .map(|top_use_tree_flat| (target_tree, top_use_tree_flat)) - }); - if let Some((old_tree, new_tree)) = normalized_use_tree { - cov_mark::hit!(replace_parent_with_normalized_use_tree); - ted::replace(old_tree.syntax(), new_tree.syntax()); - } + acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(&parent_node); + + for edit in edits { + match edit { + Remove(it) => { + let node = it.as_ref(); + if let Some(left) = node.left() { + left.remove(&mut editor); + } else if let Some(right) = node.right() { + right.remove(&mut editor); } } + Replace(old, new) => { + editor.replace(old, &new); + } } } + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } @@ -723,11 +706,10 @@ use std::{ ); cov_mark::check!(merge_with_selected_use_tree_neighbors); - cov_mark::check!(replace_parent_with_normalized_use_tree); check_assist( merge_imports, r"use std::$0{fmt::Display, fmt::Debug}$0;", - r"use std::fmt::{Debug, Display};", + r"use std::{fmt::{Debug, Display}};", ); } From 6c934f65640f4f6a4056f6f1e60c05be8bbcf21d Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Thu, 17 Apr 2025 12:11:13 +0200 Subject: [PATCH 057/302] Decouple SCC annotations from SCCs This rewires SCC annotations to have them be a separate, visitor-type data structure. It was broken out of #130227, which needed them to be able to remove unused annotations after computation without recomputing the SCCs themselves. As a drive-by it also removes some redundant code from the hot loop in SCC construction for a performance improvement. --- .../rustc_borrowck/src/constraints/mod.rs | 24 +-- .../rustc_borrowck/src/region_infer/mod.rs | 53 +++++- .../src/graph/scc/mod.rs | 132 ++++++------- .../src/graph/scc/tests.rs | 176 +++++++++++------- 4 files changed, 227 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index a52269df6828..514bbfe359b1 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; use tracing::{debug, instrument}; -use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker}; +use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations}; use crate::type_check::Locations; use crate::universal_regions::UniversalRegions; @@ -61,12 +61,14 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { &self, static_region: RegionVid, definitions: &IndexVec>, - ) -> ConstraintSccs { + ) -> AnnotatedSccs { let constraint_graph = self.graph(definitions.len()); let region_graph = &constraint_graph.region_graph(self, static_region); - ConstraintSccs::new_with_annotation(®ion_graph, |r| { - RegionTracker::new(r, &definitions[r]) - }) + let mut annotation_visitor = SccAnnotations::new(definitions); + ( + ConstraintSccs::new_with_annotation(®ion_graph, &mut annotation_visitor), + annotation_visitor.scc_to_annotation, + ) } /// This method handles Universe errors by rewriting the constraint @@ -79,12 +81,12 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { /// eventually go away. /// /// For a more precise definition, see the documentation for - /// [`RegionTracker::has_incompatible_universes()`]. + /// [`crate::region_infer::RegionTracker`]. /// /// This edge case used to be handled during constraint propagation /// by iterating over the strongly connected components in the constraint /// graph while maintaining a set of bookkeeping mappings similar - /// to what is stored in `RegionTracker` and manually adding 'sttaic as + /// to what is stored in `RegionTracker` and manually adding 'static as /// needed. /// /// It was rewritten as part of the Polonius project with the goal of moving @@ -108,9 +110,9 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { &mut self, universal_regions: &UniversalRegions<'tcx>, definitions: &IndexVec>, - ) -> ConstraintSccs { + ) -> AnnotatedSccs { let fr_static = universal_regions.fr_static; - let sccs = self.compute_sccs(fr_static, definitions); + let (sccs, annotations) = self.compute_sccs(fr_static, definitions); // Changed to `true` if we added any constraints to `self` and need to // recompute SCCs. @@ -124,7 +126,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { continue; } - let annotation = sccs.annotation(scc); + let annotation = annotations[scc]; // If this SCC participates in a universe violation, // e.g. if it reaches a region with a universe smaller than @@ -154,7 +156,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { self.compute_sccs(fr_static, definitions) } else { // If we didn't add any back-edges; no more work needs doing - sccs + (sccs, annotations) } } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c256051c122f..d483092d9b5a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -47,12 +47,13 @@ mod reverse_sccs; pub(crate) mod values; -pub(crate) type ConstraintSccs = Sccs; +pub(crate) type ConstraintSccs = Sccs; +pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec); /// An annotation for region graph SCCs that tracks -/// the values of its elements. +/// the values of its elements. This annotates a single SCC. #[derive(Copy, Debug, Clone)] -pub struct RegionTracker { +pub(crate) struct RegionTracker { /// The largest universe of a placeholder reached from this SCC. /// This includes placeholders within this SCC. max_placeholder_universe_reached: UniverseIndex, @@ -97,6 +98,31 @@ impl scc::Annotation for RegionTracker { } } +/// A Visitor for SCC annotation construction. +pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { + pub(crate) scc_to_annotation: IndexVec, + definitions: &'d IndexVec>, +} + +impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { + pub(crate) fn new(definitions: &'d IndexVec>) -> Self { + Self { scc_to_annotation: IndexVec::new(), definitions } + } +} + +impl scc::Annotations + for SccAnnotations<'_, '_, RegionTracker> +{ + fn new(&self, element: RegionVid) -> RegionTracker { + RegionTracker::new(element, &self.definitions[element]) + } + + fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { + let idx = self.scc_to_annotation.push(annotation); + assert!(idx == scc); + } +} + impl RegionTracker { pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { let (representative_is_placeholder, representative_is_existential) = match definition.origin @@ -166,6 +192,8 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: ConstraintSccs, + scc_annotations: IndexVec, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required /// to outlive a given SCC. Computed lazily. @@ -446,7 +474,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let definitions = create_definitions(infcx, &universal_regions); - let constraint_sccs = + let (constraint_sccs, scc_annotations) = outlives_constraints.add_outlives_static(&universal_regions, &definitions); let constraints = Frozen::freeze(outlives_constraints); let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); @@ -472,6 +500,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, + scc_annotations, rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), @@ -757,6 +786,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(value = ?self.scc_values.region_value_str(scc_a)); } + fn scc_annotations(&self) -> &IndexVec { + &self.scc_annotations + } + /// Invoked for each `R0 member of [R1..Rn]` constraint. /// /// `scc` is the SCC containing R0, and `choice_regions` are the @@ -798,7 +831,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.constraint_sccs().annotation(scc).min_universe().is_root() { + if !self.scc_annotations()[scc].min_universe().is_root() { return; } @@ -874,8 +907,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let a_annotation = self.constraint_sccs().annotation(scc_a); - let b_annotation = self.constraint_sccs().annotation(scc_b); + let a_annotation = self.scc_annotations()[scc_a]; + let b_annotation = self.scc_annotations()[scc_b]; let a_universe = a_annotation.min_universe(); // If scc_b's declared universe is a subset of @@ -991,7 +1024,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "lower_bound = {:?} r_scc={:?} universe={:?}", lower_bound, r_scc, - self.constraint_sccs.annotation(r_scc).min_universe() + self.scc_annotations()[r_scc].min_universe() ); // If the type test requires that `T: 'a` where `'a` is a // placeholder from another universe, that effectively requires @@ -1472,7 +1505,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The minimum universe of any variable reachable from this /// SCC, inside or outside of it. fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.constraint_sccs().annotation(scc).min_universe() + self.scc_annotations()[scc].min_universe() } /// Checks the final value for the free region `fr` to see if it @@ -2216,7 +2249,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// they *must* be equal (though not having the same repr does not /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { - self.constraint_sccs.annotation(scc).representative + self.scc_annotations()[scc].representative } pub(crate) fn liveness_constraints(&self) -> &LivenessValues { diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index e7c4ea3daae4..c0fe9e8ff93e 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -13,7 +13,7 @@ use std::fmt::Debug; use std::ops::Range; use rustc_index::{Idx, IndexSlice, IndexVec}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; @@ -48,6 +48,20 @@ pub trait Annotation: Debug + Copy { } } +/// An accumulator for annotations. +pub trait Annotations { + fn new(&self, element: N) -> A; + fn annotate_scc(&mut self, scc: S, annotation: A); +} + +/// The nil annotation accumulator, which does nothing. +impl Annotations for () { + fn new(&self, _element: N) -> () { + () + } + fn annotate_scc(&mut self, _scc: S, _annotation: ()) {} +} + /// The empty annotation, which does nothing. impl Annotation for () { fn merge_reached(self, _other: Self) -> Self { @@ -62,23 +76,20 @@ impl Annotation for () { /// the index type for the graph nodes and `S` is the index type for /// the SCCs. We can map from each node to the SCC that it /// participates in, and we also have the successors of each SCC. -pub struct Sccs { +pub struct Sccs { /// For each node, what is the SCC index of the SCC to which it /// belongs. scc_indices: IndexVec, /// Data about all the SCCs. - scc_data: SccData, + scc_data: SccData, } /// Information about an invidividual SCC node. -struct SccDetails { +struct SccDetails { /// For this SCC, the range of `all_successors` where its /// successors can be found. range: Range, - - /// User-specified metadata about the SCC. - annotation: A, } // The name of this struct should discourage you from making it public and leaking @@ -87,10 +98,10 @@ struct SccDetails { // is difficult when it's publicly inspectable. // // Obey the law of Demeter! -struct SccData { +struct SccData { /// Maps SCC indices to their metadata, including /// offsets into `all_successors`. - scc_details: IndexVec>, + scc_details: IndexVec, /// Contains the successors for all the Sccs, concatenated. The /// range of indices corresponding to a given SCC is found in its @@ -98,24 +109,18 @@ struct SccData { all_successors: Vec, } -impl Sccs { +impl Sccs { /// Compute SCCs without annotations. pub fn new(graph: &impl Successors) -> Self { - Self::new_with_annotation(graph, |_| ()) + Self::new_with_annotation(graph, &mut ()) } -} -impl Sccs { /// Compute SCCs and annotate them with a user-supplied annotation - pub fn new_with_annotation A>( + pub fn new_with_annotation>( graph: &impl Successors, - to_annotation: F, + annotations: &mut AA, ) -> Self { - SccsConstruction::construct(graph, to_annotation) - } - - pub fn annotation(&self, scc: S) -> A { - self.scc_data.annotation(scc) + SccsConstruction::construct(graph, annotations) } pub fn scc_indices(&self) -> &IndexSlice { @@ -136,7 +141,13 @@ impl Sccs { pub fn all_sccs(&self) -> impl Iterator + 'static { (0..self.scc_data.len()).map(S::new) } - + /* + /// Returns an iterator over the SCC annotations in the graph + /// The order is the same as `all_sccs()`, dependency order. + pub fn all_annotations(&self, annotations: &A) -> impl Iterator + use<'_, N, S, A> { + self.all_sccs().map(|scc| (scc, self.annotation(scc))) + } + */ /// Returns the SCC to which a node `r` belongs. pub fn scc(&self, r: N) -> S { self.scc_indices[r] @@ -160,7 +171,7 @@ impl Sccs { } } -impl DirectedGraph for Sccs { +impl DirectedGraph for Sccs { type Node = S; fn num_nodes(&self) -> usize { @@ -168,19 +179,19 @@ impl DirectedGraph for Sccs { } } -impl NumEdges for Sccs { +impl NumEdges for Sccs { fn num_edges(&self) -> usize { self.scc_data.all_successors.len() } } -impl Successors for Sccs { +impl Successors for Sccs { fn successors(&self, node: S) -> impl Iterator { self.successors(node).iter().cloned() } } -impl SccData { +impl SccData { /// Number of SCCs, fn len(&self) -> usize { self.scc_details.len() @@ -192,9 +203,8 @@ impl SccData { } /// Creates a new SCC with `successors` as its successors and - /// the maximum weight of its internal nodes `scc_max_weight` and /// returns the resulting index. - fn create_scc(&mut self, successors: impl IntoIterator, annotation: A) -> S { + fn create_scc(&mut self, successors: impl IntoIterator) -> S { // Store the successors on `scc_successors_vec`, remembering // the range of indices. let all_successors_start = self.all_successors.len(); @@ -202,28 +212,23 @@ impl SccData { let all_successors_end = self.all_successors.len(); debug!( - "create_scc({:?}) successors={:?}, annotation={:?}", + "create_scc({:?}) successors={:?}", self.len(), &self.all_successors[all_successors_start..all_successors_end], - annotation ); let range = all_successors_start..all_successors_end; - let metadata = SccDetails { range, annotation }; + let metadata = SccDetails { range }; self.scc_details.push(metadata) } - - fn annotation(&self, scc: S) -> A { - self.scc_details[scc].annotation - } } -struct SccsConstruction<'c, G, S, A, F> +struct SccsConstruction<'c, 'a, G, S, A, AA> where G: DirectedGraph + Successors, S: Idx, A: Annotation, - F: Fn(G::Node) -> A, + AA: Annotations, { graph: &'c G, @@ -247,11 +252,9 @@ where /// around between successors to amortize memory allocation costs. duplicate_set: FxHashSet, - scc_data: SccData, + scc_data: SccData, - /// A function that constructs an initial SCC annotation - /// out of a single node. - to_annotation: F, + annotations: &'a mut AA, } #[derive(Copy, Clone, Debug)] @@ -299,12 +302,12 @@ enum WalkReturn { Complete { scc_index: S, annotation: A }, } -impl<'c, G, S, A, F> SccsConstruction<'c, G, S, A, F> +impl<'c, 'a, G, S, A, AA> SccsConstruction<'c, 'a, G, S, A, AA> where G: DirectedGraph + Successors, S: Idx, - F: Fn(G::Node) -> A, A: Annotation, + AA: Annotations, { /// Identifies SCCs in the graph `G` and computes the resulting /// DAG. This uses a variant of [Tarjan's @@ -320,7 +323,7 @@ where /// Additionally, we keep track of a current annotation of the SCC. /// /// [wikipedia]: https://bit.ly/2EZIx84 - fn construct(graph: &'c G, to_annotation: F) -> Sccs { + fn construct(graph: &'c G, annotations: &'a mut AA) -> Sccs { let num_nodes = graph.num_nodes(); let mut this = Self { @@ -330,7 +333,7 @@ where successors_stack: Vec::new(), scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() }, duplicate_set: FxHashSet::default(), - to_annotation, + annotations, }; let scc_indices = graph @@ -408,7 +411,7 @@ where // a potentially derived version of the root state for non-root nodes in the chain. let (root_state, assigned_state) = { loop { - debug!("find_state(r = {node:?} in state {:?})", self.node_states[node]); + trace!("find_state(r = {node:?} in state {:?})", self.node_states[node]); match self.node_states[node] { // This must have been the first and only state since it is unexplored*; // no update needed! * Unless there is a bug :') @@ -482,7 +485,7 @@ where if previous_node == node { return root_state; } - debug!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}"); + trace!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}"); // Update to previous node in the link. match self.node_states[previous_node] { @@ -507,9 +510,9 @@ where /// Call this method when `inspect_node` has returned `None`. Having the /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. - #[instrument(skip(self, initial), level = "debug")] + #[instrument(skip(self, initial), level = "trace")] fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { - debug!("Walk unvisited node: {initial:?}"); + trace!("Walk unvisited node: {initial:?}"); struct VisitingNodeFrame { node: G::Node, successors: Option, @@ -537,7 +540,7 @@ where successors_len: 0, min_cycle_root: initial, successor_node: initial, - current_component_annotation: (self.to_annotation)(initial), + current_component_annotation: self.annotations.new(initial), }]; let mut return_value = None; @@ -556,11 +559,7 @@ where let node = *node; let depth = *depth; - // node is definitely in the current component, add it to the annotation. - if node != initial { - current_component_annotation.update_scc((self.to_annotation)(node)); - } - debug!( + trace!( "Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}" ); @@ -568,7 +567,7 @@ where Some(successors) => successors, None => { // This None marks that we still have the initialize this node's frame. - debug!(?depth, ?node); + trace!(?depth, ?node); debug_assert_matches!(self.node_states[node], NodeState::NotVisited); @@ -598,7 +597,7 @@ where return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); let successor_walk = successors.map(|successor_node| { - debug!(?node, ?successor_node); + trace!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); for (successor_node, walk) in returned_walk.chain(successor_walk) { @@ -609,13 +608,13 @@ where min_depth: successor_min_depth, annotation: successor_annotation, }) => { - debug!( + trace!( "Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}" ); // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < *min_depth { - debug!(?node, ?successor_min_depth); + trace!(?node, ?successor_min_depth); *min_depth = successor_min_depth; *min_cycle_root = successor_node; } @@ -627,20 +626,20 @@ where scc_index: successor_scc_index, annotation: successor_annotation, }) => { - debug!( + trace!( "Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}" ); // Push the completed SCC indices onto // the `successors_stack` for later. - debug!(?node, ?successor_scc_index); + trace!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); current_component_annotation.update_reachable(successor_annotation); } // `node` has no more (direct) successors; search recursively. None => { let depth = depth + 1; - debug!("Recursing down into {successor_node:?} at depth {depth:?}"); - debug!(?depth, ?successor_node); + trace!("Recursing down into {successor_node:?} at depth {depth:?}"); + trace!(?depth, ?successor_node); // Remember which node the return value will come from. frame.successor_node = successor_node; // Start a new stack frame, then step into it. @@ -652,14 +651,14 @@ where min_depth: depth, min_cycle_root: successor_node, successor_node, - current_component_annotation: (self.to_annotation)(successor_node), + current_component_annotation: self.annotations.new(successor_node), }); continue 'recurse; } } } - debug!("Finished walk from {node:?} with annotation: {current_component_annotation:?}"); + trace!("Finished walk from {node:?} with annotation: {current_component_annotation:?}"); // Completed walk, remove `node` from the stack. let r = self.node_stack.pop(); @@ -691,8 +690,9 @@ where debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node); - let scc_index = - self.scc_data.create_scc(deduplicated_successors, current_component_annotation); + let scc_index = self.scc_data.create_scc(deduplicated_successors); + + self.annotations.annotate_scc(scc_index, current_component_annotation); self.node_states[node] = NodeState::InCycle { scc_index, annotation: current_component_annotation }; diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 373f87bfdbcf..e388e7b6680a 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -5,8 +5,28 @@ use crate::graph::tests::TestGraph; #[derive(Copy, Clone, Debug)] struct MaxReached(usize); -type UsizeSccs = Sccs; -type MaxReachedSccs = Sccs; +struct Maxes(IndexVec, fn(usize) -> usize); +type UsizeSccs = Sccs; + +impl Annotations for Maxes { + fn new(&self, element: usize) -> MaxReached { + MaxReached(self.1(element)) + } + + fn annotate_scc(&mut self, scc: usize, annotation: MaxReached) { + let i = self.0.push(annotation); + assert!(i == scc); + } +} + +impl Maxes { + fn annotation(&self, scc: usize) -> MaxReached { + self.0[scc] + } + fn new(mapping: fn(usize) -> usize) -> Self { + Self(IndexVec::new(), mapping) + } +} impl Annotation for MaxReached { fn merge_scc(self, other: Self) -> Self { @@ -14,7 +34,7 @@ impl Annotation for MaxReached { } fn merge_reached(self, other: Self) -> Self { - self.merge_scc(other) + Self(std::cmp::max(other.0, self.0)) } } @@ -24,17 +44,29 @@ impl PartialEq for MaxReached { } } -impl MaxReached { - fn from_usize(nr: usize) -> Self { - Self(nr) - } -} - #[derive(Copy, Clone, Debug)] struct MinMaxIn { min: usize, max: usize, } +struct MinMaxes(IndexVec, fn(usize) -> MinMaxIn); + +impl MinMaxes { + fn annotation(&self, scc: usize) -> MinMaxIn { + self.0[scc] + } +} + +impl Annotations for MinMaxes { + fn new(&self, element: usize) -> MinMaxIn { + self.1(element) + } + + fn annotate_scc(&mut self, scc: usize, annotation: MinMaxIn) { + let i = self.0.push(annotation); + assert!(i == scc); + } +} impl Annotation for MinMaxIn { fn merge_scc(self, other: Self) -> Self { @@ -261,67 +293,68 @@ fn bench_sccc(b: &mut test::Bencher) { #[test] fn test_max_self_loop() { let graph = TestGraph::new(0, &[(0, 0)]); - let sccs: MaxReachedSccs = - Sccs::new_with_annotation(&graph, |n| if n == 0 { MaxReached(17) } else { MaxReached(0) }); - assert_eq!(sccs.annotation(0), 17); + let mut annotations = Maxes(IndexVec::new(), |n| if n == 0 { 17 } else { 0 }); + Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[0], 17); } #[test] fn test_max_branch() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 4)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.annotation(sccs.scc(0)), 4); - assert_eq!(sccs.annotation(sccs.scc(1)), 3); - assert_eq!(sccs.annotation(sccs.scc(2)), 4); -} -#[test] -fn test_single_cycle_max() { - let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.annotation(sccs.scc(2)), 4); - assert_eq!(sccs.annotation(sccs.scc(0)), 4); + let mut annotations = Maxes(IndexVec::new(), |n| n); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[sccs.scc(0)], 4); + assert_eq!(annotations.0[sccs.scc(1)], 3); + assert_eq!(annotations.0[sccs.scc(2)], 4); } #[test] -fn test_simple_cycle_max() { - let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 0)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.num_sccs(), 1); +fn test_single_cycle_max() { + let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]); + let mut annotations = Maxes(IndexVec::new(), |n| n); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[sccs.scc(2)], 4); + assert_eq!(annotations.0[sccs.scc(0)], 4); } #[test] fn test_double_cycle_max() { let graph = TestGraph::new(0, &[(0, 1), (1, 2), (1, 4), (2, 3), (2, 4), (3, 5), (4, 1), (5, 4)]); - let sccs: MaxReachedSccs = - Sccs::new_with_annotation(&graph, |n| if n == 5 { MaxReached(2) } else { MaxReached(1) }); + let mut annotations = Maxes(IndexVec::new(), |n| if n == 5 { 2 } else { 1 }); - assert_eq!(sccs.annotation(sccs.scc(0)).0, 2); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + + assert_eq!(annotations.0[sccs.scc(0)].0, 2); } #[test] fn test_bug_minimised() { let graph = TestGraph::new(0, &[(0, 3), (0, 1), (3, 2), (2, 3), (1, 4), (4, 5), (5, 4)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |n| match n { - 3 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes(IndexVec::new(), |n| match n { + 3 => 1, + _ => 0, }); - assert_eq!(sccs.annotation(sccs.scc(2)), 1); - assert_eq!(sccs.annotation(sccs.scc(1)), 0); - assert_eq!(sccs.annotation(sccs.scc(4)), 0); + + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.annotation(sccs.scc(2)), 1); + assert_eq!(annotations.annotation(sccs.scc(1)), 0); + assert_eq!(annotations.annotation(sccs.scc(4)), 0); } #[test] fn test_bug_max_leak_minimised() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 4 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes(IndexVec::new(), |w| match w { + 4 => 1, + _ => 0, }); - assert_eq!(sccs.annotation(sccs.scc(2)), 0); - assert_eq!(sccs.annotation(sccs.scc(3)), 1); - assert_eq!(sccs.annotation(sccs.scc(0)), 1); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + + assert_eq!(annotations.annotation(sccs.scc(2)), 0); + assert_eq!(annotations.annotation(sccs.scc(3)), 1); + assert_eq!(annotations.annotation(sccs.scc(0)), 1); } #[test] @@ -369,48 +402,49 @@ fn test_bug_max_leak() { (23, 24), ], ); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 22 => MaxReached(1), - 24 => MaxReached(2), - 27 => MaxReached(2), - _ => MaxReached(0), + let mut annotations = Maxes::new(|w| match w { + 22 => 1, + 24 => 2, + 27 => 2, + _ => 0, }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(2)), 0); - assert_eq!(sccs.annotation(sccs.scc(7)), 0); - assert_eq!(sccs.annotation(sccs.scc(8)), 2); - assert_eq!(sccs.annotation(sccs.scc(23)), 2); - assert_eq!(sccs.annotation(sccs.scc(3)), 2); - assert_eq!(sccs.annotation(sccs.scc(0)), 2); + assert_eq!(annotations.annotation(sccs.scc(2)), 0); + assert_eq!(annotations.annotation(sccs.scc(7)), 0); + assert_eq!(annotations.annotation(sccs.scc(8)), 2); + assert_eq!(annotations.annotation(sccs.scc(23)), 2); + assert_eq!(annotations.annotation(sccs.scc(3)), 2); + assert_eq!(annotations.annotation(sccs.scc(0)), 2); } #[test] fn test_bug_max_zero_stick_shape() { let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 2), (3, 4)]); - - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 4 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes::new(|w| match w { + 4 => 1, + _ => 0, }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(0)), 1); - assert_eq!(sccs.annotation(sccs.scc(1)), 1); - assert_eq!(sccs.annotation(sccs.scc(2)), 1); - assert_eq!(sccs.annotation(sccs.scc(3)), 1); - assert_eq!(sccs.annotation(sccs.scc(4)), 1); + assert_eq!(annotations.annotation(sccs.scc(0)), 1); + assert_eq!(annotations.annotation(sccs.scc(1)), 1); + assert_eq!(annotations.annotation(sccs.scc(2)), 1); + assert_eq!(annotations.annotation(sccs.scc(3)), 1); + assert_eq!(annotations.annotation(sccs.scc(4)), 1); } #[test] fn test_min_max_in() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3), (3, 5)]); - let sccs: Sccs = - Sccs::new_with_annotation(&graph, |w| MinMaxIn { min: w, max: w }); + let mut annotations = MinMaxes(IndexVec::new(), |w| MinMaxIn { min: w, max: w }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(2)).min, 2); - assert_eq!(sccs.annotation(sccs.scc(2)).max, 2); - assert_eq!(sccs.annotation(sccs.scc(0)).min, 0); - assert_eq!(sccs.annotation(sccs.scc(0)).max, 4); - assert_eq!(sccs.annotation(sccs.scc(3)).min, 0); - assert_eq!(sccs.annotation(sccs.scc(3)).max, 4); - assert_eq!(sccs.annotation(sccs.scc(5)).min, 5); + assert_eq!(annotations.annotation(sccs.scc(2)).min, 2); + assert_eq!(annotations.annotation(sccs.scc(2)).max, 2); + assert_eq!(annotations.annotation(sccs.scc(0)).min, 0); + assert_eq!(annotations.annotation(sccs.scc(0)).max, 4); + assert_eq!(annotations.annotation(sccs.scc(3)).min, 0); + assert_eq!(annotations.annotation(sccs.scc(3)).max, 4); + assert_eq!(annotations.annotation(sccs.scc(5)).min, 5); } From b660ab9f6978d2402c7e8f0f840bc17189365dd4 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Fri, 25 Apr 2025 14:29:21 +0200 Subject: [PATCH 058/302] Use associated types for SCC annotations, per code review suggestion --- .../rustc_borrowck/src/region_infer/mod.rs | 23 +++--- .../src/graph/scc/mod.rs | 70 +++++++++---------- .../src/graph/scc/tests.rs | 10 ++- 3 files changed, 51 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d483092d9b5a..b4ff3d66f3d5 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -110,9 +110,7 @@ impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { } } -impl scc::Annotations - for SccAnnotations<'_, '_, RegionTracker> -{ +impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { fn new(&self, element: RegionVid) -> RegionTracker { RegionTracker::new(element, &self.definitions[element]) } @@ -121,6 +119,9 @@ impl scc::Annotations let idx = self.scc_to_annotation.push(annotation); assert!(idx == scc); } + + type Ann = RegionTracker; + type SccIdx = ConstraintSccIndex; } impl RegionTracker { @@ -786,10 +787,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(value = ?self.scc_values.region_value_str(scc_a)); } - fn scc_annotations(&self) -> &IndexVec { - &self.scc_annotations - } - /// Invoked for each `R0 member of [R1..Rn]` constraint. /// /// `scc` is the SCC containing R0, and `choice_regions` are the @@ -831,7 +828,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.scc_annotations()[scc].min_universe().is_root() { + if !self.scc_universe(scc).is_root() { return; } @@ -907,8 +904,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let a_annotation = self.scc_annotations()[scc_a]; - let b_annotation = self.scc_annotations()[scc_b]; + let a_annotation = self.scc_annotations[scc_a]; + let b_annotation = self.scc_annotations[scc_b]; let a_universe = a_annotation.min_universe(); // If scc_b's declared universe is a subset of @@ -1024,7 +1021,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "lower_bound = {:?} r_scc={:?} universe={:?}", lower_bound, r_scc, - self.scc_annotations()[r_scc].min_universe() + self.scc_universe(r_scc) ); // If the type test requires that `T: 'a` where `'a` is a // placeholder from another universe, that effectively requires @@ -1505,7 +1502,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The minimum universe of any variable reachable from this /// SCC, inside or outside of it. fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.scc_annotations()[scc].min_universe() + self.scc_annotations[scc].min_universe() } /// Checks the final value for the free region `fr` to see if it @@ -2249,7 +2246,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// they *must* be equal (though not having the same repr does not /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { - self.scc_annotations()[scc].representative + self.scc_annotations[scc].representative } pub(crate) fn liveness_constraints(&self) -> &LivenessValues { diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index c0fe9e8ff93e..518817ea0f53 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -10,6 +10,7 @@ use std::assert_matches::debug_assert_matches; use std::fmt::Debug; +use std::marker::PhantomData; use std::ops::Range; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -49,16 +50,21 @@ pub trait Annotation: Debug + Copy { } /// An accumulator for annotations. -pub trait Annotations { - fn new(&self, element: N) -> A; - fn annotate_scc(&mut self, scc: S, annotation: A); +pub trait Annotations { + type Ann: Annotation; + type SccIdx: Idx + Ord; + + fn new(&self, element: N) -> Self::Ann; + fn annotate_scc(&mut self, scc: Self::SccIdx, annotation: Self::Ann); } /// The nil annotation accumulator, which does nothing. -impl Annotations for () { - fn new(&self, _element: N) -> () { - () - } +struct NoAnnotations(PhantomData); + +impl Annotations for NoAnnotations { + type SccIdx = S; + type Ann = (); + fn new(&self, _element: N) {} fn annotate_scc(&mut self, _scc: S, _annotation: ()) {} } @@ -112,13 +118,13 @@ struct SccData { impl Sccs { /// Compute SCCs without annotations. pub fn new(graph: &impl Successors) -> Self { - Self::new_with_annotation(graph, &mut ()) + Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::)) } /// Compute SCCs and annotate them with a user-supplied annotation - pub fn new_with_annotation>( + pub fn new_with_annotation>( graph: &impl Successors, - annotations: &mut AA, + annotations: &mut A, ) -> Self { SccsConstruction::construct(graph, annotations) } @@ -141,13 +147,7 @@ impl Sccs { pub fn all_sccs(&self) -> impl Iterator + 'static { (0..self.scc_data.len()).map(S::new) } - /* - /// Returns an iterator over the SCC annotations in the graph - /// The order is the same as `all_sccs()`, dependency order. - pub fn all_annotations(&self, annotations: &A) -> impl Iterator + use<'_, N, S, A> { - self.all_sccs().map(|scc| (scc, self.annotation(scc))) - } - */ + /// Returns the SCC to which a node `r` belongs. pub fn scc(&self, r: N) -> S { self.scc_indices[r] @@ -223,19 +223,17 @@ impl SccData { } } -struct SccsConstruction<'c, 'a, G, S, A, AA> +struct SccsConstruction<'c, 'a, G, A> where G: DirectedGraph + Successors, - S: Idx, - A: Annotation, - AA: Annotations, + A: Annotations, { graph: &'c G, /// The state of each node; used during walk to record the stack /// and after walk to record what cycle each node ended up being /// in. - node_states: IndexVec>, + node_states: IndexVec>, /// The stack of nodes that we are visiting as part of the DFS. node_stack: Vec, @@ -244,21 +242,21 @@ where /// position in this stack, and when we encounter a successor SCC, /// we push it on the stack. When we complete an SCC, we can pop /// everything off the stack that was found along the way. - successors_stack: Vec, + successors_stack: Vec, /// A set used to strip duplicates. As we accumulate successors /// into the successors_stack, we sometimes get duplicate entries. /// We use this set to remove those -- we also keep its storage /// around between successors to amortize memory allocation costs. - duplicate_set: FxHashSet, + duplicate_set: FxHashSet, - scc_data: SccData, + scc_data: SccData, - annotations: &'a mut AA, + annotations: &'a mut A, } #[derive(Copy, Clone, Debug)] -enum NodeState { +enum NodeState { /// This node has not yet been visited as part of the DFS. /// /// After SCC construction is complete, this state ought to be @@ -289,7 +287,7 @@ enum NodeState { /// The state of walking a given node. #[derive(Copy, Clone, Debug)] -enum WalkReturn { +enum WalkReturn { /// The walk found a cycle, but the entire component is not known to have /// been fully walked yet. We only know the minimum depth of this /// component in a minimum spanning tree of the graph. This component @@ -302,12 +300,10 @@ enum WalkReturn { Complete { scc_index: S, annotation: A }, } -impl<'c, 'a, G, S, A, AA> SccsConstruction<'c, 'a, G, S, A, AA> +impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A> where G: DirectedGraph + Successors, - S: Idx, - A: Annotation, - AA: Annotations, + A: Annotations, { /// Identifies SCCs in the graph `G` and computes the resulting /// DAG. This uses a variant of [Tarjan's @@ -323,7 +319,7 @@ where /// Additionally, we keep track of a current annotation of the SCC. /// /// [wikipedia]: https://bit.ly/2EZIx84 - fn construct(graph: &'c G, annotations: &'a mut AA) -> Sccs { + fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs { let num_nodes = graph.num_nodes(); let mut this = Self { @@ -349,7 +345,7 @@ where Sccs { scc_indices, scc_data: this.scc_data } } - fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { + fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node)) } @@ -365,7 +361,7 @@ where /// Otherwise, we are looking at a node that has already been /// completely visited. We therefore return `WalkReturn::Complete` /// with its associated SCC index. - fn inspect_node(&mut self, node: G::Node) -> Option> { + fn inspect_node(&mut self, node: G::Node) -> Option> { Some(match self.find_state(node) { NodeState::InCycle { scc_index, annotation } => { WalkReturn::Complete { scc_index, annotation } @@ -388,7 +384,7 @@ where /// of `r2` (and updates `r` to reflect current result). This is /// basically the "find" part of a standard union-find algorithm /// (with path compression). - fn find_state(&mut self, mut node: G::Node) -> NodeState { + fn find_state(&mut self, mut node: G::Node) -> NodeState { // To avoid recursion we temporarily reuse the `parent` of each // InCycleWith link to encode a downwards link while compressing // the path. After we have found the root or deepest node being @@ -511,7 +507,7 @@ where /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. #[instrument(skip(self, initial), level = "trace")] - fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { + fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { trace!("Walk unvisited node: {initial:?}"); struct VisitingNodeFrame { node: G::Node, diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index e388e7b6680a..8f04baf51f35 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -8,7 +8,7 @@ struct MaxReached(usize); struct Maxes(IndexVec, fn(usize) -> usize); type UsizeSccs = Sccs; -impl Annotations for Maxes { +impl Annotations for Maxes { fn new(&self, element: usize) -> MaxReached { MaxReached(self.1(element)) } @@ -17,6 +17,9 @@ impl Annotations for Maxes { let i = self.0.push(annotation); assert!(i == scc); } + + type Ann = MaxReached; + type SccIdx = usize; } impl Maxes { @@ -57,7 +60,7 @@ impl MinMaxes { } } -impl Annotations for MinMaxes { +impl Annotations for MinMaxes { fn new(&self, element: usize) -> MinMaxIn { self.1(element) } @@ -66,6 +69,9 @@ impl Annotations for MinMaxes { let i = self.0.push(annotation); assert!(i == scc); } + + type Ann = MinMaxIn; + type SccIdx = usize; } impl Annotation for MinMaxIn { From f479012d0ee77bb8a2a19f6ffb096860498ca5c2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 28 Apr 2025 17:16:28 +0200 Subject: [PATCH 059/302] refactor: De-arc lang item queries --- .../rust-analyzer/crates/hir-def/src/db.rs | 8 +- .../crates/hir-def/src/lang_item.rs | 199 ++++++++++-------- .../crates/hir-ty/src/autoderef.rs | 6 +- .../crates/hir-ty/src/chalk_db.rs | 24 +-- .../crates/hir-ty/src/chalk_ext.rs | 7 +- .../crates/hir-ty/src/diagnostics/expr.rs | 5 +- .../crates/hir-ty/src/display.rs | 14 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 7 +- .../crates/hir-ty/src/dyn_compatibility.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 4 +- .../crates/hir-ty/src/infer/coerce.rs | 9 +- .../crates/hir-ty/src/infer/mutability.rs | 12 +- .../crates/hir-ty/src/infer/unify.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 15 +- .../crates/hir-ty/src/mir/eval.rs | 25 +-- .../crates/hir-ty/src/mir/eval/shim.rs | 21 +- .../crates/hir-ty/src/mir/lower.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 11 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 3 +- .../rust-analyzer/crates/hir/src/display.rs | 3 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 54 ++--- .../crates/hir/src/source_analyzer.rs | 8 +- .../rust-analyzer/crates/ide/src/hover.rs | 4 +- 23 files changed, 194 insertions(+), 261 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 34cf42d02bdb..2cbdbe16f9bb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -22,7 +22,7 @@ use crate::{ hir::generics::GenericParams, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, - lang_item::{self, LangItem, LangItemTarget, LangItems}, + lang_item::{self, LangItem}, nameres::{ DefMap, LocalDefMap, assoc::{ImplItems, TraitItems}, @@ -325,9 +325,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // endregion:attrs - #[salsa::invoke(LangItems::lang_item_query)] - fn lang_item(&self, start_crate: Crate, item: LangItem) -> Option; - #[salsa::invoke(ImportMap::import_map_query)] fn import_map(&self, krate: Crate) -> Arc; @@ -349,9 +346,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // endregion:visibilities - #[salsa::invoke(LangItems::crate_lang_items_query)] - fn crate_lang_items(&self, krate: Crate) -> Option>; - #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>; #[salsa::invoke(crate::lang_item::crate_notable_traits)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 5431ec9679c5..6a4ac199b340 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -83,6 +83,91 @@ impl LangItemTarget { } } +/// Salsa query. This will look for lang items in a specific crate. +#[salsa::tracked(return_ref)] +pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { + let _p = tracing::info_span!("crate_lang_items_query").entered(); + + let mut lang_items = LangItems::default(); + + let crate_def_map = db.crate_def_map(krate); + + for (_, module_data) in crate_def_map.modules() { + for impl_def in module_data.scope.impls() { + lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); + for &(_, assoc) in db.impl_items(impl_def).items.iter() { + match assoc { + AssocItemId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function) + } + AssocItemId::TypeAliasId(t) => { + lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias) + } + AssocItemId::ConstId(_) => (), + } + } + } + + for def in module_data.scope.declarations() { + match def { + ModuleDefId::TraitId(trait_) => { + lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait); + db.trait_items(trait_).items.iter().for_each(|&(_, assoc_id)| match assoc_id { + AssocItemId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function); + } + AssocItemId::TypeAliasId(alias) => { + lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias) + } + AssocItemId::ConstId(_) => {} + }); + } + ModuleDefId::AdtId(AdtId::EnumId(e)) => { + lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); + db.enum_variants(e).variants.iter().for_each(|&(id, _)| { + lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); + }); + } + ModuleDefId::AdtId(AdtId::StructId(s)) => { + lang_items.collect_lang_item(db, s, LangItemTarget::Struct); + } + ModuleDefId::AdtId(AdtId::UnionId(u)) => { + lang_items.collect_lang_item(db, u, LangItemTarget::Union); + } + ModuleDefId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function); + } + ModuleDefId::StaticId(s) => { + lang_items.collect_lang_item(db, s, LangItemTarget::Static); + } + ModuleDefId::TypeAliasId(t) => { + lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias); + } + _ => {} + } + } + } + + if lang_items.items.is_empty() { None } else { Some(Box::new(lang_items)) } +} + +/// Salsa query. Look for a lang item, starting from the specified crate and recursively +/// traversing its dependencies. +#[salsa::tracked] +pub fn lang_item( + db: &dyn DefDatabase, + start_crate: Crate, + item: LangItem, +) -> Option { + let _p = tracing::info_span!("lang_item_query").entered(); + if let Some(target) = + crate_lang_items(db, start_crate).as_ref().and_then(|it| it.items.get(&item).copied()) + { + return Some(target); + } + start_crate.data(db).dependencies.iter().find_map(|dep| lang_item(db, dep.crate_id, item)) +} + #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LangItems { items: FxHashMap, @@ -93,96 +178,6 @@ impl LangItems { self.items.get(&item).copied() } - /// Salsa query. This will look for lang items in a specific crate. - pub(crate) fn crate_lang_items_query( - db: &dyn DefDatabase, - krate: Crate, - ) -> Option> { - let _p = tracing::info_span!("crate_lang_items_query").entered(); - - let mut lang_items = LangItems::default(); - - let crate_def_map = db.crate_def_map(krate); - - for (_, module_data) in crate_def_map.modules() { - for impl_def in module_data.scope.impls() { - lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); - for &(_, assoc) in db.impl_items(impl_def).items.iter() { - match assoc { - AssocItemId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function) - } - AssocItemId::TypeAliasId(t) => { - lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias) - } - AssocItemId::ConstId(_) => (), - } - } - } - - for def in module_data.scope.declarations() { - match def { - ModuleDefId::TraitId(trait_) => { - lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait); - db.trait_items(trait_).items.iter().for_each( - |&(_, assoc_id)| match assoc_id { - AssocItemId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function); - } - AssocItemId::TypeAliasId(alias) => lang_items.collect_lang_item( - db, - alias, - LangItemTarget::TypeAlias, - ), - AssocItemId::ConstId(_) => {} - }, - ); - } - ModuleDefId::AdtId(AdtId::EnumId(e)) => { - lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_variants(e).variants.iter().for_each(|&(id, _)| { - lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); - }); - } - ModuleDefId::AdtId(AdtId::StructId(s)) => { - lang_items.collect_lang_item(db, s, LangItemTarget::Struct); - } - ModuleDefId::AdtId(AdtId::UnionId(u)) => { - lang_items.collect_lang_item(db, u, LangItemTarget::Union); - } - ModuleDefId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function); - } - ModuleDefId::StaticId(s) => { - lang_items.collect_lang_item(db, s, LangItemTarget::Static); - } - ModuleDefId::TypeAliasId(t) => { - lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias); - } - _ => {} - } - } - } - - if lang_items.items.is_empty() { None } else { Some(Arc::new(lang_items)) } - } - - /// Salsa query. Look for a lang item, starting from the specified crate and recursively - /// traversing its dependencies. - pub(crate) fn lang_item_query( - db: &dyn DefDatabase, - start_crate: Crate, - item: LangItem, - ) -> Option { - let _p = tracing::info_span!("lang_item_query").entered(); - if let Some(target) = - db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied()) - { - return Some(target); - } - start_crate.data(db).dependencies.iter().find_map(|dep| db.lang_item(dep.crate_id, item)) - } - fn collect_lang_item( &mut self, db: &dyn DefDatabase, @@ -269,18 +264,38 @@ macro_rules! language_item_table { } impl LangItem { + pub fn resolve_function(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_function()) + } + + pub fn resolve_trait(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_trait()) + } + + pub fn resolve_enum(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_enum()) + } + + pub fn resolve_type_alias( + self, + db: &dyn DefDatabase, + start_crate: Crate, + ) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_type_alias()) + } + /// Opposite of [`LangItem::name`] pub fn from_name(name: &hir_expand::name::Name) -> Option { Self::from_symbol(name.symbol()) } pub fn path(&self, db: &dyn DefDatabase, start_crate: Crate) -> Option { - let t = db.lang_item(start_crate, *self)?; + let t = lang_item(db, start_crate, *self)?; Some(Path::LangItem(t, None)) } pub fn ty_rel_path(&self, db: &dyn DefDatabase, start_crate: Crate, seg: Name) -> Option { - let t = db.lang_item(start_crate, *self)?; + let t = lang_item(db, start_crate, *self)?; Some(Path::LangItem(t, Some(seg))) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 711544545681..7acc9456ec9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -198,15 +198,13 @@ pub(crate) fn deref_by_trait( // blanked impl on `Deref`. #[expect(clippy::overly_complex_bool_expr)] if use_receiver_trait && false { - if let Some(receiver) = - db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait()) - { + if let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) { return Some(receiver); } } // Old rustc versions might not have `Receiver` trait. // Fallback to `Deref` if they don't - db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait()) + LangItem::Deref.resolve_trait(db, table.trait_env.krate) }; let trait_id = trait_id()?; let target = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 2aa9401eefa9..376daccbdae8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -16,7 +16,7 @@ use hir_def::{ AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId, hir::Movability, - lang_item::{LangItem, LangItemTarget}, + lang_item::LangItem, signatures::{ImplFlags, StructFlags, TraitFlags}, }; @@ -262,10 +262,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { well_known_trait: rust_ir::WellKnownTrait, ) -> Option> { let lang_attr = lang_item_from_well_known_trait(well_known_trait); - let trait_ = match self.db.lang_item(self.krate, lang_attr) { - Some(LangItemTarget::Trait(trait_)) => trait_, - _ => return None, - }; + let trait_ = lang_attr.resolve_trait(self.db, self.krate)?; Some(to_chalk_trait_id(trait_)) } @@ -306,11 +303,8 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { chalk_ir::Binders::new(binders, bound) } crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = self - .db - .lang_item(self.krate, LangItem::Future) - .and_then(|item| item.as_trait()) - .and_then(|trait_| { + if let Some((future_trait, future_output)) = + LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| { let alias = self .db .trait_items(trait_) @@ -338,10 +332,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { }); let mut binder = vec![]; binder.push(crate::wrap_empty_binders(impl_bound)); - let sized_trait = self - .db - .lang_item(self.krate, LangItem::Sized) - .and_then(|item| item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(self.db, self.krate); if let Some(sized_trait_) = sized_trait { let sized_bound = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(sized_trait_), @@ -660,9 +651,8 @@ pub(crate) fn associated_ty_data_query( } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = db - .lang_item(resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); + let sized_trait = + LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id); let sized_bound = sized_trait.into_iter().map(|sized_trait| { let trait_bound = rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 0f0cf6ae7ae6..aabc4c4234db 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -251,9 +251,7 @@ impl TyExt for Ty { match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { let krate = def.module(db).krate(); - if let Some(future_trait) = - db.lang_item(krate, LangItem::Future).and_then(|item| item.as_trait()) - { + if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { // This is only used by type walking. // Parameters will be walked outside, and projection predicate is not used. // So just provide the Future trait. @@ -364,8 +362,7 @@ impl TyExt for Ty { fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool { let crate_id = owner.module(db).krate(); - let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|it| it.as_trait()) - else { + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, crate_id) else { return false; }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 5e3d88058962..57106412765a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -482,9 +482,8 @@ struct FilterMapNextChecker { impl FilterMapNextChecker { fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self { // Find and store the FunctionIds for Iterator::filter_map and Iterator::next - let (next_function_id, filter_map_function_id) = match db - .lang_item(resolver.krate(), LangItem::IteratorNext) - .and_then(|it| it.as_function()) + let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext + .resolve_function(db, resolver.krate()) { Some(next_function_id) => ( Some(next_function_id), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f62e4bb4f806..e810467b994a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -19,7 +19,7 @@ use hir_def::{ hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_scope::ItemInNs, item_tree::FieldsShape, - lang_item::{LangItem, LangItemTarget}, + lang_item::LangItem, nameres::DefMap, signatures::VariantFields, type_ref::{ @@ -1348,9 +1348,8 @@ impl HirDisplay for Ty { )?; } ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => { - let future_trait = db - .lang_item(body.module(db).krate(), LangItem::Future) - .and_then(LangItemTarget::as_trait); + let future_trait = + LangItem::Future.resolve_trait(db, body.module(db).krate()); let output = future_trait.and_then(|t| { db.trait_items(t) .associated_type_by_name(&Name::new_symbol_root(sym::Output)) @@ -1728,9 +1727,7 @@ impl SizedByDefault { match self { Self::NotSized => false, Self::Sized { anchor } => { - let sized_trait = db - .lang_item(anchor, LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(db, anchor); Some(trait_) == sized_trait } } @@ -1895,8 +1892,7 @@ fn write_bounds_like_dyn_trait( write!(f, ">")?; } if let SizedByDefault::Sized { anchor } = default_sized { - let sized_trait = - f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(f.db, anchor); if !is_sized { if !first { write!(f, " + ")?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 9823c854d5b3..70763759ef0e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -19,9 +19,7 @@ fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool { AdtId::StructId(id) => db.lookup_intern_struct(id).container, AdtId::UnionId(id) => db.lookup_intern_union(id).container, }; - let Some(drop_trait) = - db.lang_item(module.krate(), LangItem::Drop).and_then(|it| it.as_trait()) - else { + let Some(drop_trait) = LangItem::Drop.resolve_trait(db, module.krate()) else { return false; }; let impls = match module.containing_block() { @@ -181,8 +179,7 @@ fn projection_has_drop_glue( } fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { - let Some(copy_trait) = db.lang_item(env.krate, LangItem::Copy).and_then(|it| it.as_trait()) - else { + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else { return false; }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 80b18473907d..fecaafb4c2e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -124,7 +124,7 @@ pub fn dyn_compatibility_of_trait_query( fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { let krate = def.module(db).krate(); - let Some(sized) = db.lang_item(krate, LangItem::Sized).and_then(|l| l.as_trait()) else { + let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else { return false; }; @@ -491,8 +491,8 @@ fn receiver_is_dispatchable( let krate = func.module(db).krate(); let traits = ( - db.lang_item(krate, LangItem::Unsize).and_then(|it| it.as_trait()), - db.lang_item(krate, LangItem::DispatchFromDyn).and_then(|it| it.as_trait()), + LangItem::Unsize.resolve_trait(db, krate), + LangItem::DispatchFromDyn.resolve_trait(db, krate), ); let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else { return false; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 790914fdaf2a..f0ec31db8bb9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -39,7 +39,7 @@ use hir_def::{ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, - lang_item::{LangItem, LangItemTarget}, + lang_item::{LangItem, LangItemTarget, lang_item}, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, signatures::{ConstSignature, StaticSignature}, @@ -1801,7 +1801,7 @@ impl<'a> InferenceContext<'a> { fn resolve_lang_item(&self, item: LangItem) -> Option { let krate = self.resolver.krate(); - self.db.lang_item(krate, item) + lang_item(self.db, krate, item) } fn resolve_output_on(&self, trait_: TraitId) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 847dd43a02d6..39bd90849fe8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -8,10 +8,7 @@ use std::iter; use chalk_ir::{BoundVar, Goal, Mutability, TyKind, TyVariableKind, cast::Cast}; -use hir_def::{ - hir::ExprId, - lang_item::{LangItem, LangItemTarget}, -}; +use hir_def::{hir::ExprId, lang_item::LangItem}; use stdx::always; use triomphe::Arc; @@ -701,8 +698,8 @@ impl InferenceTable<'_> { reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone()); let krate = self.trait_env.krate; - let coerce_unsized_trait = match self.db.lang_item(krate, LangItem::CoerceUnsized) { - Some(LangItemTarget::Trait(trait_)) => trait_, + let coerce_unsized_trait = match LangItem::CoerceUnsized.resolve_trait(self.db, krate) { + Some(trait_) => trait_, _ => return Err(TypeError), }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index cf0152ecd263..ac450c0b5591 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -126,10 +126,8 @@ impl InferenceContext<'_> { &Expr::Index { base, index } => { if mutability == Mutability::Mut { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { - if let Some(index_trait) = self - .db - .lang_item(self.table.trait_env.krate, LangItem::IndexMut) - .and_then(|l| l.as_trait()) + if let Some(index_trait) = + LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) { if let Some(index_fn) = self .db @@ -183,10 +181,8 @@ impl InferenceContext<'_> { let mut mutability = mutability; if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if mutability == Mutability::Mut { - if let Some(deref_trait) = self - .db - .lang_item(self.table.trait_env.krate, LangItem::DerefMut) - .and_then(|l| l.as_trait()) + if let Some(deref_trait) = + LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate) { let ty = self.result.type_of_expr.get(*expr); let is_mut_ptr = ty.is_some_and(|ty| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 60aa9b5a17a8..d921afeb9879 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -1024,11 +1024,7 @@ impl<'a> InferenceTable<'a> { } } - let Some(sized) = self - .db - .lang_item(self.trait_env.krate, LangItem::Sized) - .and_then(|sized| sized.as_trait()) - else { + let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else { return false; }; let sized_pred = WhereClause::Implemented(TraitRef { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index e4688d044e98..6d7e58bea6a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -590,10 +590,7 @@ impl<'a> TyLoweringContext<'a> { } } &TypeBound::Path(path, TraitBoundModifier::Maybe) => { - let sized_trait = self - .db - .lang_item(self.resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate()); // Don't lower associated type bindings as the only possible relaxed trait bound // `?Sized` has no of them. // If we got another trait here ignore the bound completely. @@ -736,10 +733,8 @@ impl<'a> TyLoweringContext<'a> { } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = ctx - .db - .lang_item(krate, LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); + let sized_trait = + LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id); let sized_clause = sized_trait.map(|trait_id| { let clause = WhereClause::Implemented(TraitRef { trait_id, @@ -1188,9 +1183,7 @@ fn implicitly_sized_clauses<'a, 'subst: 'a>( substitution: &'subst Substitution, resolver: &Resolver, ) -> Option + Captures<'a> + Captures<'subst>> { - let sized_trait = db - .lang_item(resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id))?; + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?; let trait_self_idx = trait_self_param_idx(db, def); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 386226b16d5d..286381ce99cf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -655,22 +655,15 @@ impl Evaluator<'_> { mir_or_dyn_index_cache: RefCell::new(Default::default()), unused_locals_store: RefCell::new(Default::default()), cached_ptr_size, - cached_fn_trait_func: db - .lang_item(crate_id, LangItem::Fn) - .and_then(|x| x.as_trait()) + cached_fn_trait_func: LangItem::Fn + .resolve_trait(db, crate_id) .and_then(|x| db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call))), - cached_fn_mut_trait_func: db - .lang_item(crate_id, LangItem::FnMut) - .and_then(|x| x.as_trait()) - .and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) - }), - cached_fn_once_trait_func: db - .lang_item(crate_id, LangItem::FnOnce) - .and_then(|x| x.as_trait()) - .and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once)) - }), + cached_fn_mut_trait_func: LangItem::FnMut.resolve_trait(db, crate_id).and_then(|x| { + db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) + }), + cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| { + db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once)) + }), }) } @@ -2811,7 +2804,7 @@ impl Evaluator<'_> { span: MirSpan, ) -> Result<()> { let Some(drop_fn) = (|| { - let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; + let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?; self.db.trait_items(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop)) })() else { // in some tests we don't have drop trait in minicore, and diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 4de44cfd02e9..26ef95d264be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -6,7 +6,6 @@ use std::cmp::{self, Ordering}; use chalk_ir::TyKind; use hir_def::{ builtin_type::{BuiltinInt, BuiltinUint}, - lang_item::LangItemTarget, resolver::HasResolver, }; use hir_expand::name::Name; @@ -156,8 +155,8 @@ impl Evaluator<'_> { if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) { let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db); - let Some(hir_def::lang_item::LangItemTarget::Function(const_panic_fmt)) = - self.db.lang_item(resolver.krate(), LangItem::ConstPanicFmt) + let Some(const_panic_fmt) = + LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate()) else { not_supported!("const_panic_fmt lang item not found or not a function"); }; @@ -1257,12 +1256,12 @@ impl Evaluator<'_> { let addr = tuple.interval.addr.offset(offset); args.push(IntervalAndTy::new(addr, field, self, locals)?); } - if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) { - if let Some(def) = target.as_trait().and_then(|it| { - self.db - .trait_items(it) - .method_by_name(&Name::new_symbol_root(sym::call_once)) - }) { + if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) { + if let Some(def) = self + .db + .trait_items(target) + .method_by_name(&Name::new_symbol_root(sym::call_once)) + { self.exec_fn_trait( def, &args, @@ -1376,9 +1375,7 @@ impl Evaluator<'_> { } } } - if let Some(LangItemTarget::EnumId(e)) = - self.db.lang_item(self.crate_id, LangItem::Ordering) - { + if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { let ty = self.db.ty(e.into()); let r = self .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 557027756f39..ebccb11ce0ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -13,7 +13,7 @@ use hir_def::{ Pat, PatId, RecordFieldPat, RecordLitField, }, item_tree::FieldsShape, - lang_item::{LangItem, LangItemTarget}, + lang_item::{LangItem, LangItemTarget, lang_item}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, }; use hir_expand::name::Name; @@ -1727,7 +1727,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn resolve_lang_item(&self, item: LangItem) -> Result { let crate_id = self.owner.module(self.db).krate(); - self.db.lang_item(crate_id, item).ok_or(MirLowerError::LangItemNotFound(item)) + lang_item(self.db, crate_id, item).ok_or(MirLowerError::LangItemNotFound(item)) } fn lower_block_to_place( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index a5c195d4086a..f9f8776cff7c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -8,10 +8,7 @@ use chalk_recursive::Cache; use chalk_solve::{Solver, logging_db::LoggingRustIrDatabase, rust_ir}; use base_db::Crate; -use hir_def::{ - BlockId, TraitId, - lang_item::{LangItem, LangItemTarget}, -}; +use hir_def::{BlockId, TraitId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use span::Edition; @@ -292,10 +289,6 @@ impl FnTrait { } pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { - let target = db.lang_item(krate, self.lang_item())?; - match target { - LangItemTarget::Trait(t) => Some(t), - _ => None, - } + self.lang_item().resolve_trait(db, krate) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 198f715a6db2..1e0ff423ded6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -36,8 +36,7 @@ use crate::{ pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator + '_ { [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce] .into_iter() - .filter_map(move |lang| db.lang_item(krate, lang)) - .flat_map(|it| it.as_trait()) + .filter_map(move |lang| lang.resolve_trait(db, krate)) } /// Returns an iterator over the direct super traits (including the trait itself). diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 53817f37aa66..124ab8e274af 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -516,8 +516,7 @@ impl HirDisplay for TypeParam { return Ok(()); } - let sized_trait = - f.db.lang_item(krate, LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(f.db, krate); let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() { WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait, _ => false, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 143c13069e42..c62e4cf4497d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -53,7 +53,6 @@ use hir_def::{ generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, - lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, per_ns::PerNs, @@ -781,7 +780,7 @@ impl Module { let drop_maybe_dangle = (|| { // FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper let trait_ = trait_?; - let drop_trait = db.lang_item(self.krate().into(), LangItem::Drop)?.as_trait()?; + let drop_trait = LangItem::Drop.resolve_trait(db, self.krate().into())?; if drop_trait != trait_.into() { return None; } @@ -2388,14 +2387,11 @@ impl Function { } let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false }; - let Some(future_trait_id) = - db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait()) + let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate) else { return false; }; - let Some(sized_trait_id) = - db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait()) - else { + let Some(sized_trait_id) = LangItem::Sized.resolve_trait(db, self.ty(db).env.krate) else { return false; }; @@ -2861,9 +2857,7 @@ pub struct Trait { impl Trait { pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option { - db.lang_item(krate.into(), LangItem::from_name(name)?) - .and_then(LangItemTarget::as_trait) - .map(Into::into) + LangItem::from_name(name)?.resolve_trait(db, krate.into()).map(Into::into) } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -4989,18 +4983,14 @@ impl Type { /// `std::future::Future` and returns the `Output` associated type. /// This function is used in `.await` syntax completion. pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option { - let trait_ = db - .lang_item(self.env.krate, LangItem::IntoFutureIntoFuture) - .and_then(|it| { - let into_future_fn = it.as_function()?; + let trait_ = LangItem::IntoFutureIntoFuture + .resolve_function(db, self.env.krate) + .and_then(|into_future_fn| { let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?; let into_future_trait = assoc_item.container_or_implemented_trait(db)?; Some(into_future_trait.id) }) - .or_else(|| { - let future_trait = db.lang_item(self.env.krate, LangItem::Future)?; - future_trait.as_trait() - })?; + .or_else(|| LangItem::Future.resolve_trait(db, self.env.krate))?; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; @@ -5015,14 +5005,13 @@ impl Type { /// This does **not** resolve `IntoFuture`, only `Future`. pub fn future_output(self, db: &dyn HirDatabase) -> Option { - let future_output = - db.lang_item(self.env.krate, LangItem::FutureOutput)?.as_type_alias()?; + let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?; self.normalize_trait_assoc_type(db, &[], future_output.into()) } /// This does **not** resolve `IntoIterator`, only `Iterator`. pub fn iterator_item(self, db: &dyn HirDatabase) -> Option { - let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?; + let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?; let iterator_item = db .trait_items(iterator_trait) .associated_type_by_name(&Name::new_symbol_root(sym::Item))?; @@ -5030,9 +5019,7 @@ impl Type { } pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool { - let Some(iterator_trait) = - db.lang_item(self.env.krate, LangItem::Iterator).and_then(|it| it.as_trait()) - else { + let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else { return false; }; let canonical_ty = @@ -5042,12 +5029,13 @@ impl Type { /// Resolves the projection `::IntoIter` and returns the resulting type pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option { - let trait_ = db.lang_item(self.env.krate, LangItem::IntoIterIntoIter).and_then(|it| { - let into_iter_fn = it.as_function()?; - let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; - let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; - Some(into_iter_trait.id) - })?; + let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then( + |into_iter_fn| { + let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; + let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; + Some(into_iter_trait.id) + }, + )?; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; @@ -5133,10 +5121,8 @@ impl Type { } pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { - let lang_item = db.lang_item(self.env.krate, LangItem::Copy); - let copy_trait = match lang_item { - Some(LangItemTarget::Trait(it)) => it, - _ => return false, + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else { + return false; }; self.impls_trait(db, copy_trait.into(), &[]) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 666efe8ec645..7d447116e088 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -556,8 +556,8 @@ impl SourceAnalyzer { } } - let future_trait = db.lang_item(self.resolver.krate(), LangItem::Future)?.as_trait()?; - let poll_fn = db.lang_item(self.resolver.krate(), LangItem::FuturePoll)?.as_function()?; + let future_trait = LangItem::Future.resolve_trait(db, self.resolver.krate())?; + let poll_fn = LangItem::FuturePoll.resolve_function(db, self.resolver.krate())?; // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself // doesn't have any generic parameters, so we skip building another subst for `poll()`. let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build(); @@ -666,7 +666,7 @@ impl SourceAnalyzer { ) -> Option { let ty = self.ty_of_expr(try_expr.expr()?)?; - let op_fn = db.lang_item(self.resolver.krate(), LangItem::TryTraitBranch)?.as_function()?; + let op_fn = LangItem::TryTraitBranch.resolve_function(db, self.resolver.krate())?; let op_trait = match op_fn.lookup(db).container { ItemContainerId::TraitId(id) => id, _ => return None, @@ -1425,7 +1425,7 @@ impl SourceAnalyzer { lang_trait: LangItem, method_name: &Name, ) -> Option<(TraitId, FunctionId)> { - let trait_id = db.lang_item(self.resolver.krate(), lang_trait)?.as_trait()?; + let trait_id = lang_trait.resolve_trait(db, self.resolver.krate())?; let fn_id = db.trait_items(trait_id).method_by_name(method_name)?; Some((trait_id, fn_id)) } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 2f2d2252f844..075afcec019f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -634,9 +634,7 @@ fn walk_and_push_ty( } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push_new_def(trait_.into()); } else if let Some(tp) = t.as_type_param(db) { - let sized_trait = db - .lang_item(t.krate(db).into(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(db, t.krate(db).into()); tp.trait_bounds(db) .into_iter() .filter(|&it| Some(it.into()) != sized_trait) From 2ac60bc0896b4edd09e192204e768ddbe715a573 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 26 Apr 2025 08:18:26 +0000 Subject: [PATCH 060/302] We always use the current item as parent, so no need to pass it --- compiler/rustc_ast_lowering/src/expr.rs | 3 +-- compiler/rustc_ast_lowering/src/lib.rs | 7 ++----- compiler/rustc_ast_lowering/src/pat.rs | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8e1a3cd14354..9f3aed9216c2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -492,9 +492,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut generic_args = ThinVec::new(); for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); + self.create_def(node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { AstP(Expr { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e14b4d6723f..b2a0b32fe261 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -494,12 +494,12 @@ enum GenericArgsMode { impl<'a, 'hir> LoweringContext<'a, 'hir> { fn create_def( &mut self, - parent: LocalDefId, node_id: ast::NodeId, name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { + let parent = self.current_hir_id_owner.def_id; debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), @@ -781,7 +781,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, kind, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( - self.current_hir_id_owner.def_id, param, Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, @@ -2107,8 +2106,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::ConstArgKind::Path(qpath) } else { // Construct an AnonConst where the expr is the "ty"'s path. - - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); let span = self.lower_span(span); @@ -2116,7 +2113,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index f94d788a9b0e..2c2bae0238fd 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -517,14 +517,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, base_type: Span, ) -> &'hir hir::ConstArg<'hir> { - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); // Add a definition for the in-band const def. // We're generating a range end that didn't exist in the AST, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let unstable_span = self.mark_span_with_reason( From f831670519586bca8093d0913861d06270c7dfac Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 28 Apr 2025 22:09:11 +0200 Subject: [PATCH 061/302] Use target-cpu=z13 on s390x codegen const vector test The default s390x cpu(z10) does not have vector support. Setting target-cpu at least to z13 enables vectorisation for s390x architecture and makes the test pass. --- tests/codegen/const-vector.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs index 1d4edc39b1c8..5a7a5433ffd7 100644 --- a/tests/codegen/const-vector.rs +++ b/tests/codegen/const-vector.rs @@ -1,4 +1,8 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ revisions: OPT0 OPT0_S390X +//@ [OPT0] ignore-s390x +//@ [OPT0_S390X] only-s390x +//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13 // This test checks that constants of SIMD type are passed as immediate vectors. // We ensure that both vector representations (struct with fields and struct wrapping array) work. From 833f526196fffb9fc3113886a313b15f4b388691 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 28 Apr 2025 11:37:33 -0700 Subject: [PATCH 062/302] base-db: add more details to panic --- .../rust-analyzer/crates/base-db/src/lib.rs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 7f7a712577e4..1d73ba804a68 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -57,7 +57,12 @@ pub struct Files { impl Files { pub fn file_text(&self, file_id: vfs::FileId) -> FileText { - *self.files.get(&file_id).expect("Unable to fetch file; this is a bug") + match self.files.get(&file_id) { + Some(text) => *text, + None => { + panic!("Unable to fetch file text for `vfs::FileId`: {:?}; this is a bug", file_id) + } + } } pub fn set_file_text(&self, db: &mut dyn SourceDatabase, file_id: vfs::FileId, text: &str) { @@ -93,10 +98,13 @@ impl Files { /// Source root of the file. pub fn source_root(&self, source_root_id: SourceRootId) -> SourceRootInput { - let source_root = self - .source_roots - .get(&source_root_id) - .expect("Unable to fetch source root id; this is a bug"); + let source_root = match self.source_roots.get(&source_root_id) { + Some(source_root) => source_root, + None => panic!( + "Unable to fetch `SourceRootInput` with `SourceRootId` ({:?}); this is a bug", + source_root_id + ), + }; *source_root } @@ -121,10 +129,13 @@ impl Files { } pub fn file_source_root(&self, id: vfs::FileId) -> FileSourceRootInput { - let file_source_root = self - .file_source_roots - .get(&id) - .expect("Unable to fetch FileSourceRootInput; this is a bug"); + let file_source_root = match self.file_source_roots.get(&id) { + Some(file_source_root) => file_source_root, + None => panic!( + "Unable to get `FileSourceRootInput` with `vfs::FileId` ({:?}); this is a bug", + id + ), + }; *file_source_root } From b15584b1a3882a3d21f65261ccb6331b62bf1c58 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 14 Mar 2025 22:49:08 +0100 Subject: [PATCH 063/302] shared-generics: Do not share instantiations that cannot be created outside of the current crate In Zed shared-generics loading takes up a significant chunk of time in incremental build, as rustc deserializes rmeta of all dependencies of a crate. I've recently realized that shared-generics includes all instantiations of some_generic_function in the following snippet: ```rs pub fn some_generic_function(_: impl Fn()) {} pub fn non_generic_function() { some_generic_function(|| {}); some_generic_function(|| {}); some_generic_function(|| {}); some_generic_function(|| {}); some_generic_function(|| {}); some_generic_function(|| {}); some_generic_function(|| {}); } ``` even though none of these instantiations can actually be created from outside of `non_generic_function`. This PR makes shared-generics account for visibilities of generic arguments; an item is only considered for exporting if it is reachable from the outside or if all of it's arguments are visible outside of the local crate. This PR reduces incremental build time for Zed (touch edito.rs scenario) from 12.4s to 10.4s. Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- .../src/back/symbol_export.rs | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index fd06c50eb814..0c07a204b6a3 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -164,10 +164,10 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } -fn exported_symbols_provider_local( - tcx: TyCtxt<'_>, +fn exported_symbols_provider_local<'tcx>( + tcx: TyCtxt<'tcx>, _: LocalCrate, -) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { +) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { if !tcx.sess.opts.output_types.should_codegen() { return &[]; } @@ -321,6 +321,38 @@ fn exported_symbols_provider_local( let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; + // Do not export symbols that cannot be instantiated by downstream crates. + let reachable_set = tcx.reachable_set(()); + let is_local_to_current_crate = |ty: Ty<'_>| { + let no_refs = ty.peel_refs(); + let root_def_id = match no_refs.kind() { + ty::Closure(closure, _) => *closure, + ty::FnDef(def_id, _) => *def_id, + ty::Coroutine(def_id, _) => *def_id, + ty::CoroutineClosure(def_id, _) => *def_id, + ty::CoroutineWitness(def_id, _) => *def_id, + _ => return false, + }; + let Some(root_def_id) = root_def_id.as_local() else { + return false; + }; + + let is_local = !reachable_set.contains(&root_def_id); + is_local + }; + + let is_instantiable_downstream = + |did: Option, generic_args: GenericArgsRef<'tcx>| { + generic_args + .types() + .chain(did.into_iter().map(move |did| tcx.type_of(did).skip_binder())) + .all(move |arg| { + arg.walk().all(|ty| { + ty.as_type().map_or(true, |ty| !is_local_to_current_crate(ty)) + }) + }) + }; + // The symbols created in this loop are sorted below it #[allow(rustc::potential_query_instability)] for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { @@ -349,7 +381,12 @@ fn exported_symbols_provider_local( match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { - if args.non_erasable_generics().next().is_some() { + let has_generics = args.non_erasable_generics().next().is_some(); + + let should_export = + has_generics && is_instantiable_downstream(Some(def), &args); + + if should_export { let symbol = ExportedSymbol::Generic(def, args); symbols.push(( symbol, @@ -364,14 +401,24 @@ fn exported_symbols_provider_local( MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => { // A little sanity-check assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); - symbols.push(( - ExportedSymbol::DropGlue(ty), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); + + // Drop glue did is always going to be non-local outside of libcore, thus we don't need to check it's locality (which includes invoking `type_of` query). + let should_export = match ty.kind() { + ty::Adt(_, args) => is_instantiable_downstream(None, args), + ty::Closure(_, args) => is_instantiable_downstream(None, args), + _ => true, + }; + + if should_export { + symbols.push(( + ExportedSymbol::DropGlue(ty), + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); + } } MonoItem::Fn(Instance { def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)), From ea6844560a0c281e52b16d8f8e3cf6e5463434dc Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 28 Apr 2025 20:14:58 -0400 Subject: [PATCH 064/302] Move `in_external_macro` to `SyntaxContext` --- compiler/rustc_span/src/hygiene.rs | 25 +++++++++++++++++++++++++ compiler/rustc_span/src/lib.rs | 21 +++------------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ab0a802dc7f7..b621920d62ba 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -41,6 +41,7 @@ use tracing::{debug, trace}; use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId}; use crate::edition::Edition; +use crate::source_map::SourceMap; use crate::symbol::{Symbol, kw, sym}; use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals}; @@ -907,6 +908,30 @@ impl SyntaxContext { pub fn edition(self) -> Edition { HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition) } + + /// Returns whether this context originates in a foreign crate's external macro. + /// + /// This is used to test whether a lint should not even begin to figure out whether it should + /// be reported on the current node. + pub fn in_external_macro(self, sm: &SourceMap) -> bool { + let expn_data = self.outer_expn_data(); + match expn_data.kind { + ExpnKind::Root + | ExpnKind::Desugaring( + DesugaringKind::ForLoop + | DesugaringKind::WhileLoop + | DesugaringKind::OpaqueTy + | DesugaringKind::Async + | DesugaringKind::Await, + ) => false, + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::Macro(MacroKind::Bang, _) => { + // Dummy span for the `def_site` means it's an external macro. + expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) + } + ExpnKind::Macro { .. } => true, // definitely a plugin + } + } } impl fmt::Debug for SyntaxContext { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index fccdaed21a20..79aede72a293 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -607,28 +607,13 @@ impl Span { !self.is_dummy() && sm.is_span_accessible(self) } - /// Returns whether `span` originates in a foreign crate's external macro. + /// Returns whether this span originates in a foreign crate's external macro. /// /// This is used to test whether a lint should not even begin to figure out whether it should /// be reported on the current node. + #[inline] pub fn in_external_macro(self, sm: &SourceMap) -> bool { - let expn_data = self.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Desugaring( - DesugaringKind::ForLoop - | DesugaringKind::WhileLoop - | DesugaringKind::OpaqueTy - | DesugaringKind::Async - | DesugaringKind::Await, - ) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::Macro(MacroKind::Bang, _) => { - // Dummy span for the `def_site` means it's an external macro. - expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) - } - ExpnKind::Macro { .. } => true, // definitely a plugin - } + self.ctxt().in_external_macro(sm) } /// Returns `true` if `span` originates in a derive-macro's expansion. From cff9efde748b6027fe9f135ddd5aaf8a3276601d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 22 Apr 2025 07:02:27 +0200 Subject: [PATCH 065/302] Add a jobserver proxy to ensure at least one token is always held --- .../rustc_data_structures/src/jobserver.rs | 94 ++++++++++++++++++- compiler/rustc_data_structures/src/marker.rs | 8 +- compiler/rustc_interface/src/interface.rs | 6 +- compiler/rustc_interface/src/passes.rs | 15 ++- compiler/rustc_interface/src/util.rs | 28 ++++-- compiler/rustc_middle/src/ty/context.rs | 5 + compiler/rustc_query_impl/src/plumbing.rs | 6 ++ compiler/rustc_query_system/src/query/job.rs | 11 ++- compiler/rustc_query_system/src/query/mod.rs | 3 + .../rustc_query_system/src/query/plumbing.rs | 2 +- 10 files changed, 149 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 1204f2d692d6..3ed1ea7543f4 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -1,7 +1,8 @@ -use std::sync::{LazyLock, OnceLock}; +use std::sync::{Arc, LazyLock, OnceLock}; pub use jobserver_crate::{Acquired, Client, HelperThread}; use jobserver_crate::{FromEnv, FromEnvErrorKind}; +use parking_lot::{Condvar, Mutex}; // We can only call `from_env_ext` once per process @@ -71,10 +72,93 @@ pub fn client() -> Client { GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).clone() } -pub fn acquire_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).acquire_raw().ok(); +struct ProxyData { + /// The number of tokens assigned to threads. + /// If this is 0, a single token is still assigned to this process, but is unused. + used: u16, + + /// The number of threads requesting a token + pending: u16, } -pub fn release_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).release_raw().ok(); +/// This is a jobserver proxy used to ensure that we hold on to at least one token. +pub struct Proxy { + client: Client, + data: Mutex, + + /// Threads which are waiting on a token will wait on this. + wake_pending: Condvar, + + helper: OnceLock, +} + +impl Proxy { + pub fn new() -> Arc { + let proxy = Arc::new(Proxy { + client: client(), + data: Mutex::new(ProxyData { used: 1, pending: 0 }), + wake_pending: Condvar::new(), + helper: OnceLock::new(), + }); + let proxy_ = Arc::clone(&proxy); + let helper = proxy + .client + .clone() + .into_helper_thread(move |token| { + if let Ok(token) = token { + let mut data = proxy_.data.lock(); + if data.pending > 0 { + // Give the token to a waiting thread + token.drop_without_releasing(); + assert!(data.used > 0); + data.used += 1; + data.pending -= 1; + proxy_.wake_pending.notify_one(); + } else { + // The token is no longer needed, drop it. + drop(data); + drop(token); + } + } + }) + .expect("failed to create helper thread"); + proxy.helper.set(helper).unwrap(); + proxy + } + + pub fn acquire_thread(&self) { + let mut data = self.data.lock(); + + if data.used == 0 { + // There was a free token around. This can + // happen when all threads release their token. + assert_eq!(data.pending, 0); + data.used += 1; + } else { + // Request a token from the helper thread. We can't directly use `acquire_raw` + // as we also need to be able to wait for the final token in the process which + // does not get a corresponding `release_raw` call. + self.helper.get().unwrap().request_token(); + data.pending += 1; + self.wake_pending.wait(&mut data); + } + } + + pub fn release_thread(&self) { + let mut data = self.data.lock(); + + if data.pending > 0 { + // Give the token to a waiting thread + data.pending -= 1; + self.wake_pending.notify_one(); + } else { + data.used -= 1; + + // Release the token unless it's the last one in the process + if data.used > 0 { + drop(data); + self.client.release_raw().ok(); + } + } + } } diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index dfd9bd320761..e0df1b232e13 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -59,8 +59,8 @@ macro_rules! already_send { // These structures are already `Send`. already_send!( [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File] - [rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread] + [crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); macro_rules! impl_dyn_send { @@ -134,8 +134,8 @@ macro_rules! already_sync { already_sync!( [std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8] [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File] - [jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap] + [crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); // Use portable AtomicU64 for targets without native 64-bit atomics diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 708fe23b7915..0178c1470fa2 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::jobserver; +use rustc_data_structures::jobserver::{self, Proxy}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_errors::registry::Registry; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; @@ -41,6 +41,7 @@ pub struct Compiler { pub codegen_backend: Box, pub(crate) override_queries: Option, pub(crate) current_gcx: CurrentGcx, + pub(crate) jobserver_proxy: Arc, } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. @@ -415,7 +416,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.opts.unstable_opts.threads, &config.extra_symbols, SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, - |current_gcx| { + |current_gcx, jobserver_proxy| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); @@ -511,6 +512,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend, override_queries: config.override_queries, current_gcx, + jobserver_proxy, }; // There are two paths out of `f`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 66d2a79b93a4..c95442d908d6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -7,6 +7,7 @@ use std::{env, fs, iter}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; @@ -841,12 +842,13 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( dyn for<'tcx> FnOnce( &'tcx Session, CurrentGcx, + Arc, &'tcx OnceLock>, &'tcx WorkerLocal>, &'tcx WorkerLocal>, F, ) -> T, - > = Box::new(move |sess, current_gcx, gcx_cell, arena, hir_arena, f| { + > = Box::new(move |sess, current_gcx, jobserver_proxy, gcx_cell, arena, hir_arena, f| { TyCtxt::create_global_ctxt( gcx_cell, sess, @@ -865,6 +867,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ), providers.hooks, current_gcx, + jobserver_proxy, |tcx| { let feed = tcx.create_crate_num(stable_crate_id).unwrap(); assert_eq!(feed.key(), LOCAL_CRATE); @@ -887,7 +890,15 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ) }); - inner(&compiler.sess, compiler.current_gcx.clone(), &gcx_cell, &arena, &hir_arena, f) + inner( + &compiler.sess, + compiler.current_gcx.clone(), + Arc::clone(&compiler.jobserver_proxy), + &gcx_cell, + &arena, + &hir_arena, + f, + ) } /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c3a939f1ab08..3a291bbe802d 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,11 +1,12 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; -use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, OnceLock}; use std::{env, iter, thread}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; @@ -113,7 +114,7 @@ fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize { }) } -fn run_in_thread_with_globals R + Send, R: Send>( +fn run_in_thread_with_globals) -> R + Send, R: Send>( thread_stack_size: usize, edition: Edition, sm_inputs: SourceMapInputs, @@ -139,7 +140,7 @@ fn run_in_thread_with_globals R + Send, R: Send>( edition, extra_symbols, Some(sm_inputs), - || f(CurrentGcx::new()), + || f(CurrentGcx::new(), Proxy::new()), ) }) .unwrap() @@ -152,7 +153,10 @@ fn run_in_thread_with_globals R + Send, R: Send>( }) } -pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals< + F: FnOnce(CurrentGcx, Arc) -> R + Send, + R: Send, +>( thread_builder_diag: &EarlyDiagCtxt, edition: Edition, threads: usize, @@ -162,8 +166,8 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, ) -> R { use std::process; + use rustc_data_structures::defer; use rustc_data_structures::sync::FromDyn; - use rustc_data_structures::{defer, jobserver}; use rustc_middle::ty::tls; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::{QueryContext, break_query_cycles}; @@ -178,11 +182,11 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, edition, sm_inputs, extra_symbols, - |current_gcx| { + |current_gcx, jobserver_proxy| { // Register the thread for use with the `WorkerLocal` type. registry.register(); - f(current_gcx) + f(current_gcx, jobserver_proxy) }, ); } @@ -190,10 +194,14 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, let current_gcx = FromDyn::from(CurrentGcx::new()); let current_gcx2 = current_gcx.clone(); + let proxy = Proxy::new(); + + let proxy_ = Arc::clone(&proxy); + let proxy__ = Arc::clone(&proxy); let builder = rayon_core::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) - .acquire_thread_handler(jobserver::acquire_thread) - .release_thread_handler(jobserver::release_thread) + .acquire_thread_handler(move || proxy_.acquire_thread()) + .release_thread_handler(move || proxy__.release_thread()) .num_threads(threads) .deadlock_handler(move || { // On deadlock, creates a new thread and forwards information in thread @@ -257,7 +265,7 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, }, // Run `f` on the first thread in the thread pool. move |pool: &rayon_core::ThreadPool| { - pool.install(|| f(current_gcx.into_inner())) + pool.install(|| f(current_gcx.into_inner(), proxy)) }, ) .unwrap() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1efd0d1d14be..eb12249882e7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -21,6 +21,7 @@ use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -1438,6 +1439,8 @@ pub struct GlobalCtxt<'tcx> { pub(crate) alloc_map: interpret::AllocMap<'tcx>, current_gcx: CurrentGcx, + + pub jobserver_proxy: Arc, } impl<'tcx> GlobalCtxt<'tcx> { @@ -1642,6 +1645,7 @@ impl<'tcx> TyCtxt<'tcx> { query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, current_gcx: CurrentGcx, + jobserver_proxy: Arc, f: impl FnOnce(TyCtxt<'tcx>) -> T, ) -> T { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { @@ -1676,6 +1680,7 @@ impl<'tcx> TyCtxt<'tcx> { data_layout, alloc_map: interpret::AllocMap::new(), current_gcx, + jobserver_proxy, }); // This is a separate function to work around a crash with parallel rustc (#135870) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 19ccc5587d6a..ea37dc5489bd 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -4,6 +4,7 @@ use std::num::NonZero; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; @@ -69,6 +70,11 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { impl<'tcx> QueryContext for QueryCtxt<'tcx> { type QueryInfo = QueryStackDeferred<'tcx>; + #[inline] + fn jobserver_proxy(&self) -> &Proxy { + &*self.jobserver_proxy + } + #[inline] fn next_job_id(self) -> QueryJobId { QueryJobId( diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index de35cd79ea27..6321abc5087f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use parking_lot::{Condvar, Mutex}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::jobserver; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; use rustc_session::Session; @@ -207,12 +206,13 @@ impl QueryLatch { /// Awaits for the query job to complete. pub(super) fn wait_on( &self, + qcx: impl QueryContext, query: Option, span: Span, ) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); - self.wait_on_inner(&waiter); + self.wait_on_inner(qcx, &waiter); // FIXME: Get rid of this lock. We have ownership of the QueryWaiter // although another thread may still have a Arc reference so we cannot // use Arc::get_mut @@ -224,7 +224,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Arc>) { + fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -237,11 +237,12 @@ impl QueryLatch { // we have to be in the `wait` call. This is ensured by the deadlock handler // getting the self.info lock. rayon_core::mark_blocked(); - jobserver::release_thread(); + let proxy = qcx.jobserver_proxy(); + proxy.release_thread(); waiter.condvar.wait(&mut info); // Release the lock before we potentially block in `acquire_thread` drop(info); - jobserver::acquire_thread(); + proxy.acquire_thread(); } } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ef21af7dafba..a87f598674e5 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -16,6 +16,7 @@ mod caches; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; @@ -151,6 +152,8 @@ pub enum QuerySideEffect { pub trait QueryContext: HasDepContext { type QueryInfo: Clone; + fn jobserver_proxy(&self) -> &Proxy; + fn next_job_id(self) -> QueryJobId; /// Get the query information from the TLS context. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6ea8e3b92008..3c1fc7317848 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -297,7 +297,7 @@ where // With parallel queries we might just have to wait on some other // thread. - let result = latch.wait_on(current, span); + let result = latch.wait_on(qcx, current, span); match result { Ok(()) => { From c519510c29eb6a46e2bebe4cb240f80785495583 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 28 Apr 2025 20:40:27 +0200 Subject: [PATCH 066/302] Delay checking of `#[rustc_no_implicit_autorefs]` for reason --- compiler/rustc_lint/src/autorefs.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 5dd26854c957..ddab13190beb 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -75,10 +75,9 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { _ => return, }, ExprKind::Index(base, _, _) => base, - ExprKind::MethodCall(_, inner, _, _) - if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) => - { + ExprKind::MethodCall(_, inner, _, _) => { + // PERF: Checking of `#[rustc_no_implicit_refs]` is deferred below + // because checking for attribute is a bit costly. inner } ExprKind::Field(inner, _) => inner, @@ -99,6 +98,14 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { peel_place_mappers(inner).kind // 1. Deref of a raw pointer. && typeck.expr_ty(dereferenced).is_raw_ptr() + // PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]` + && match expr.kind { + ExprKind::MethodCall(..) => matches!( + cx.typeck_results().type_dependent_def_id(expr.hir_id), + Some(def_id) if cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) + ), + _ => true, + } { cx.emit_span_lint( DANGEROUS_IMPLICIT_AUTOREFS, From d93d553a0ce1dde45fa5cebd111d41aa9c767d09 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Apr 2025 10:40:06 +0200 Subject: [PATCH 067/302] refactor: Clean up cache priming cancellation handling --- .../rust-analyzer/crates/hir/src/symbols.rs | 17 +++---- .../rust-analyzer/crates/ide-db/src/lib.rs | 10 +--- .../crates/ide-db/src/prime_caches.rs | 51 ++++++++++++++----- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 +- .../rust-analyzer/src/cli/analysis_stats.rs | 3 +- .../crates/rust-analyzer/src/discover.rs | 6 +-- .../rust-analyzer/crates/stdx/src/thread.rs | 2 + 7 files changed, 54 insertions(+), 39 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 3d944afb8b30..e87ab87407ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -13,13 +13,13 @@ use hir_def::{ use hir_expand::{HirFileId, name::Name}; use hir_ty::{ db::HirDatabase, - display::{DisplayTarget, HirDisplay, hir_display_with_store}, + display::{HirDisplay, hir_display_with_store}, }; use intern::Symbol; use rustc_hash::FxHashMap; use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast::HasName}; -use crate::{Module, ModuleDef, Semantics}; +use crate::{HasCrate, Module, ModuleDef, Semantics}; pub type FxIndexSet = indexmap::IndexSet>; @@ -66,7 +66,6 @@ pub struct SymbolCollector<'a> { symbols: FxIndexSet, work: Vec, current_container_name: Option, - display_target: DisplayTarget, } /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect @@ -78,10 +77,6 @@ impl<'a> SymbolCollector<'a> { symbols: Default::default(), work: Default::default(), current_container_name: None, - display_target: DisplayTarget::from_crate( - db, - *db.all_crates().last().expect("no crate graph present"), - ), } } @@ -93,8 +88,7 @@ impl<'a> SymbolCollector<'a> { pub fn collect(&mut self, module: Module) { let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered(); - tracing::info!(?module, "SymbolCollector::collect",); - self.display_target = module.krate().to_display_target(self.db); + tracing::info!(?module, "SymbolCollector::collect"); // The initial work is the root module we're collecting, additional work will // be populated as we traverse the module's definitions. @@ -321,7 +315,10 @@ impl<'a> SymbolCollector<'a> { let impl_data = self.db.impl_signature(impl_id); let impl_name = Some( hir_display_with_store(impl_data.self_ty, &impl_data.store) - .display(self.db, self.display_target) + .display( + self.db, + crate::Impl::from(impl_id).krate(self.db).to_display_target(self.db), + ) .to_smolstr(), ); self.with_container_name(impl_name, |s| { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index d3934e14abf9..a433f184e765 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -78,6 +78,8 @@ pub type FileRange = FileRangeWrapper; #[salsa::db] pub struct RootDatabase { + // FIXME: Revisit this commit now that we migrated to the new salsa, given we store arcs in this + // db directly now // We use `ManuallyDrop` here because every codegen unit that contains a // `&RootDatabase -> &dyn OtherDatabase` cast will instantiate its drop glue in the vtable, // which duplicates `Weak::drop` and `Arc::drop` tens of thousands of times, which makes @@ -234,14 +236,6 @@ impl RootDatabase { // ); // hir::db::BodyWithSourceMapQuery.in_db_mut(self).set_lru_capacity(2048); } - - pub fn snapshot(&self) -> Self { - Self { - storage: self.storage.clone(), - files: self.files.clone(), - crates_map: self.crates_map.clone(), - } - } } #[query_group::query_group] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index 17c3f75ce173..5e8d016bfb02 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -51,6 +51,7 @@ pub fn parallel_prime_caches( enum ParallelPrimeCacheWorkerProgress { BeginCrate { crate_id: Crate, crate_name: Symbol }, EndCrate { crate_id: Crate }, + Cancelled(Cancelled), } // We split off def map computation from other work, @@ -71,26 +72,32 @@ pub fn parallel_prime_caches( progress_sender .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?; - match kind { + let cancelled = Cancelled::catch(|| match kind { PrimingPhase::DefMap => _ = db.crate_def_map(crate_id), PrimingPhase::ImportMap => _ = db.import_map(crate_id), PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()), - } + }); - progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?; + match cancelled { + Ok(()) => progress_sender + .send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?, + Err(cancelled) => progress_sender + .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?, + } } Ok::<_, crossbeam_channel::SendError<_>>(()) }; for id in 0..num_worker_threads { - let worker = prime_caches_worker.clone(); - let db = db.snapshot(); - stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .allow_leak(true) .name(format!("PrimeCaches#{id}")) - .spawn(move || Cancelled::catch(|| worker(db.snapshot()))) + .spawn({ + let worker = prime_caches_worker.clone(); + let db = db.clone(); + move || worker(db) + }) .expect("failed to spawn thread"); } @@ -142,9 +149,14 @@ pub fn parallel_prime_caches( continue; } Err(crossbeam_channel::RecvTimeoutError::Disconnected) => { - // our workers may have died from a cancelled task, so we'll check and re-raise here. - db.unwind_if_revision_cancelled(); - break; + // all our workers have exited, mark us as finished and exit + cb(ParallelPrimeCachesProgress { + crates_currently_indexing: vec![], + crates_done, + crates_total: crates_done, + work_type: "Indexing", + }); + return; } }; match worker_progress { @@ -156,6 +168,10 @@ pub fn parallel_prime_caches( crates_to_prime.mark_done(crate_id); crates_done += 1; } + ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => { + // Cancelled::throw should probably be public + std::panic::resume_unwind(Box::new(cancelled)); + } }; let progress = ParallelPrimeCachesProgress { @@ -186,9 +202,14 @@ pub fn parallel_prime_caches( continue; } Err(crossbeam_channel::RecvTimeoutError::Disconnected) => { - // our workers may have died from a cancelled task, so we'll check and re-raise here. - db.unwind_if_revision_cancelled(); - break; + // all our workers have exited, mark us as finished and exit + cb(ParallelPrimeCachesProgress { + crates_currently_indexing: vec![], + crates_done, + crates_total: crates_done, + work_type: "Populating symbols", + }); + return; } }; match worker_progress { @@ -199,6 +220,10 @@ pub fn parallel_prime_caches( crates_currently_indexing.swap_remove(&crate_id); crates_done += 1; } + ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => { + // Cancelled::throw should probably be public + std::panic::resume_unwind(Box::new(cancelled)); + } }; let progress = ParallelPrimeCachesProgress { diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index e7f5fcbf69f3..aa525a86123d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -182,7 +182,7 @@ impl AnalysisHost { /// Returns a snapshot of the current state, which you can query for /// semantic information. pub fn analysis(&self) -> Analysis { - Analysis { db: self.db.snapshot() } + Analysis { db: self.db.clone() } } /// Applies changes to the current state of the world. If there are @@ -864,7 +864,7 @@ impl Analysis { where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - let snap = self.db.snapshot(); + let snap = self.db.clone(); Cancelled::catch(|| f(&snap)) } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index c50df4b6d45e..a1e4adf0844a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -701,10 +701,9 @@ impl flags::AnalysisStats { if self.parallel { let mut inference_sw = self.stop_watch(); - let snap = db.snapshot(); bodies .par_iter() - .map_with(snap, |snap, &body| { + .map_with(db.clone(), |snap, &body| { snap.body(body.into()); snap.infer(body.into()); }) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs index 67ddc41f3b21..24c433610f1a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs @@ -126,10 +126,8 @@ impl CargoParser for DiscoverProjectParser { Some(msg) } Err(err) => { - let err = DiscoverProjectData::Error { - error: format!("{:#?}\n{}", err, line), - source: None, - }; + let err = + DiscoverProjectData::Error { error: format!("{err:#?}\n{line}"), source: None }; Some(DiscoverProjectMessage::new(err)) } } diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread.rs b/src/tools/rust-analyzer/crates/stdx/src/thread.rs index 6c742fecf1b6..3d1453831269 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread.rs @@ -56,6 +56,8 @@ impl Builder { Self { inner: self.inner.stack_size(size), ..self } } + /// Whether dropping should detach the thread + /// instead of joining it. #[must_use] pub fn allow_leak(self, allow_leak: bool) -> Self { Self { allow_leak, ..self } From 9f4abd313dfe3fbb0984d79a4a232009c582e9f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2025 17:47:48 +0100 Subject: [PATCH 068/302] stabilize ptr::swap_nonoverlapping in const --- library/core/src/intrinsics/mod.rs | 1 - library/core/src/ptr/mod.rs | 37 ++++++++++++++++++- library/coretests/tests/lib.rs | 1 - library/coretests/tests/ptr.rs | 4 ++ tests/ui/consts/missing_span_in_backtrace.rs | 2 - .../consts/missing_span_in_backtrace.stderr | 12 +++--- 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c5d5bc000f1c..5649736e4049 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3320,7 +3320,6 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[inline] #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] -#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 445c789a7de2..aa103af93ffc 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1065,10 +1065,45 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// assert_eq!(x, [7, 8, 3, 4]); /// assert_eq!(y, [1, 2, 9]); /// ``` +/// +/// # Const evaluation limitations +/// +/// If this function is invoked during const-evaluation, the current implementation has a small (and +/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y` +/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may +/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the +/// future. +/// +/// The limitation is illustrated by the following example: +/// +/// ``` +/// use std::mem::size_of; +/// use std::ptr; +/// +/// const { unsafe { +/// const PTR_SIZE: usize = size_of::<*const i32>(); +/// let mut data1 = [0u8; PTR_SIZE]; +/// let mut data2 = [0u8; PTR_SIZE]; +/// // Store a pointer in `data1`. +/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42); +/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks. +/// // This call will fail, because the pointer in `data1` crosses the boundary +/// // between several of the 1-byte chunks that are being swapped here. +/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE); +/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size +/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between +/// // two chunks. +/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1); +/// // Read the pointer from `data2` and dereference it. +/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned(); +/// assert!(*ptr == 42); +/// } } +/// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] -#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")] +#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] +#[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { ub_checks::assert_unsafe_precondition!( check_library_ub, diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ef548971aafa..195fe3890dbc 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] -#![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 7d6e4eac1e21..bb60fb07468f 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -949,6 +949,10 @@ fn test_const_swap_ptr() { // Make sure they still work. assert!(*s1.0.ptr == 1); assert!(*s2.0.ptr == 666); + + // This is where we'd swap again using a `u8` type and a `count` of `size_of::()` if it + // were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple + // elements. }; } diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index c8c7453daa12..490eb57c24d4 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Z ui-testing=no - -#![feature(const_swap_nonoverlapping)] use std::{ mem::{self, MaybeUninit}, ptr, diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index aad3d76dd269..88b3e37bb84f 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/missing_span_in_backtrace.rs:16:9 + --> $DIR/missing_span_in_backtrace.rs:14:9 | -16 | / ptr::swap_nonoverlapping( -17 | | &mut ptr1 as *mut _ as *mut MaybeUninit, -18 | | &mut ptr2 as *mut _ as *mut MaybeUninit, -19 | | mem::size_of::<&i32>(), -20 | | ); +14 | / ptr::swap_nonoverlapping( +15 | | &mut ptr1 as *mut _ as *mut MaybeUninit, +16 | | &mut ptr2 as *mut _ as *mut MaybeUninit, +17 | | mem::size_of::<&i32>(), +18 | | ); | |_________^ unable to copy parts of a pointer from memory at ALLOC0 | note: inside `swap_nonoverlapping::>` From 97f0f68769f424b9149fc52225eb6fecaefe7808 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Apr 2025 10:49:41 +0200 Subject: [PATCH 069/302] Cleanup cfg check handling in expression store lowering --- .../rust-analyzer/crates/hir-def/src/attr.rs | 55 ++++-- .../crates/hir-def/src/expr_store/expander.rs | 18 +- .../crates/hir-def/src/expr_store/lower.rs | 93 ++++++----- .../hir-def/src/expr_store/lower/generics.rs | 2 +- .../crates/hir-def/src/item_tree.rs | 4 +- .../crates/hir-expand/src/attrs.rs | 158 +++++++++++------- .../crates/hir-expand/src/declarative.rs | 2 +- .../crates/ide-db/src/prime_caches.rs | 20 ++- .../crates/rust-analyzer/src/bin/main.rs | 6 +- .../rust-analyzer/src/cli/diagnostics.rs | 12 +- .../src/cli/unresolved_references.rs | 12 +- .../crates/rust-analyzer/src/command.rs | 8 +- .../crates/rust-analyzer/src/flycheck.rs | 8 +- .../rust-analyzer/tests/slow-tests/support.rs | 3 +- .../rust-analyzer/crates/stdx/src/thread.rs | 13 +- .../crates/stdx/src/thread/pool.rs | 5 +- .../crates/vfs-notify/src/lib.rs | 3 +- 17 files changed, 234 insertions(+), 188 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index a80313aba3e4..bb6222b1d464 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,6 +1,6 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{borrow::Cow, hash::Hash, ops}; +use std::{borrow::Cow, convert::identity, hash::Hash, ops}; use base_db::Crate; use cfg::{CfgExpr, CfgOptions}; @@ -8,6 +8,7 @@ use either::Either; use hir_expand::{ HirFileId, InFile, attrs::{Attr, AttrId, RawAttrs, collect_attrs}, + span_map::SpanMapRef, }; use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; @@ -45,8 +46,27 @@ impl Attrs { (**self).iter().find(|attr| attr.id == id) } - pub(crate) fn filter(db: &dyn DefDatabase, krate: Crate, raw_attrs: RawAttrs) -> Attrs { - Attrs(raw_attrs.filter(db, krate)) + pub(crate) fn expand_cfg_attr( + db: &dyn DefDatabase, + krate: Crate, + raw_attrs: RawAttrs, + ) -> Attrs { + Attrs(raw_attrs.expand_cfg_attr(db, krate)) + } + + pub(crate) fn is_cfg_enabled_for( + db: &dyn DefDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> Result<(), CfgExpr> { + RawAttrs::attrs_iter_expanded::(db, owner, span_map, cfg_options) + .filter_map(|attr| attr.cfg()) + .find_map(|cfg| match cfg_options.check(&cfg).is_none_or(identity) { + true => None, + false => Some(cfg), + }) + .map_or(Ok(()), Err) } } @@ -522,38 +542,41 @@ impl AttrsWithOwner { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id()) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id()) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id()) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id()) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } GenericParamId::LifetimeParamId(it) => { let src = it.parent.child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } }, AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), @@ -561,7 +584,7 @@ impl AttrsWithOwner { AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), }; - let attrs = raw_attrs.filter(db, def.krate(db)); + let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db)); Attrs(attrs) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index 7eec913dd654..d24f4b7028d7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -3,10 +3,11 @@ use std::mem; use base_db::Crate; +use cfg::CfgOptions; use drop_bomb::DropBomb; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, - attrs::RawAttrs, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, + eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, }; use span::{AstIdMap, Edition, SyntaxContext}; use syntax::ast::HasAttrs; @@ -64,22 +65,13 @@ impl Expander { } } - pub(super) fn attrs( - &self, - db: &dyn DefDatabase, - krate: Crate, - has_attrs: &dyn HasAttrs, - ) -> Attrs { - Attrs::filter(db, krate, RawAttrs::new(db, has_attrs, self.span_map.as_ref())) - } - pub(super) fn is_cfg_enabled( &self, db: &dyn DefDatabase, - krate: Crate, has_attrs: &dyn HasAttrs, - ) -> bool { - self.attrs(db, krate, has_attrs).is_cfg_enabled(krate.cfg_options(db)) + cfg_options: &CfgOptions, + ) -> Result<(), cfg::CfgExpr> { + Attrs::is_cfg_enabled_for(db, has_attrs, self.span_map.as_ref(), cfg_options) } pub(super) fn call_syntax_ctx(&self) -> SyntaxContext { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 7f907fdba8e3..50505d54ba2f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -7,6 +7,7 @@ mod path; use std::mem; +use cfg::CfgOptions; use either::Either; use hir_expand::{ HirFileId, InFile, Lookup, MacroDefId, @@ -81,8 +82,6 @@ pub(super) fn lower_body( // even though they should be the same. Also, when the body comes from multiple expansions, their // hygiene is different. - let krate = module.krate(); - let mut self_param = None; let mut source_map_self_param = None; let mut params = vec![]; @@ -100,9 +99,8 @@ pub(super) fn lower_body( // and skip the body. if skip_body { if let Some(param_list) = parameters { - if let Some(self_param_syn) = param_list - .self_param() - .filter(|self_param| collector.expander.is_cfg_enabled(db, krate, self_param)) + if let Some(self_param_syn) = + param_list.self_param().filter(|self_param| collector.check_cfg(self_param)) { let is_mutable = self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none(); @@ -119,10 +117,7 @@ pub(super) fn lower_body( source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn))); } - let count = param_list - .params() - .filter(|it| collector.expander.is_cfg_enabled(db, krate, it)) - .count(); + let count = param_list.params().filter(|it| collector.check_cfg(it)).count(); params = (0..count).map(|_| collector.missing_pat()).collect(); }; let body_expr = collector.missing_expr(); @@ -138,9 +133,7 @@ pub(super) fn lower_body( } if let Some(param_list) = parameters { - if let Some(self_param_syn) = - param_list.self_param().filter(|it| collector.expander.is_cfg_enabled(db, krate, it)) - { + if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) { let is_mutable = self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none(); let hygiene = self_param_syn @@ -157,7 +150,7 @@ pub(super) fn lower_body( } for param in param_list.params() { - if collector.expander.is_cfg_enabled(db, krate, ¶m) { + if collector.check_cfg(¶m) { let param_pat = collector.collect_pat_top(param.pat()); params.push(param_pat); } @@ -346,7 +339,7 @@ pub(crate) fn lower_function( collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| { if let Some(param_list) = fn_.value.param_list() { if let Some(param) = param_list.self_param() { - let enabled = collector.expander.is_cfg_enabled(db, module.krate(), ¶m); + let enabled = collector.check_cfg(¶m); if enabled { has_self_param = true; params.push(match param.ty() { @@ -381,7 +374,7 @@ pub(crate) fn lower_function( } let p = param_list .params() - .filter(|param| collector.expander.is_cfg_enabled(db, module.krate(), param)) + .filter(|param| collector.check_cfg(param)) .filter(|param| { let is_variadic = param.dotdotdot_token().is_some(); has_variadic |= is_variadic; @@ -441,6 +434,7 @@ pub(crate) fn lower_function( pub struct ExprCollector<'db> { db: &'db dyn DefDatabase, + cfg_options: &'db CfgOptions, expander: Expander, def_map: Arc, local_def_map: Arc, @@ -553,6 +547,7 @@ impl ExprCollector<'_> { let expander = Expander::new(db, current_file_id, &def_map); ExprCollector { db, + cfg_options: module.krate().cfg_options(db), module, def_map, local_def_map, @@ -1026,7 +1021,9 @@ impl ExprCollector<'_> { /// Returns `None` if and only if the expression is `#[cfg]`d out. fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { let syntax_ptr = AstPtr::new(&expr); - self.check_cfg(&expr)?; + if !self.check_cfg(&expr) { + return None; + } // FIXME: Move some of these arms out into separate methods for clarity Some(match expr { @@ -1114,6 +1111,7 @@ impl ExprCollector<'_> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { + // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c let is_rustc_box = { let attrs = e.attrs(); attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") @@ -1156,13 +1154,17 @@ impl ExprCollector<'_> { match_arm_list .arms() .filter_map(|arm| { - self.check_cfg(&arm).map(|()| MatchArm { - pat: self.collect_pat_top(arm.pat()), - expr: self.collect_expr_opt(arm.expr()), - guard: arm - .guard() - .map(|guard| self.collect_expr_opt(guard.condition())), - }) + if self.check_cfg(&arm) { + Some(MatchArm { + pat: self.collect_pat_top(arm.pat()), + expr: self.collect_expr_opt(arm.expr()), + guard: arm + .guard() + .map(|guard| self.collect_expr_opt(guard.condition())), + }) + } else { + None + } }) .collect() } else { @@ -1230,7 +1232,9 @@ impl ExprCollector<'_> { let fields = nfl .fields() .filter_map(|field| { - self.check_cfg(&field)?; + if !self.check_cfg(&field) { + return None; + } let name = field.field_name()?.as_name(); @@ -1483,7 +1487,9 @@ impl ExprCollector<'_> { } fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option { - self.check_cfg(expr)?; + if !self.check_cfg(expr) { + return None; + } let syntax_ptr = AstPtr::new(expr); let result = match expr { @@ -1558,7 +1564,9 @@ impl ExprCollector<'_> { let args = record_field_list .fields() .filter_map(|f| { - self.check_cfg(&f)?; + if !self.check_cfg(&f) { + return None; + } let field_expr = f.expr()?; let pat = self.collect_expr_as_pat(field_expr); let name = f.field_name()?.as_name(); @@ -2044,7 +2052,7 @@ impl ExprCollector<'_> { fn collect_stmt(&mut self, statements: &mut Vec, s: ast::Stmt) { match s { ast::Stmt::LetStmt(stmt) => { - if self.check_cfg(&stmt).is_none() { + if !self.check_cfg(&stmt) { return; } let pat = self.collect_pat_top(stmt.pat()); @@ -2059,7 +2067,7 @@ impl ExprCollector<'_> { ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); match &expr { - Some(expr) if self.check_cfg(expr).is_none() => return, + Some(expr) if !self.check_cfg(expr) => return, _ => (), } let has_semi = stmt.semicolon_token().is_some(); @@ -2074,7 +2082,7 @@ impl ExprCollector<'_> { } } ast::Stmt::Item(ast::Item::MacroDef(macro_)) => { - if self.check_cfg(¯o_).is_none() { + if !self.check_cfg(¯o_) { return; } let Some(name) = macro_.name() else { @@ -2086,7 +2094,7 @@ impl ExprCollector<'_> { self.collect_macro_def(statements, macro_id); } ast::Stmt::Item(ast::Item::MacroRules(macro_)) => { - if self.check_cfg(¯o_).is_none() { + if !self.check_cfg(¯o_) { return; } let Some(name) = macro_.name() else { @@ -2360,7 +2368,9 @@ impl ExprCollector<'_> { let args = record_pat_field_list .fields() .filter_map(|f| { - self.check_cfg(&f)?; + if !self.check_cfg(&f) { + return None; + } let ast_pat = f.pat()?; let pat = self.collect_pat(ast_pat, binding_list); let name = f.field_name()?.as_name(); @@ -2536,25 +2546,18 @@ impl ExprCollector<'_> { /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when /// not. - fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> { - let attrs = self.expander.attrs(self.db, self.module.krate(), owner); - match attrs.cfg() { - Some(cfg) => { - let cfg_options = self.module.krate().cfg_options(self.db); - - if cfg_options.check(&cfg) != Some(false) { - return Some(()); - } - + fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> bool { + let enabled = self.expander.is_cfg_enabled(self.db, owner, self.cfg_options); + match enabled { + Ok(()) => true, + Err(cfg) => { self.source_map.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode { node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())), cfg, - opts: cfg_options.clone(), + opts: self.cfg_options.clone(), }); - - None + false } - None => Some(()), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index 9485e703d9cb..42c85571f646 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -110,7 +110,7 @@ impl GenericParamsCollector { fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericParamList) { for generic_param in params.generic_params() { - let enabled = ec.expander.is_cfg_enabled(ec.db, ec.module.krate(), &generic_param); + let enabled = ec.check_cfg(&generic_param); if !enabled { continue; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 01d340cea6df..1b97eb72b6f2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -179,7 +179,7 @@ impl ItemTree { /// Returns the inner attributes of the source file. pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { - Attrs::filter( + Attrs::expand_cfg_attr( db, krate, self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(), @@ -191,7 +191,7 @@ impl ItemTree { } pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs { - Attrs::filter(db, krate, self.raw_attrs(of).clone()) + Attrs::expand_cfg_attr(db, krate, self.raw_attrs(of).clone()) } /// Returns a count of a few, expensive items. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 5dae27f7a16c..107316239809 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, fmt, ops}; use base_db::Crate; -use cfg::CfgExpr; +use cfg::{CfgExpr, CfgOptions}; use either::Either; use intern::{Interned, Symbol, sym}; @@ -14,11 +14,10 @@ use syntax::{AstNode, AstToken, SyntaxNode, ast, match_ast}; use syntax_bridge::{DocCommentDesugarMode, desugar_doc_comment_text, syntax_node_to_token_tree}; use triomphe::ThinArc; -use crate::name::Name; use crate::{ - InFile, db::ExpandDatabase, mod_path::ModPath, + name::Name, span_map::SpanMapRef, tt::{self, TopSubtree, token_to_literal}, }; @@ -49,29 +48,7 @@ impl RawAttrs { owner: &dyn ast::HasAttrs, span_map: SpanMapRef<'_>, ) -> Self { - let entries: Vec<_> = collect_attrs(owner) - .filter_map(|(id, attr)| match attr { - Either::Left(attr) => { - attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id)) - } - Either::Right(comment) => comment.doc_comment().map(|doc| { - let span = span_map.span_for_range(comment.syntax().text_range()); - let (text, kind) = - desugar_doc_comment_text(doc, DocCommentDesugarMode::ProcMacro); - Attr { - id, - input: Some(Box::new(AttrInput::Literal(tt::Literal { - symbol: text, - span, - kind, - suffix: None, - }))), - path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))), - ctxt: span.ctx, - } - }), - }) - .collect(); + let entries: Vec<_> = Self::attrs_iter::(db, owner, span_map).collect(); let entries = if entries.is_empty() { None @@ -82,12 +59,61 @@ impl RawAttrs { RawAttrs { entries } } - pub fn from_attrs_owner( + /// A [`RawAttrs`] that has its `#[cfg_attr(...)]` attributes expanded. + pub fn new_expanded( db: &dyn ExpandDatabase, - owner: InFile<&dyn ast::HasAttrs>, + owner: &dyn ast::HasAttrs, span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, ) -> Self { - Self::new(db, owner.value, span_map) + let entries: Vec<_> = + Self::attrs_iter_expanded::(db, owner, span_map, cfg_options).collect(); + + let entries = if entries.is_empty() { + None + } else { + Some(ThinArc::from_header_and_iter((), entries.into_iter())) + }; + + RawAttrs { entries } + } + + pub fn attrs_iter( + db: &dyn ExpandDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + ) -> impl Iterator { + collect_attrs(owner).filter_map(move |(id, attr)| match attr { + Either::Left(attr) => { + attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id)) + } + Either::Right(comment) if DESUGAR_COMMENTS => comment.doc_comment().map(|doc| { + let span = span_map.span_for_range(comment.syntax().text_range()); + let (text, kind) = desugar_doc_comment_text(doc, DocCommentDesugarMode::ProcMacro); + Attr { + id, + input: Some(Box::new(AttrInput::Literal(tt::Literal { + symbol: text, + span, + kind, + suffix: None, + }))), + path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))), + ctxt: span.ctx, + } + }), + Either::Right(_) => None, + }) + } + + pub fn attrs_iter_expanded( + db: &dyn ExpandDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> impl Iterator { + Self::attrs_iter::(db, owner, span_map) + .flat_map(|attr| attr.expand_cfg_attr(db, cfg_options)) } pub fn merge(&self, other: Self) -> Self { @@ -114,9 +140,8 @@ impl RawAttrs { } } - /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. - // FIXME: This should return a different type, signaling it was filtered? - pub fn filter(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs { + /// Processes `cfg_attr`s + pub fn expand_cfg_attr(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs { let has_cfg_attrs = self.iter().any(|attr| attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr)); if !has_cfg_attrs { @@ -126,37 +151,8 @@ impl RawAttrs { let cfg_options = krate.cfg_options(db); let new_attrs = self .iter() - .flat_map(|attr| -> SmallVec<[_; 1]> { - let is_cfg_attr = attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr); - if !is_cfg_attr { - return smallvec![attr.clone()]; - } - - let subtree = match attr.token_tree_value() { - Some(it) => it, - _ => return smallvec![attr.clone()], - }; - - let (cfg, parts) = match parse_cfg_attr_input(subtree) { - Some(it) => it, - None => return smallvec![attr.clone()], - }; - let index = attr.id; - let attrs = parts - .enumerate() - .take(1 << AttrId::CFG_ATTR_BITS) - .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx))); - - let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg); - let cfg = CfgExpr::parse(&cfg); - if cfg_options.check(&cfg) == Some(false) { - smallvec![] - } else { - cov_mark::hit!(cfg_attr_active); - - attrs.collect() - } - }) + .cloned() + .flat_map(|attr| attr.expand_cfg_attr(db, cfg_options)) .collect::>(); let entries = if new_attrs.is_empty() { None @@ -316,6 +312,42 @@ impl Attr { pub fn path(&self) -> &ModPath { &self.path } + + pub fn expand_cfg_attr( + self, + db: &dyn ExpandDatabase, + cfg_options: &CfgOptions, + ) -> impl IntoIterator { + let is_cfg_attr = self.path.as_ident().is_some_and(|name| *name == sym::cfg_attr); + if !is_cfg_attr { + return smallvec![self.clone()]; + } + + let subtree = match self.token_tree_value() { + Some(it) => it, + _ => return smallvec![self.clone()], + }; + + let (cfg, parts) = match parse_cfg_attr_input(subtree) { + Some(it) => it, + None => return smallvec![self.clone()], + }; + let index = self.id; + let attrs = parts + .enumerate() + .take(1 << AttrId::CFG_ATTR_BITS) + .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx))); + + let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg); + let cfg = CfgExpr::parse(&cfg); + if cfg_options.check(&cfg) == Some(false) { + smallvec![] + } else { + cov_mark::hit!(cfg_attr_active); + + attrs.collect::>() + } + } } impl Attr { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 1fa682ce3a2d..0d100c1364ab 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -82,7 +82,7 @@ impl DeclarativeMacroExpander { let transparency = |node| { // ... would be nice to have the item tree here - let attrs = RawAttrs::new(db, node, map.as_ref()).filter(db, def_crate); + let attrs = RawAttrs::new_expanded(db, node, map.as_ref(), def_crate.cfg_options(db)); match attrs .iter() .find(|it| { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index 5e8d016bfb02..cbe31405ab78 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -90,15 +90,17 @@ pub fn parallel_prime_caches( }; for id in 0..num_worker_threads { - stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .allow_leak(true) - .name(format!("PrimeCaches#{id}")) - .spawn({ - let worker = prime_caches_worker.clone(); - let db = db.clone(); - move || worker(db) - }) - .expect("failed to spawn thread"); + stdx::thread::Builder::new( + stdx::thread::ThreadIntent::Worker, + format!("PrimeCaches#{id}"), + ) + .allow_leak(true) + .spawn({ + let worker = prime_caches_worker.clone(); + let db = db.clone(); + move || worker(db) + }) + .expect("failed to spawn thread"); } (work_sender, progress_receiver) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ea5a5eaa6a44..4dba97c8ec49 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -182,10 +182,8 @@ fn with_extra_thread( thread_intent: stdx::thread::ThreadIntent, f: impl FnOnce() -> anyhow::Result<()> + Send + 'static, ) -> anyhow::Result<()> { - let handle = stdx::thread::Builder::new(thread_intent) - .name(thread_name.into()) - .stack_size(STACK_SIZE) - .spawn(f)?; + let handle = + stdx::thread::Builder::new(thread_intent, thread_name).stack_size(STACK_SIZE).spawn(f)?; handle.join()?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 7c4eeebdfa31..7b12cb14009f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -15,11 +15,13 @@ impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { const STACK_SIZE: usize = 1024 * 1024 * 8; - let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive) - .name("BIG_STACK_THREAD".into()) - .stack_size(STACK_SIZE) - .spawn(|| self.run_()) - .unwrap(); + let handle = stdx::thread::Builder::new( + stdx::thread::ThreadIntent::LatencySensitive, + "BIG_STACK_THREAD", + ) + .stack_size(STACK_SIZE) + .spawn(|| self.run_()) + .unwrap(); handle.join() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs index bca7c8a098c2..1d4fbb942235 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -15,11 +15,13 @@ impl flags::UnresolvedReferences { pub fn run(self) -> anyhow::Result<()> { const STACK_SIZE: usize = 1024 * 1024 * 8; - let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive) - .name("BIG_STACK_THREAD".into()) - .stack_size(STACK_SIZE) - .spawn(|| self.run_()) - .unwrap(); + let handle = stdx::thread::Builder::new( + stdx::thread::ThreadIntent::LatencySensitive, + "BIG_STACK_THREAD", + ) + .stack_size(STACK_SIZE) + .spawn(|| self.run_()) + .unwrap(); handle.join() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs index 0035d941e2c6..d6c80c399ba2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs @@ -148,10 +148,10 @@ impl CommandHandle { let stderr = child.0.stderr().take().unwrap(); let actor = CargoActor::::new(parser, sender, stdout, stderr); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("CommandHandle".to_owned()) - .spawn(move || actor.run()) - .expect("failed to spawn thread"); + let thread = + stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "CommandHandle") + .spawn(move || actor.run()) + .expect("failed to spawn thread"); Ok(CommandHandle { program, arguments, current_dir, child, thread, _phantom: PhantomData }) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 2778b311e1e3..fc312439d58c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -133,10 +133,10 @@ impl FlycheckHandle { let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path); let (sender, receiver) = unbounded::(); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("Flycheck".to_owned()) - .spawn(move || actor.run(receiver)) - .expect("failed to spawn thread"); + let thread = + stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, format!("Flycheck{id}")) + .spawn(move || actor.run(receiver)) + .expect("failed to spawn thread"); FlycheckHandle { id, sender, _thread: thread } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 3f97952365f3..7b5a53311217 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -298,8 +298,7 @@ impl Server { ) -> Server { let (connection, client) = Connection::memory(); - let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("test server".to_owned()) + let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "test server") .spawn(move || main_loop(config, connection).unwrap()) .expect("failed to spawn a thread"); diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread.rs b/src/tools/rust-analyzer/crates/stdx/src/thread.rs index 3d1453831269..a34e9e4a6551 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread.rs @@ -26,12 +26,12 @@ pub use pool::Pool; /// # Panics /// /// Panics if failed to spawn the thread. -pub fn spawn(intent: ThreadIntent, f: F) -> JoinHandle +pub fn spawn(intent: ThreadIntent, name: String, f: F) -> JoinHandle where F: (FnOnce() -> T) + Send + 'static, T: Send + 'static, { - Builder::new(intent).spawn(f).expect("failed to spawn thread") + Builder::new(intent, name).spawn(f).expect("failed to spawn thread") } pub struct Builder { @@ -42,13 +42,8 @@ pub struct Builder { impl Builder { #[must_use] - pub fn new(intent: ThreadIntent) -> Self { - Self { intent, inner: jod_thread::Builder::new(), allow_leak: false } - } - - #[must_use] - pub fn name(self, name: String) -> Self { - Self { inner: self.inner.name(name), ..self } + pub fn new(intent: ThreadIntent, name: impl Into) -> Self { + Self { intent, inner: jod_thread::Builder::new().name(name.into()), allow_leak: false } } #[must_use] diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs index 074cd747dacc..a8de4db624f1 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs @@ -50,10 +50,9 @@ impl Pool { let extant_tasks = Arc::new(AtomicUsize::new(0)); let mut handles = Vec::with_capacity(threads); - for _ in 0..threads { - let handle = Builder::new(INITIAL_INTENT) + for idx in 0..threads { + let handle = Builder::new(INITIAL_INTENT, format!("Worker{idx}",)) .stack_size(STACK_SIZE) - .name("Worker".into()) .allow_leak(true) .spawn({ let extant_tasks = Arc::clone(&extant_tasks); diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index e918fd0887db..a03337dbc51e 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -38,8 +38,7 @@ impl loader::Handle for NotifyHandle { fn spawn(sender: loader::Sender) -> NotifyHandle { let actor = NotifyActor::new(sender); let (sender, receiver) = unbounded::(); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("VfsLoader".to_owned()) + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "VfsLoader") .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); NotifyHandle { sender, _thread: thread } From 578ea26b8fdf67c830b8991051c1840ff0846e33 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 29 Apr 2025 11:47:37 +0200 Subject: [PATCH 070/302] mono collector: Reduce \# of locking while walking the graph While profiling Zed's dev build I've noticed that while most of the time `upstream_monomorphizations` takes a lot of time in monomorpization_collector, in some cases (e.g. build of `editor` itself) the rest of monomorphization_collector_graph_walk dominates it. Most of the time is spent in collect_items_rec. This PR aims to reduce the number of locks taking place; instead of locking output MonoItems once per children of current node, we do so once per *parent*. We also get to reuse locks for mentioned and used items. While this commit does not reduce Wall time of Zed's build, it does shave off `cargo build -j1` from 43s to 41.5s. --- compiler/rustc_monomorphize/src/collector.rs | 64 +++++++++++--------- compiler/rustc_monomorphize/src/lib.rs | 1 + 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 76dad6b35714..1e3744e19f54 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +use std::cell::OnceCell; use std::path::PathBuf; use rustc_attr_parsing::InlineAttr; @@ -348,6 +349,27 @@ impl<'tcx> Extend>> for MonoItems<'tcx> { } } +fn collect_items_root<'tcx>( + tcx: TyCtxt<'tcx>, + starting_item: Spanned>, + state: &SharedState<'tcx>, + recursion_limit: Limit, +) { + if !state.visited.lock_mut().insert(starting_item.node) { + // We've been here already, no need to search again. + return; + } + let mut recursion_depths = DefIdMap::default(); + collect_items_rec( + tcx, + starting_item, + state, + &mut recursion_depths, + recursion_limit, + CollectionMode::UsedItems, + ); +} + /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a /// post-monomorphization error is encountered during a collection step. /// @@ -362,24 +384,6 @@ fn collect_items_rec<'tcx>( recursion_limit: Limit, mode: CollectionMode, ) { - if mode == CollectionMode::UsedItems { - if !state.visited.lock_mut().insert(starting_item.node) { - // We've been here already, no need to search again. - return; - } - } else { - if state.visited.lock().contains(&starting_item.node) { - // We've already done a *full* visit on this one, no need to do the "mention" visit. - return; - } - if !state.mentioned.lock_mut().insert(starting_item.node) { - // We've been here already, no need to search again. - return; - } - // There's some risk that we first do a 'mention' visit and then a full visit. But there's no - // harm in that, the mention visit will trigger all the queries and the results are cached. - } - let mut used_items = MonoItems::new(); let mut mentioned_items = MonoItems::new(); let recursion_depth_reset; @@ -536,6 +540,20 @@ fn collect_items_rec<'tcx>( state.usage_map.lock_mut().record_used(starting_item.node, &used_items); } + { + let mut visited = OnceCell::default(); + if mode == CollectionMode::UsedItems { + used_items + .items + .retain(|k, _| visited.get_mut_or_init(|| state.visited.lock_mut()).insert(*k)); + } + + let mut mentioned = OnceCell::default(); + mentioned_items.items.retain(|k, _| { + !visited.get_or_init(|| state.visited.lock()).contains(k) + && mentioned.get_mut_or_init(|| state.mentioned.lock_mut()).insert(*k) + }); + } if mode == CollectionMode::MentionedItems { assert!(used_items.is_empty(), "'mentioned' collection should never encounter used items"); } else { @@ -1689,15 +1707,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>( tcx.sess.time("monomorphization_collector_graph_walk", || { par_for_each_in(roots, |root| { - let mut recursion_depths = DefIdMap::default(); - collect_items_rec( - tcx, - dummy_spanned(*root), - &state, - &mut recursion_depths, - recursion_limit, - CollectionMode::UsedItems, - ); + collect_items_root(tcx, dummy_spanned(*root), &state, recursion_limit); }); }); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8469e0f17a69..1b484da698aa 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -4,6 +4,7 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] +#![feature(once_cell_get_mut)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; From 08b27ffbe89c26d0307b524c4f920bcc704ba23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 29 Apr 2025 12:04:33 +0200 Subject: [PATCH 071/302] Add some comments --- compiler/rustc_interface/src/interface.rs | 4 ++++ compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_query_system/src/query/mod.rs | 2 ++ 3 files changed, 7 insertions(+) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 0178c1470fa2..cf494f8d686e 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -40,7 +40,11 @@ pub struct Compiler { pub sess: Session, pub codegen_backend: Box, pub(crate) override_queries: Option, + + /// A reference to the current `GlobalCtxt` which we pass on to `GlobalCtxt`. pub(crate) current_gcx: CurrentGcx, + + /// A jobserver reference which we pass on to `GlobalCtxt`. pub(crate) jobserver_proxy: Arc, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index eb12249882e7..a185b29092a1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1440,6 +1440,7 @@ pub struct GlobalCtxt<'tcx> { current_gcx: CurrentGcx, + /// A jobserver reference used to release then acquire a token while waiting on a query. pub jobserver_proxy: Arc, } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index a87f598674e5..855769dacc3e 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -152,6 +152,8 @@ pub enum QuerySideEffect { pub trait QueryContext: HasDepContext { type QueryInfo: Clone; + /// Gets a jobserver reference which is used to release then acquire + /// a token while waiting on a query. fn jobserver_proxy(&self) -> &Proxy; fn next_job_id(self) -> QueryJobId; From e561ec0e03c4991938e0d3d39766fa74d86f7448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 29 Apr 2025 12:59:15 +0200 Subject: [PATCH 072/302] Remove global `next_disambiguator` state and handle it with a `DisambiguatorState` type --- compiler/rustc_ast_lowering/src/lib.rs | 6 +- .../src/const_eval/dummy_machine.rs | 4 +- .../src/const_eval/machine.rs | 5 +- .../rustc_const_eval/src/interpret/intern.rs | 15 ++-- .../rustc_const_eval/src/interpret/util.rs | 5 +- compiler/rustc_hir/src/def.rs | 11 +-- compiler/rustc_hir/src/definitions.rs | 56 +++++++++++---- .../src/collect/resolve_bound_vars.rs | 30 +++++--- compiler/rustc_middle/src/ty/context.rs | 17 +++-- compiler/rustc_middle/src/ty/mod.rs | 3 + compiler/rustc_middle/src/ty/print/pretty.rs | 4 ++ .../src/coroutine/by_move_body.rs | 10 ++- compiler/rustc_resolve/src/lib.rs | 7 +- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 70 +++++++++++++------ tests/ui/delegation/unsupported.stderr | 8 +-- .../impl-trait/in-trait/doesnt-satisfy.stderr | 4 +- tests/ui/impl-trait/in-trait/dump.rs | 2 +- tests/ui/impl-trait/in-trait/dump.stderr | 2 +- ...atability-via-leakage-cycle.current.stderr | 4 +- ...ompatability-via-leakage-cycle.next.stderr | 8 +-- .../return-dont-satisfy-bounds.stderr | 4 +- .../issue-103052-2.stderr | 4 +- 24 files changed, 190 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b2a0b32fe261..e53f64805802 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -509,7 +509,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hir_def_key(self.local_def_id(node_id)), ); - let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id(); + let def_id = self + .tcx + .at(span) + .create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator) + .def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.resolver.node_id_to_def_id.insert(node_id, def_id); diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 46dcebc46e9c..dc5f84adb76f 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -1,3 +1,5 @@ +use rustc_hir::def_id::LocalDefId; +use rustc_hir::definitions::DisambiguatorState; use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult}; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; @@ -42,7 +44,7 @@ pub macro throw_machine_stop_str($($tt:tt)*) {{ pub struct DummyMachine; impl HasStaticRootDefId for DummyMachine { - fn static_def_id(&self) -> Option { + fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)> { None } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 61a7ec13511c..dddfc6a4e092 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -6,6 +6,7 @@ use rustc_abi::{Align, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; @@ -63,7 +64,7 @@ pub struct CompileTimeMachine<'tcx> { /// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`, /// storing the result in the given `AllocId`. /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops. - pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, + pub(crate) static_root_ids: Option<(AllocId, LocalDefId, DisambiguatorState)>, /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). union_data_ranges: FxHashMap, RangeSet>, @@ -706,7 +707,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { // Check if this is the currently evaluated static. - if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { + if Some(alloc_id) == ecx.machine.static_root_ids.as_ref().map(|(id, ..)| *id) { return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8f0cb197c445..adf2c255d089 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -17,6 +17,7 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; +use rustc_hir::definitions::DisambiguatorState; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; use rustc_middle::query::TyCtxtAt; @@ -46,12 +47,13 @@ pub trait CompileTimeMachine<'tcx, T> = Machine< pub trait HasStaticRootDefId { /// Returns the `DefId` of the static item that is currently being evaluated. /// Used for interning to be able to handle nested allocations. - fn static_def_id(&self) -> Option; + fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)>; } impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { - fn static_def_id(&self) -> Option { - Some(self.static_root_ids?.1) + fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)> { + let (_, static_id, d) = self.static_root_ids.as_mut()?; + Some((*static_id, d)) } } @@ -87,8 +89,8 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( } // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); - if let Some(static_id) = ecx.machine.static_def_id() { - intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc); + if let Some((static_id, disambiguator)) = ecx.machine.static_parent_and_disambiguator() { + intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc, disambiguator); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } @@ -102,11 +104,14 @@ fn intern_as_new_static<'tcx>( static_id: LocalDefId, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, + disambiguator: &mut DisambiguatorState, ) { let feed = tcx.create_def( static_id, Some(sym::nested), DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, + None, + disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index ba579e25f036..faaa2bd24bbd 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,4 +1,5 @@ use rustc_hir::def_id::LocalDefId; +use rustc_hir::definitions::DisambiguatorState; use rustc_middle::mir; use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; @@ -40,8 +41,8 @@ pub(crate) fn create_static_alloc<'tcx>( ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); - assert_eq!(ecx.machine.static_root_ids, None); - ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); + assert!(ecx.machine.static_root_ids.is_none()); + ecx.machine.static_root_ids = Some((alloc_id, static_def_id, DisambiguatorState::new())); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 9372ab532bf3..5872ec5aedf2 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -269,14 +269,9 @@ impl DefKind { | DefKind::TyParam | DefKind::ExternCrate => DefPathData::TypeNs(name.unwrap()), - // An associated type name will be missing for an RPITIT. - DefKind::AssocTy => { - if let Some(name) = name { - DefPathData::TypeNs(name) - } else { - DefPathData::AnonAssocTy - } - } + // An associated type name will be missing for an RPITIT (DefPathData::AnonAssocTy), + // but those provide their own DefPathData. + DefKind::AssocTy => DefPathData::TypeNs(name.unwrap()), // It's not exactly an anon const, but wrt DefPathData, there // is no difference. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index bf7b1eefcf68..d66775cd20b0 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -68,7 +68,7 @@ impl DefPathTable { // // See the documentation for DefPathHash for more information. panic!( - "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \ + "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ Compilation cannot continue." ); } @@ -97,13 +97,31 @@ impl DefPathTable { } } +#[derive(Debug)] +pub struct DisambiguatorState { + next: UnordMap<(LocalDefId, DefPathData), u32>, +} + +impl DisambiguatorState { + pub fn new() -> Self { + Self { next: Default::default() } + } + + /// Creates a `DisambiguatorState` where the next allocated `(LocalDefId, DefPathData)` pair + /// will have `index` as the disambiguator. + pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self { + let mut this = Self::new(); + this.next.insert((def_id, data), index); + this + } +} + /// The definition table containing node definitions. /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s. /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s. #[derive(Debug)] pub struct Definitions { table: DefPathTable, - next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>, } /// A unique identifier that we can use to lookup a definition @@ -173,7 +191,11 @@ impl DisambiguatedDefPathData { } } DefPathDataName::Anon { namespace } => { - write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + if let DefPathData::AnonAssocTy(method) = self.data { + write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator) + } else { + write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + } } } } @@ -288,7 +310,7 @@ pub enum DefPathData { /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, /// An anonymous associated type from an RPITIT. - AnonAssocTy, + AnonAssocTy(Symbol), /// A synthetic body for a coroutine's by-move body. SyntheticCoroutineBody, } @@ -342,11 +364,20 @@ impl Definitions { let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; assert_eq!(root.local_def_index, CRATE_DEF_INDEX); - Definitions { table, next_disambiguator: Default::default() } + Definitions { table } } - /// Adds a definition with a parent definition. - pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId { + /// Creates a definition with a parent definition. + /// If there are multiple definitions with the same DefPathData and the same parent, use + /// `disambiguator` to differentiate them. Distinct `DisambiguatorState` instances are not + /// guaranteed to generate unique disambiguators and should instead ensure that the `parent` + /// and `data` pair is distinct from other instances. + pub fn create_def( + &mut self, + parent: LocalDefId, + data: DefPathData, + disambiguator: &mut DisambiguatorState, + ) -> LocalDefId { // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a // reference to `Definitions` and we're already holding a mutable reference. debug!( @@ -354,12 +385,12 @@ impl Definitions { self.def_path(parent).to_string_no_crate_verbose(), ); - // The root node must be created with `create_root_def()`. + // The root node must be created in `new()`. assert!(data != DefPathData::CrateRoot); // Find the next free disambiguator for this key. let disambiguator = { - let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0); + let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0); let disambiguator = *next_disamb; *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); disambiguator @@ -411,7 +442,9 @@ impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; match *self { - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) => { + Some(name) + } Impl | ForeignMod @@ -422,7 +455,6 @@ impl DefPathData { | Ctor | AnonConst | OpaqueTy - | AnonAssocTy | SyntheticCoroutineBody => None, } } @@ -443,7 +475,7 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, - AnonAssocTy => DefPathDataName::Anon { namespace: sym::anon_assoc }, + AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc }, SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 59ab36d98fda..104de262fee8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -14,6 +14,7 @@ use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::definitions::DisambiguatorState; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{ self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node, @@ -63,6 +64,7 @@ impl ResolvedArg { struct BoundVarContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, rbv: &'a mut ResolveBoundVars, + disambiguator: &'a mut DisambiguatorState, scope: ScopeRef<'a>, } @@ -245,8 +247,12 @@ pub(crate) fn provide(providers: &mut Providers) { #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { let mut rbv = ResolveBoundVars::default(); - let mut visitor = - BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } }; + let mut visitor = BoundVarContext { + tcx, + rbv: &mut rbv, + scope: &Scope::Root { opt_parent_item: None }, + disambiguator: &mut DisambiguatorState::new(), + }; match tcx.hir_owner_node(local_def_id) { hir::OwnerNode::Item(item) => visitor.visit_item(item), hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), @@ -515,9 +521,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(opaque); if capture_all_in_scope_lifetimes { + let tcx = self.tcx; let lifetime_ident = |def_id: LocalDefId| { - let name = self.tcx.item_name(def_id.to_def_id()); - let span = self.tcx.def_span(def_id); + let name = tcx.item_name(def_id.to_def_id()); + let span = tcx.def_span(def_id); Ident::new(name, span) }; @@ -1091,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>), { - let BoundVarContext { tcx, rbv, .. } = self; - let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope }; + let BoundVarContext { tcx, rbv, disambiguator, .. } = self; + let mut this = BoundVarContext { tcx: *tcx, rbv, disambiguator, scope: &wrap_scope }; let span = debug_span!("scope", scope = ?this.scope.debug_truncated()); { let _enter = span.enter(); @@ -1446,7 +1453,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] fn remap_opaque_captures( - &self, + &mut self, opaque_capture_scopes: &Vec<(LocalDefId, &RefCell>)>, mut lifetime: ResolvedArg, ident: Ident, @@ -1462,8 +1469,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { - let feed = - self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam); + let feed = self.tcx.create_def( + opaque_def_id, + Some(ident.name), + DefKind::LifetimeParam, + None, + &mut self.disambiguator, + ); feed.def_span(ident.span); feed.def_ident_span(Some(ident.span)); feed.def_id() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e8dad1e056cb..fffbf0513482 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,7 +34,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::definitions::Definitions; +use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate}; @@ -1957,8 +1957,10 @@ impl<'tcx> TyCtxtAt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, + def_path_data: Option, + disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let feed = self.tcx.create_def(parent, name, def_kind); + let feed = self.tcx.create_def(parent, name, def_kind, def_path_data, disambiguator); feed.def_span(self.span); feed @@ -1972,8 +1974,10 @@ impl<'tcx> TyCtxt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, + def_path_data: Option, + disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let data = def_kind.def_path_data(name); + let data = def_path_data.unwrap_or_else(|| def_kind.def_path_data(name)); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to // decode the on-disk cache. @@ -1983,12 +1987,7 @@ impl<'tcx> TyCtxt<'tcx> { // - has been created by this call to `create_def`. // As a consequence, this LocalDefId is always re-created before it is needed by the incr. // comp. engine itself. - // - // This call also writes to the value of the `source_span` query. - // This is fine because: - // - that query is `eval_always` so we won't miss its result changing; - // - this write will have happened before that query is called. - let def_id = self.untracked.definitions.write().create_def(parent, data); + let def_id = self.untracked.definitions.write().create_def(parent, data, disambiguator); // This function modifies `self.definitions` using a side-effect. // We need to ensure that these side effects are re-run by the incr. comp. engine. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index be00c0e116dd..4e4ef3f9bf2c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,6 +38,7 @@ use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::DisambiguatorState; use rustc_index::IndexVec; use rustc_macros::{ Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, @@ -207,6 +208,8 @@ pub struct ResolverAstLowering { pub node_id_to_def_id: NodeMap, + pub disambiguator: DisambiguatorState, + pub trait_map: NodeMap>, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1df3bff52442..f589c7df6285 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -391,6 +391,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let visible_parent_map = self.tcx().visible_parent_map(()); let kind = self.tcx().def_kind(def_id); + if let DefPathData::AnonAssocTy(..) = key.disambiguated_data.data { + return Ok(false); + } + let get_local_name = |this: &Self, name, def_id, key: DefKey| { if let Some(visible_parent) = visible_parent_map.get(&def_id) && let actual_parent = this.tcx().opt_parent(def_id) diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index dd0e07f2218e..bbc4531789b0 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -73,6 +73,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::DisambiguatorState; use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; @@ -213,8 +214,13 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( let mut by_move_body = body.clone(); MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); - // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. - let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody); + let body_def = tcx.create_def( + parent_def_id, + None, + DefKind::SyntheticCoroutineBody, + None, + &mut DisambiguatorState::new(), + ); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4a252a7b5281..bb8d7b763719 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -55,6 +55,7 @@ use rustc_hir::def::{ self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS, }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; @@ -1184,6 +1185,8 @@ pub struct Resolver<'ra, 'tcx> { node_id_to_def_id: NodeMap>, + disambiguator: DisambiguatorState, + /// Indices of unnamed struct or variant fields with unresolved attributes. placeholder_field_indices: FxHashMap, /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` @@ -1347,7 +1350,7 @@ impl<'tcx> Resolver<'_, 'tcx> { ); // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()` - let feed = self.tcx.create_def(parent, name, def_kind); + let feed = self.tcx.create_def(parent, name, def_kind, None, &mut self.disambiguator); let def_id = feed.def_id(); // Create the definition. @@ -1561,6 +1564,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lint_buffer: LintBuffer::default(), next_node_id: CRATE_NODE_ID, node_id_to_def_id, + disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), invocation_parents, legacy_const_generic_args: Default::default(), @@ -1690,6 +1694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .into_items() .map(|(k, f)| (k, f.key())) .collect(), + disambiguator: self.disambiguator, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 4b1b3903e403..ed32c34bb4b5 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -722,7 +722,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAssocTy => { + | hir::definitions::DefPathData::AnonAssocTy(..) => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f310aa655002..12aa876045c4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -859,7 +859,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) - | DefPathData::AnonAssocTy => { + | DefPathData::AnonAssocTy(..) => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6cb9fdc6f931..f14a45aa1e3b 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,6 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; @@ -159,6 +160,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::AssocItemContainer::Impl, } } +struct RPITVisitor { + rpits: FxIndexSet, +} + +impl<'tcx> Visitor<'tcx> for RPITVisitor { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { + if let hir::TyKind::OpaqueDef(opaq) = ty.kind + && self.rpits.insert(opaq.def_id) + { + for bound in opaq.bounds { + intravisit::walk_param_bound(self, bound); + } + } + intravisit::walk_ty(self, ty) + } +} /// Given an `fn_def_id` of a trait or a trait implementation: /// @@ -177,23 +194,6 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - struct RPITVisitor { - rpits: FxIndexSet, - } - - impl<'tcx> Visitor<'tcx> for RPITVisitor { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { - if let hir::TyKind::OpaqueDef(opaq) = ty.kind - && self.rpits.insert(opaq.def_id) - { - for bound in opaq.bounds { - intravisit::walk_param_bound(self, bound); - } - } - intravisit::walk_ty(self, ty) - } - } - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { @@ -246,9 +246,23 @@ fn associated_type_for_impl_trait_in_trait( let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); + // Collect all opaque types in return position for the method and use + // the index as the disambiguator to make an unique def path. + let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; + visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap()); + let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap(); + let span = tcx.def_span(opaque_ty_def_id); - // No name because this is an anonymous associated type. - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); + // Also use the method name to create an unique def path. + let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let trait_assoc_ty = tcx.at(span).create_def( + trait_def_id, + // No name because this is an anonymous associated type. + None, + DefKind::AssocTy, + Some(data), + &mut DisambiguatorState::with(trait_def_id, data, disambiguator), + ); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -299,8 +313,22 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - // No name because this is an anonymous associated type. - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); + + // Use the same disambiguator and method name as the anon associated type in the trait. + let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data; + let DefPathData::AnonAssocTy(name) = disambiguated_data.data else { + bug!("expected anon associated type") + }; + let data = DefPathData::AnonAssocTy(name); + + let impl_assoc_ty = tcx.at(span).create_def( + impl_local_def_id, + // No name because this is an anonymous associated type. + None, + DefKind::AssocTy, + Some(data), + &mut DisambiguatorState::with(impl_local_def_id, data, disambiguated_data.disambiguator), + ); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index cb14d9f459a2..53d05c3db8c4 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` --> $DIR/unsupported.rs:22:25 | LL | reuse to_reuse::opaque_ret; @@ -9,7 +9,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:21:5 | @@ -17,7 +17,7 @@ LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` --> $DIR/unsupported.rs:25:24 | LL | reuse ToReuse::opaque_ret; @@ -28,7 +28,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:24:5 | diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index a9dfac274d55..119195f17ffc 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -6,11 +6,11 @@ LL | fn bar() -> () {} | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `Foo::{anon_assoc#0}` +note: required by a bound in `Foo::bar::{anon_assoc#0}` --> $DIR/doesnt-satisfy.rs:2:22 | LL | fn bar() -> impl std::fmt::Display; - | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{anon_assoc#0}` + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{anon_assoc#0}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs index da3cfd099b56..0a951b4fd99a 100644 --- a/tests/ui/impl-trait/in-trait/dump.rs +++ b/tests/ui/impl-trait/in-trait/dump.rs @@ -8,7 +8,7 @@ trait Foo { } fn hello<'s, T: Foo>(x: &'s T) -> impl Sized + use<'s, T> { -//~^ ERROR ::{anon_assoc#0}<'s/#1> + //~^ ERROR ::hello::{anon_assoc#0}<'s/#1> x.hello() } diff --git a/tests/ui/impl-trait/in-trait/dump.stderr b/tests/ui/impl-trait/in-trait/dump.stderr index 15b6f186ced5..35ed21bde113 100644 --- a/tests/ui/impl-trait/in-trait/dump.stderr +++ b/tests/ui/impl-trait/in-trait/dump.stderr @@ -1,4 +1,4 @@ -error: ::{anon_assoc#0}<'s/#1> +error: ::hello::{anon_assoc#0}<'s/#1> --> $DIR/dump.rs:10:35 | LL | fn hello<'s, T: Foo>(x: &'s T) -> impl Sized + use<'s, T> { diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr index bf598d627094..5d6512457467 100644 --- a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `::foo::{anon_assoc#0}` --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 | LL | fn foo(b: bool) -> impl Sized { @@ -45,7 +45,7 @@ note: ...which requires type-checking ` impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `::foo::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `` is well-formed --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 | diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr index 6bec5bbc0632..4bbba62bd710 100644 --- a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `::foo::{anon_assoc#0}` --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 | LL | fn foo(b: bool) -> impl Sized { @@ -49,7 +49,7 @@ note: ...which requires type-checking ` impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `::foo::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `` is well-formed --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 | @@ -57,7 +57,7 @@ LL | impl Trait for u32 { | ^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `::foo::{anon_assoc#0}` --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 | LL | fn foo(b: bool) -> impl Sized { @@ -108,7 +108,7 @@ note: ...which requires type-checking ` impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `::foo::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `` is well-formed --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 | diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index 6571ce2d5f05..a16e0160223b 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -14,11 +14,11 @@ LL | fn foo>(self) -> impl Foo { | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` | = help: the trait `Foo` is implemented for `Bar` -note: required by a bound in `Foo::{anon_assoc#0}` +note: required by a bound in `Foo::foo::{anon_assoc#0}` --> $DIR/return-dont-satisfy-bounds.rs:2:30 | LL | fn foo(self) -> impl Foo; - | ^^^^^^ required by this bound in `Foo::{anon_assoc#0}` + | ^^^^^^ required by this bound in `Foo::foo::{anon_assoc#0}` error[E0277]: the trait bound `Bar: Foo` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr index 400969c279e6..99fd83e7b6ff 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr @@ -4,11 +4,11 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied LL | fn main() -> Something { | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` | -note: required by a bound in `Main::{anon_assoc#0}` +note: required by a bound in `Main::main::{anon_assoc#0}` --> $DIR/issue-103052-2.rs:3:27 | LL | fn main() -> impl std::process::Termination; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{anon_assoc#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::main::{anon_assoc#0}` error: aborting due to 1 previous error From 21e7003a025419af87bb315dc394beee0ba391e5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Apr 2025 13:09:19 +0200 Subject: [PATCH 073/302] refactor: Remove unnecessary extension trait --- .../rust-analyzer/crates/hir-expand/src/db.rs | 5 +- .../crates/hir-expand/src/hygiene.rs | 60 +------------------ .../crates/hir-expand/src/mod_path.rs | 4 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 1 - .../rust-analyzer/crates/hir/src/semantics.rs | 1 - .../rust-analyzer/crates/span/src/hygiene.rs | 56 ++++++++++++++++- 6 files changed, 59 insertions(+), 68 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 2219a55a84be..67391dbd955a 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -18,10 +18,7 @@ use crate::{ cfg_process, declarative::DeclarativeMacroExpander, fixup::{self, SyntaxFixupUndoInfo}, - hygiene::{ - SyntaxContextExt as _, span_with_call_site_ctxt, span_with_def_site_ctxt, - span_with_mixed_site_ctxt, - }, + hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros}, span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef}, tt, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index e7856920bc42..28800c6fabdb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -22,7 +22,7 @@ // FIXME: Move this into the span crate? Not quite possible today as that depends on `MacroCallLoc` // which contains a bunch of unrelated things -use std::{convert::identity, iter}; +use std::convert::identity; use span::{Edition, MacroCallId, Span, SyntaxContext}; @@ -141,61 +141,3 @@ fn apply_mark_internal( |_| opaque_and_semitransparent, ) } - -pub trait SyntaxContextExt { - fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn parent_ctxt(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn remove_mark(&mut self, db: &dyn ExpandDatabase) - -> (Option, Transparency); - fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option, Transparency); - fn marks(self, db: &dyn ExpandDatabase) -> Vec<(span::MacroCallId, Transparency)>; - fn is_opaque(self, db: &dyn ExpandDatabase) -> bool; -} - -impl SyntaxContextExt for SyntaxContext { - fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.opaque_and_semitransparent(db) - } - fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.opaque(db) - } - fn parent_ctxt(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.parent(db) - } - fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option, Transparency) { - let data = self; - (data.outer_expn(db), data.outer_transparency(db)) - } - fn remove_mark( - &mut self, - db: &dyn ExpandDatabase, - ) -> (Option, Transparency) { - let data = *self; - *self = data.parent(db); - (data.outer_expn(db), data.outer_transparency(db)) - } - fn marks(self, db: &dyn ExpandDatabase) -> Vec<(span::MacroCallId, Transparency)> { - let mut marks = marks_rev(self, db).collect::>(); - marks.reverse(); - marks - } - fn is_opaque(self, db: &dyn ExpandDatabase) -> bool { - !self.is_root() && self.outer_transparency(db).is_opaque() - } -} - -// FIXME: Make this a SyntaxContextExt method once we have RPIT -pub fn marks_rev( - ctxt: SyntaxContext, - db: &dyn ExpandDatabase, -) -> impl Iterator + '_ { - iter::successors(Some(ctxt), move |&mark| Some(mark.parent_ctxt(db))) - .take_while(|&it| !it.is_root()) - .map(|ctx| { - let mark = ctx.outer_mark(db); - // We stop before taking the root expansion, as such we cannot encounter a `None` outer - // expansion, as only the ROOT has it. - (mark.0.unwrap(), mark.1) - }) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 72a5627636bf..9f1e3879e1ee 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ db::ExpandDatabase, - hygiene::{SyntaxContextExt, Transparency, marks_rev}, + hygiene::Transparency, name::{AsName, Name}, tt, }; @@ -340,7 +340,7 @@ pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContext) -> O // definitions actually produced by `macro` and `macro` definitions produced by // `macro_rules!`, but at least such configurations are not stable yet. ctxt = ctxt.normalize_to_macro_rules(db); - let mut iter = marks_rev(ctxt, db).peekable(); + let mut iter = ctxt.marks_rev(db).peekable(); let mut result_mark = None; // Find the last opaque mark from the end if it exists. while let Some(&(mark, Transparency::Opaque)) = iter.peek() { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c62e4cf4497d..d7754bf2e233 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -136,7 +136,6 @@ pub use { HirFileRange, InFile, InFileWrapper, InMacroFile, InRealFile, MacroFilePosition, MacroFileRange, }, - hygiene::{SyntaxContextExt, marks_rev}, inert_attr_macro::AttributeTemplate, mod_path::{ModPath, PathKind, tool_path}, name::Name, diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index f708f2e16673..2e693559e292 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -25,7 +25,6 @@ use hir_expand::{ builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, files::{FileRangeWrapper, InRealFile}, - hygiene::SyntaxContextExt as _, inert_attr_macro::find_builtin_attr_idx, mod_path::{ModPath, PathKind}, name::AsName, diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index b21102f2db71..d1e75d97d7a7 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -308,7 +308,7 @@ impl SyntaxContext { } #[cfg(feature = "salsa")] -impl SyntaxContext { +impl<'db> SyntaxContext { const MAX_ID: u32 = salsa::Id::MAX_U32 - 1; #[inline] @@ -340,6 +340,60 @@ impl SyntaxContext { // SAFETY: This comes from a Salsa ID. unsafe { Self::from_u32(id.as_u32()) } } + + #[inline] + pub fn outer_mark( + self, + db: &'db dyn salsa::Database, + ) -> (Option, Transparency) { + (self.outer_expn(db), self.outer_transparency(db)) + } + + #[inline] + pub fn normalize_to_macros_2_0(self, db: &'db dyn salsa::Database) -> SyntaxContext { + self.opaque(db) + } + + #[inline] + pub fn normalize_to_macro_rules(self, db: &'db dyn salsa::Database) -> SyntaxContext { + self.opaque_and_semitransparent(db) + } + + pub fn is_opaque(self, db: &'db dyn salsa::Database) -> bool { + !self.is_root() && self.outer_transparency(db).is_opaque() + } + + pub fn remove_mark( + &mut self, + db: &'db dyn salsa::Database, + ) -> (Option, Transparency) { + let data = *self; + *self = data.parent(db); + (data.outer_expn(db), data.outer_transparency(db)) + } + + pub fn marks( + self, + db: &'db dyn salsa::Database, + ) -> impl Iterator { + let mut marks = self.marks_rev(db).collect::>(); + marks.reverse(); + marks.into_iter() + } + + pub fn marks_rev( + self, + db: &'db dyn salsa::Database, + ) -> impl Iterator { + std::iter::successors(Some(self), move |&mark| Some(mark.parent(db))) + .take_while(|&it| !it.is_root()) + .map(|ctx| { + let mark = ctx.outer_mark(db); + // We stop before taking the root expansion, as such we cannot encounter a `None` outer + // expansion, as only the ROOT has it. + (mark.0.unwrap(), mark.1) + }) + } } #[cfg(not(feature = "salsa"))] #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] From df1f8d140e637d927caa0610f47e320d75b76a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 29 Apr 2025 14:49:00 +0200 Subject: [PATCH 074/302] Update stable-mir test --- .../stable-mir/check_assoc_items.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index 755bec8747bc..bb95bedf9733 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -17,13 +17,13 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use std::io::Write; use std::collections::HashSet; -use stable_mir::CrateDef; -use stable_mir::*; -use stable_mir::ty::*; +use std::io::Write; use std::ops::ControlFlow; +use stable_mir::ty::*; +use stable_mir::{CrateDef, *}; + const CRATE_NAME: &str = "crate_assoc_items"; /// This function uses the Stable MIR APIs to get information about the test crate. @@ -45,30 +45,30 @@ fn test_assoc_items() -> ControlFlow<()> { let local_impls = local_crate.trait_impls(); let local_traits = local_crate.trait_decls(); - let trait_assoc_item_defs: Vec = local_traits[0].associated_items() - .iter().map(|assoc_item| assoc_item.def_id).collect(); + let trait_assoc_item_defs: Vec = + local_traits[0].associated_items().iter().map(|assoc_item| assoc_item.def_id).collect(); check_items( &trait_assoc_item_defs, &[ - "ATrait::{anon_assoc#0}", + "ATrait::rpitit::{anon_assoc#0}", "ATrait::rpitit", "ATrait::Assoc", "ATrait::assoc_fn_no_self", "ATrait::assoc_fn_has_self", - ] + ], ); - let impl_assoc_item_defs: Vec = local_impls[0].associated_items() - .iter().map(|assoc_item| assoc_item.def_id).collect(); + let impl_assoc_item_defs: Vec = + local_impls[0].associated_items().iter().map(|assoc_item| assoc_item.def_id).collect(); check_items( &impl_assoc_item_defs, &[ - "::{anon_assoc#0}", + "::rpitit::{anon_assoc#0}", "::rpitit", "::Assoc", "::assoc_fn_no_self", "::assoc_fn_has_self", - ] + ], ); ControlFlow::Continue(()) From 820fce61e72a1bc9c8eb132afec9ab71c67f4923 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 29 Apr 2025 13:55:28 +0000 Subject: [PATCH 075/302] Some style nits --- compiler/rustc_mir_transform/src/shim.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 0d9a04b760a2..9688ac8ed2e2 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -298,10 +298,9 @@ fn local_decls_for_sig<'tcx>( fn dropee_emit_retag<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, - dropee_ptr: Place<'tcx>, + mut dropee_ptr: Place<'tcx>, span: Span, ) -> Place<'tcx> { - let mut dropee_ptr = dropee_ptr; if tcx.sess.opts.unstable_opts.mir_emit_retag { let source_info = SourceInfo::outermost(span); // We want to treat the function argument as if it was passed by `&mut`. As such, we @@ -365,8 +364,8 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); // The first argument (index 0), but add 1 for the return value. - let mut dropee_ptr = Place::from(Local::new(1 + 0)); - dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); + let dropee_ptr = Place::from(Local::new(1 + 0)); + let dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); if ty.is_some() { let patch = { From ef5834968e41aa6c1ef479f8acc1197dec526731 Mon Sep 17 00:00:00 2001 From: geetanshjuneja Date: Sun, 13 Apr 2025 14:03:22 +0530 Subject: [PATCH 076/302] Added random scheduling --- src/tools/miri/src/bin/miri.rs | 2 + src/tools/miri/src/concurrency/thread.rs | 52 ++++++++++++------- src/tools/miri/src/eval.rs | 3 ++ src/tools/miri/src/machine.rs | 2 +- .../concurrency/libc_pthread_join_self.rs | 2 +- .../fail-dep/concurrency/windows_join_main.rs | 2 +- .../fail-dep/concurrency/windows_join_self.rs | 2 +- .../fail-dep/libc/env-set_var-data-race.rs | 2 +- .../fail-dep/libc/eventfd_block_read_twice.rs | 2 +- .../libc/eventfd_block_write_twice.rs | 2 +- .../fail-dep/libc/libc-epoll-data-race.rs | 2 +- .../libc/libc_epoll_block_two_thread.rs | 2 +- .../libc/socketpair-close-while-blocked.rs | 2 +- .../fail-dep/libc/socketpair-data-race.rs | 2 +- .../libc/socketpair_block_read_twice.rs | 2 +- .../libc/socketpair_block_write_twice.rs | 2 +- .../both_borrows/retag_data_race_write.rs | 2 +- .../tests/fail/data_race/alloc_read_race.rs | 2 +- .../tests/fail/data_race/alloc_write_race.rs | 2 +- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 2 +- .../fail/data_race/dangling_thread_race.rs | 2 +- .../fail/data_race/dealloc_read_race1.rs | 2 +- .../fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- .../fail/data_race/dealloc_write_race1.rs | 2 +- .../fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../data_race/enable_after_join_to_main.rs | 2 +- .../tests/fail/data_race/fence_after_load.rs | 2 +- .../data_race/local_variable_alloc_race.rs | 2 +- .../data_race/local_variable_read_race.rs | 2 +- .../data_race/local_variable_write_race.rs | 2 +- .../data_race/mixed_size_read_read_write.rs | 2 +- .../fail/data_race/mixed_size_read_write.rs | 2 +- .../fail/data_race/mixed_size_write_write.rs | 2 +- .../tests/fail/data_race/read_write_race.rs | 2 +- .../fail/data_race/read_write_race_stack.rs | 2 +- .../fail/data_race/relax_acquire_race.rs | 2 +- .../tests/fail/data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- .../miri/tests/fail/data_race/rmw_race.rs | 2 +- .../tests/fail/data_race/stack_pop_race.rs | 2 +- .../tests/fail/data_race/write_write_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 2 +- .../retag_data_race_protected_read.rs | 2 +- .../stacked_borrows/retag_data_race_read.rs | 2 +- .../tree_borrows/reservedim_spurious_write.rs | 2 +- .../tests/fail/tree_borrows/spurious_read.rs | 2 +- .../tests/fail/weak_memory/weak_uninit.rs | 2 +- .../tests/pass-dep/concurrency/apple-futex.rs | 2 +- .../concurrency/env-cleanup-data-race.rs | 2 +- .../pass-dep/concurrency/freebsd-futex.rs | 2 +- .../concurrency/windows_detach_terminated.rs | 2 +- .../pass-dep/concurrency/windows_init_once.rs | 2 +- .../concurrency/windows_join_multiple.rs | 2 +- .../pass-dep/libc/libc-epoll-blocking.rs | 2 +- .../miri/tests/pass-dep/libc/libc-eventfd.rs | 2 +- .../miri/tests/pass-dep/libc/libc-pipe.rs | 2 +- .../tests/pass-dep/libc/libc-socketpair.rs | 2 +- .../miri/tests/pass-dep/libc/pthread-sync.rs | 2 +- .../miri/tests/pass/concurrency/data_race.rs | 2 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 2 +- src/tools/miri/tests/pass/concurrency/sync.rs | 2 +- .../tests/pass/concurrency/sync_nopreempt.rs | 2 +- .../miri/tests/pass/panic/concurrent-panic.rs | 2 +- src/tools/miri/tests/pass/shims/env/var.rs | 2 +- .../pass/tree_borrows/read_retag_no_race.rs | 2 +- .../tests/pass/tree_borrows/spurious_read.rs | 2 +- src/tools/miri/tests/pass/weak_memory/weak.rs | 2 +- 76 files changed, 111 insertions(+), 92 deletions(-) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 4e8fe0ca8adf..57568071d0dd 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -573,6 +573,8 @@ fn main() { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-retag-fields" { miri_config.retag_fields = RetagFields::Yes; + } else if arg == "-Zmiri-fixed-schedule" { + miri_config.fixed_scheduling = true; } else if let Some(retag_fields) = arg.strip_prefix("-Zmiri-retag-fields=") { miri_config.retag_fields = match retag_fields { "all" => RetagFields::Yes, diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 72fa918e8e51..d640e7777e59 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -6,6 +6,8 @@ use std::task::Poll; use std::time::{Duration, SystemTime}; use either::Either; +use rand::rngs::StdRng; +use rand::seq::IteratorRandom; use rustc_abi::ExternAbi; use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::fx::FxHashMap; @@ -401,6 +403,8 @@ pub struct ThreadManager<'tcx> { thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, + /// A flag that indicates that we should do round robin scheduling of threads else randomized scheduling is used. + fixed_scheduling: bool, } impl VisitProvenance for ThreadManager<'_> { @@ -410,6 +414,7 @@ impl VisitProvenance for ThreadManager<'_> { thread_local_allocs, active_thread: _, yield_active_thread: _, + fixed_scheduling: _, } = self; for thread in threads { @@ -421,8 +426,8 @@ impl VisitProvenance for ThreadManager<'_> { } } -impl<'tcx> Default for ThreadManager<'tcx> { - fn default() -> Self { +impl<'tcx> ThreadManager<'tcx> { + pub(crate) fn new(config: &MiriConfig) -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. threads.push(Thread::new(Some("main"), None)); @@ -431,11 +436,10 @@ impl<'tcx> Default for ThreadManager<'tcx> { threads, thread_local_allocs: Default::default(), yield_active_thread: false, + fixed_scheduling: config.fixed_scheduling, } } -} -impl<'tcx> ThreadManager<'tcx> { pub(crate) fn init( ecx: &mut MiriInterpCx<'tcx>, on_main_stack_empty: StackEmptyCallback<'tcx>, @@ -702,7 +706,11 @@ impl<'tcx> ThreadManager<'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> { + fn schedule( + &mut self, + clock: &MonotonicClock, + rng: &mut StdRng, + ) -> InterpResult<'tcx, SchedulingAction> { // This thread and the program can keep going. if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread { // The currently active thread is still enabled, just continue with it. @@ -720,30 +728,33 @@ impl<'tcx> ThreadManager<'tcx> { } // No callbacks immediately scheduled, pick a regular thread to execute. // The active thread blocked or yielded. So we go search for another enabled thread. - // Crucially, we start searching at the current active thread ID, rather than at 0, since we - // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2. - // - // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after* - // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the - // active thread. - let threads = self + // We build the list of threads by starting with the thread after the current one, followed by + // the threads before the current one and then the current thread itself (i.e., this iterator acts + // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first + // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step. + let mut threads_iter = self .threads .iter_enumerated() .skip(self.active_thread.index() + 1) - .chain(self.threads.iter_enumerated().take(self.active_thread.index())); - for (id, thread) in threads { - debug_assert_ne!(self.active_thread, id); - if thread.state.is_enabled() { + .chain(self.threads.iter_enumerated().take(self.active_thread.index() + 1)) + .filter(|(_id, thread)| thread.state.is_enabled()); + // Pick a new thread, and switch to it. + let new_thread = + if self.fixed_scheduling { threads_iter.next() } else { threads_iter.choose(rng) }; + + if let Some((id, _thread)) = new_thread { + if self.active_thread != id { info!( "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------", self.get_thread_display_name(id), self.get_thread_display_name(self.active_thread) ); self.active_thread = id; - break; } } + //This completes the `yield`, if any was requested. self.yield_active_thread = false; + if self.threads[self.active_thread].state.is_enabled() { return interp_ok(SchedulingAction::ExecuteStep); } @@ -1138,7 +1149,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - if this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) { + if !this.machine.threads.fixed_scheduling + && this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) + { this.yield_active_thread(); } } @@ -1152,7 +1165,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.handle_abnormal_termination(); throw_machine_stop!(TerminationInfo::Interrupted); } - match this.machine.threads.schedule(&this.machine.monotonic_clock)? { + let rng = this.machine.rng.get_mut(); + match this.machine.threads.schedule(&this.machine.monotonic_clock, rng)? { SchedulingAction::ExecuteStep => { if !this.step()? { // See if this thread can do something else. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 7586b5efd4b2..3349d2df0d58 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -163,6 +163,8 @@ pub struct MiriConfig { pub address_reuse_rate: f64, /// Probability for address reuse across threads. pub address_reuse_cross_thread_rate: f64, + /// Round Robin scheduling with no preemption. + pub fixed_scheduling: bool, } impl Default for MiriConfig { @@ -200,6 +202,7 @@ impl Default for MiriConfig { collect_leak_backtraces: true, address_reuse_rate: 0.5, address_reuse_cross_thread_rate: 0.1, + fixed_scheduling: false, } } } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ea59d327be84..bbd170a8b273 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -669,7 +669,7 @@ impl<'tcx> MiriMachine<'tcx> { cpu_affinity::MAX_CPUS, config.num_cpus ); - let threads = ThreadManager::default(); + let threads = ThreadManager::new(config); let mut thread_cpu_affinity = FxHashMap::default(); if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") { thread_cpu_affinity diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs index 53760b05a312..a3db0fd25dc0 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule // Joining itself is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index 3ee2bf14f9fe..044d9a88ddc0 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock // On windows, joining main is not UB, but it will block a thread forever. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs index eee2979f3cff..812fab445d1e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock // On windows, a thread joining itself is not UB, but it will deadlock. diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 3a832bb0ce0c..16706fd47448 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule //@ignore-target: windows # No libc env support on Windows use std::{env, thread}; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs index 0d893663fd6d..168711d4d344 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs index 9fed47c17d40..cc71aaf1a141 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs index 45f6bf6da096..f9a4a4e5b2bb 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs @@ -4,7 +4,7 @@ //! to be considered synchronized. //@only-target: linux android illumos // ensure deterministic schedule -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs index 059b24cb8c0b..c5c1db64037d 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //~^ERROR: deadlocked //~^^ERROR: deadlocked //@only-target: linux android illumos diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs index 8413e118819c..1f6bb430ab20 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs @@ -2,7 +2,7 @@ //! faulty logic around `release_clock` that led to this code not reporting a data race. //~^^ERROR: deadlock //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-rate=0 //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs index 55491da9f60d..b864347e2343 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs @@ -1,7 +1,7 @@ //! This is a regression test for : we had some //! faulty logic around `release_clock` that led to this code not reporting a data race. //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-rate=0 use std::thread; fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs index d3e4c43f2b75..c7bcdd54ec7b 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs index 4f951acb2c31..aaf9ead20003 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs index 0061679eaa4e..09924cd61aca 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs @@ -1,6 +1,6 @@ //! Make sure that a retag acts like a write for the data race model. //@revisions: stack tree -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 //@[tree]compile-flags: -Zmiri-tree-borrows diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs index 312b7ba05d31..e3f602511210 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs index f1f308b37e7b..0a010f68abbb 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs index 4003892f0a60..de3bac474dbe 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs index c67ce65eb340..123050331cdd 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs index 5e328740e851..88ce531a6949 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs index e0876a93fdd8..963ce28065fa 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs index 1010216a4976..cfbcec9cc2b1 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs index fdc0f9e20f07..1e76f0faa2ab 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs index dffafe3cfaa9..c9fa6a86443a 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs index 8dc35c7ea720..d4bcc9abca33 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs index d0a284820541..f1458131c48a 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs index f56c44cabc23..8a8595b97a0b 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs index c67e03d362b0..de79076f59d8 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs index a16ea25e11ce..d42a89eae3cd 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs index f3855e33c98d..a3d7770c2cef 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs index 8e63bc1dc7b4..770283a7be2d 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs index 53050608d271..6820ec46058e 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs index 5dfb260c20bd..df5730ae1bb7 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs index 751a308a3999..208b974cc7b6 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation #![feature(core_intrinsics)] #![feature(custom_mir)] diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs index 16a23f595ee4..4a622e5d1b91 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs index 7e00573146c2..e80f2a0c037f 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs index e76654806bb1..6496fb30b762 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 // Two variants: the atomic store matches the size of the first or second atomic load. diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs index 53016bab7804..08fe0965aef2 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 // Two revisions, depending on which access goes first. diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs index 545e354a0372..dd3db5a11d83 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 //@revisions: fst snd diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.rs b/src/tools/miri/tests/fail/data_race/read_write_race.rs index adf19dda9d3d..dfe9de155ec3 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race.rs @@ -1,5 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs index f411767f7b57..f02c0b23e524 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs index c4f943808229..1d9cebb6c74a 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.rs b/src/tools/miri/tests/fail/data_race/release_seq_race.rs index f03ab3efa062..367160506358 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs index 88ae01b3ca1c..8c223ee4ac19 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.rs b/src/tools/miri/tests/fail/data_race/rmw_race.rs index d738caa10587..d06c13a8f7f9 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.rs +++ b/src/tools/miri/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs index 762a8e51f692..95d4145e5e73 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.rs b/src/tools/miri/tests/fail/data_race/write_write_race.rs index 993d8d25b4c1..7d7516449c3a 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race.rs @@ -1,5 +1,5 @@ // We want to control preemption here. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs index 8070a7f4fc2a..6707de52e3f1 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs index a6ee7b40c340..9fb910a3de4a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs @@ -1,5 +1,5 @@ // Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 use std::thread; #[derive(Copy, Clone)] diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index 949f659e7e8e..a91931312bcf 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -1,6 +1,6 @@ //! Make sure that a retag acts like a read for the data race model. // Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 73f227fee2fc..19c6e1bfcc17 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -1,7 +1,7 @@ // Illustrating a problematic interaction between Reserved, interior mutability, // and protectors, that makes spurious writes fail in the previous model of Tree Borrows. // As for all similar tests, we disable preemption so that the error message is deterministic. -//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-fixed-schedule // // One revision without spurious read (default source code) and one with spurious read. // Both are expected to be UB. Both revisions are expected to have the *same* error diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs index 50ef0ceef91e..19f56730f365 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs @@ -2,7 +2,7 @@ // Note that we are *also* using barriers: the barriers enforce the // specific interleaving of operations that we want, but only the preemption // rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs index 79c97a5b7527..b4b4b0849877 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs index becb90eb9230..d71104667628 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs @@ -1,5 +1,5 @@ //@only-target: darwin -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::time::{Duration, Instant}; use std::{io, ptr, thread}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index c9c9dc5dfd2a..4c42e97b66c8 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule //@ignore-target: windows # No libc env support on Windows use std::ffi::CStr; diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs index 38a0bf58148e..36dbb1bb4fd5 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs @@ -1,5 +1,5 @@ //@only-target: freebsd -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-isolation +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-isolation use std::mem::{self, MaybeUninit}; use std::ptr::{self, addr_of}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs index fe2d20bb76f8..aabd542f7c74 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::os::windows::io::IntoRawHandle; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs index 6853395686aa..f02ad3d4edd9 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::ptr::null_mut; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs index 2796541a3d72..5a62c41927a9 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::os::windows::io::IntoRawHandle; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index 825e1355848b..ae9bf6995e62 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index 30e1bbb8fa1b..12e12aa7138b 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index d6072c2569e9..71e0467b3eb8 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc pipe on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::thread; fn main() { test_pipe(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index 9163fd3d06fa..f4277791aeb9 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc socketpair on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index fa11b5b12990..fae517f8e19f 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index d16de0ae8e23..76b31a76ccf1 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule use std::sync::atomic::*; use std::thread::{self, spawn}; diff --git a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs index 354a4bef932e..968d5237ead8 100644 --- a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs +++ b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-disable-data-race-detector // Avoid non-determinism -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 use std::thread::spawn; diff --git a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs index 44b16e1ac74d..55d6e0660c9a 100644 --- a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,5 +1,5 @@ // This specifically tests behavior *without* preemption. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 91c67b215a1a..6e726ee0e093 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -1,7 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-fixed-schedule use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs index c6cff038f81e..7c465d7ad568 100644 --- a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-strict-provenance -Zmiri-fixed-schedule use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.rs b/src/tools/miri/tests/pass/panic/concurrent-panic.rs index e804df90977a..d4d5eecd9122 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.rs +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index 655b29674e34..44eb69cc6847 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::{env, thread}; fn main() { diff --git a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs index d9897a1033fb..19f90e5ee126 100644 --- a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs +++ b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs @@ -2,7 +2,7 @@ // This test relies on a specific interleaving that cannot be enforced // with just barriers. We must remove preemption so that the execution and the // error messages are deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule use std::ptr::addr_of_mut; use std::sync::{Arc, Barrier}; use std::thread; diff --git a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs index 71e93d2f84f5..061a5dd9e8e6 100644 --- a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs @@ -2,7 +2,7 @@ // Note that we are *also* using barriers: the barriers enforce the // specific interleaving of operations that we want, but only the preemption // rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-fixed-schedule //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 5d636431d867..eeab4ebf129e 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. From a2b3f11700821d778d4dfbc3651a61a0f0f6f3be Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Tue, 29 Apr 2025 22:12:27 +0800 Subject: [PATCH 077/302] Filter out LoongArch features not supported by the current LLVM version --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ae1bdac1655d..c17b99f19468 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -273,6 +273,12 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version + ("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq") + if get_version().0 < 20 => + { + None + } + // Filter out features that are not supported by the current LLVM version ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => { From 74b55b4b865a6ca882e9006bcf7b87f5eb845f4b Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Tue, 29 Apr 2025 22:15:11 +0800 Subject: [PATCH 078/302] Add comment to remind filtering unsupported features when adding new ones --- compiler/rustc_target/src/target_features.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..007bfea887c8 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -102,6 +102,9 @@ impl Stability { // check whether they're named already elsewhere in rust // e.g. in stdarch and whether the given name matches LLVM's // if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. +// Additionally, if the feature is not available in older version of LLVM supported by the current +// rust, the same function must be updated to filter out these features to avoid triggering +// warnings. // // Also note that all target features listed here must be purely additive: for target_feature 1.1 to // be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a From 9193dfe435559ff69c5b63b610c4e5ebac2ef23b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 29 Apr 2025 14:23:23 +0000 Subject: [PATCH 079/302] Use a closure instead of three chained iterators --- compiler/rustc_middle/src/mir/terminator.rs | 103 ++++++++---------- compiler/rustc_mir_transform/src/coroutine.rs | 6 +- .../rustc_mir_transform/src/jump_threading.rs | 4 +- compiler/rustc_mir_transform/src/prettify.rs | 4 +- .../src/remove_noop_landing_pads.rs | 4 +- compiler/rustc_mir_transform/src/simplify.rs | 9 +- 6 files changed, 58 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 8a1ead7d19d0..0834fa8844c0 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -437,8 +437,8 @@ impl<'tcx> Terminator<'tcx> { } #[inline] - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - self.kind.successors_mut() + pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) { + self.kind.successors_mut(f) } #[inline] @@ -486,7 +486,6 @@ pub use helper::*; mod helper { use super::*; pub type Successors<'a> = impl DoubleEndedIterator + 'a; - pub type SuccessorsMut<'a> = impl DoubleEndedIterator + 'a; impl SwitchTargets { /// Like [`SwitchTargets::target_for_value`], but returning the same type as @@ -560,69 +559,63 @@ mod helper { } #[inline] - #[define_opaque(SuccessorsMut)] - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { + pub fn successors_mut<'a>(&'a mut self, mut f: impl FnMut(&'a mut BasicBlock)) { use self::TerminatorKind::*; - match *self { - // 3-successors for async drop: target, unwind, dropline (parent coroutine drop) - Drop { - target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - drop: Some(ref mut d), - .. - } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(Some(d))), - // 2-successors - Call { - target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. + match self { + Drop { target, unwind, drop, .. } => { + f(target); + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } + if let Some(d) = drop { + f(d) + } } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | Drop { - target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - drop: None, - .. + Call { target, unwind, .. } => { + if let Some(target) = target { + f(target); + } + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } } - | Drop { target: ref mut t, unwind: _, drop: Some(ref mut u), .. } - | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } - | FalseUnwind { - real_target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(None)), - // single successor - Goto { target: ref mut t } - | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } - | Call { target: Some(ref mut t), unwind: _, .. } - | Yield { resume: ref mut t, drop: None, .. } - | Drop { target: ref mut t, unwind: _, .. } - | Assert { target: ref mut t, unwind: _, .. } - | FalseUnwind { real_target: ref mut t, unwind: _ } => { - slice::from_mut(t).into_iter().chain(None.into_iter().chain(None)) + Yield { resume, drop, .. } => { + f(resume); + if let Some(d) = drop { + f(d) + } + } + Assert { target, unwind, .. } | FalseUnwind { real_target: target, unwind } => { + f(target); + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } + } + Goto { target } => { + f(target); } - // No successors UnwindResume | UnwindTerminate(_) | CoroutineDrop | Return | Unreachable - | TailCall { .. } - | Call { target: None, unwind: _, .. } => { - (&mut []).into_iter().chain(None.into_iter().chain(None)) + | TailCall { .. } => {} + InlineAsm { targets, unwind, .. } => { + for target in targets { + f(target); + } + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } } - // Multiple successors - InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => { - targets.iter_mut().chain(Some(u).into_iter().chain(None)) + SwitchInt { targets, .. } => { + for target in &mut targets.targets { + f(target); + } } - InlineAsm { ref mut targets, unwind: _, .. } => { - targets.iter_mut().chain(None.into_iter().chain(None)) - } - SwitchInt { ref mut targets, .. } => { - targets.targets.iter_mut().chain(None.into_iter().chain(None)) - } - // FalseEdge - FalseEdge { ref mut real_target, ref mut imaginary_target } => { - slice::from_mut(real_target) - .into_iter() - .chain(Some(imaginary_target).into_iter().chain(None)) + FalseEdge { real_target, imaginary_target } => { + f(real_target); + f(imaginary_target); } } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 263f0c40f5a5..66f106bec6fc 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1064,10 +1064,8 @@ fn insert_switch<'tcx>( }, ); - let blocks = body.basic_blocks_mut().iter_mut(); - - for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target += 1; + for b in body.basic_blocks_mut().iter_mut() { + b.terminator_mut().successors_mut(|target| *target += 1); } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9732225e48dd..f1f5bcaaab11 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -765,12 +765,12 @@ impl OpportunitySet { // Replace `succ` by `new_succ` where it appears. let mut num_edges = 0; - for s in basic_blocks[current].terminator_mut().successors_mut() { + basic_blocks[current].terminator_mut().successors_mut(|s| { if *s == succ { *s = new_succ; num_edges += 1; } - } + }); // Update predecessors with the new block. let _new_succ = self.predecessors.push(num_edges); diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index 8ccfbe2f194b..8217feff24ec 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -115,9 +115,7 @@ impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> { } fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) { - for succ in terminator.successors_mut() { - *succ = self.map[*succ]; - } + terminator.successors_mut(|succ| *succ = self.map[*succ]); } } diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 1dd34005d664..797056ad52d4 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -58,13 +58,13 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads { } } - for target in body[bb].terminator_mut().successors_mut() { + body[bb].terminator_mut().successors_mut(|target| { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); *target = resume_block; jumps_folded += 1; } - } + }); let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); if is_nop_landing_pad { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 4f2cce8ac104..8f88228d9bbd 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -147,9 +147,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { let mut terminator = self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); - for successor in terminator.successors_mut() { - self.collapse_goto_chain(successor, &mut changed); - } + terminator + .successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed)); let mut inner_changed = true; merged_blocks.clear(); @@ -375,9 +374,7 @@ pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { } for block in basic_blocks { - for target in block.terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } + block.terminator_mut().successors_mut(|target| *target = replacements[target.index()]); } } From 47e111a03c543859010cc7677617cd940ea42753 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Apr 2025 17:08:51 +0200 Subject: [PATCH 080/302] move EnvVars::cleanup into the main-thread-exit handler --- src/tools/miri/src/eval.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 7586b5efd4b2..1ca11b05f0ee 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -265,6 +265,17 @@ impl<'tcx> MainThreadState<'tcx> { // Deal with our thread-local memory. We do *not* want to actually free it, instead we consider TLS // to be like a global `static`, so that all memory reached by it is considered to "not leak". this.terminate_active_thread(TlsAllocAction::Leak)?; + + // Machine cleanup. Only do this if all threads have terminated; threads that are still running + // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). + if this.have_all_terminated() { + // Even if all threads have terminated, we have to beware of data races since some threads + // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020, + // https://github.com/rust-lang/miri/issues/2508). + this.allow_data_races_all_threads_done(); + EnvVars::cleanup(this).expect("error during env var cleanup"); + } + // Stop interpreter loop. throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true }); } @@ -467,16 +478,6 @@ pub fn eval_entry<'tcx>( // If we get here there was no fatal error. - // Machine cleanup. Only do this if all threads have terminated; threads that are still running - // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). - if ecx.have_all_terminated() { - // Even if all threads have terminated, we have to beware of data races since some threads - // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020, - // https://github.com/rust-lang/miri/issues/2508). - ecx.allow_data_races_all_threads_done(); - EnvVars::cleanup(&mut ecx).expect("error during env var cleanup"); - } - // Possibly check for memory leaks. if leak_check && !ignore_leaks { // Check for thread leaks. From 76992ce41e49d03bda37de4308fa6324111fb3b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Apr 2025 17:24:48 +0200 Subject: [PATCH 081/302] fix comment typos --- src/tools/miri/src/concurrency/thread.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d640e7777e59..f8ff47e71137 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -728,7 +728,7 @@ impl<'tcx> ThreadManager<'tcx> { } // No callbacks immediately scheduled, pick a regular thread to execute. // The active thread blocked or yielded. So we go search for another enabled thread. - // We build the list of threads by starting with the thread after the current one, followed by + // We build the list of threads by starting with the threads after the current one, followed by // the threads before the current one and then the current thread itself (i.e., this iterator acts // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step. @@ -752,7 +752,7 @@ impl<'tcx> ThreadManager<'tcx> { self.active_thread = id; } } - //This completes the `yield`, if any was requested. + // This completes the `yield`, if any was requested. self.yield_active_thread = false; if self.threads[self.active_thread].state.is_enabled() { From 0e139b899500a98af440e40e5dd1bf2c967a52f7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Apr 2025 19:25:11 +0200 Subject: [PATCH 082/302] Update salsa --- src/tools/rust-analyzer/Cargo.lock | 12 ++-- src/tools/rust-analyzer/Cargo.toml | 2 +- .../rust-analyzer/crates/base-db/src/lib.rs | 58 +++++++++++++++++-- .../rust-analyzer/src/cli/rustc_tests.rs | 3 +- .../crates/rust-analyzer/src/diagnostics.rs | 4 +- .../rust-analyzer/src/handlers/dispatch.rs | 18 +++--- .../rust-analyzer/crates/span/src/hygiene.rs | 9 +-- src/tools/rust-analyzer/xtask/src/util.rs | 2 +- 8 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9f6b80c63790..1542084d726a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2033,9 +2033,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be22155f8d9732518b2db2bf379fe6f0b2375e76b08b7c8fe6c1b887d548c24" +checksum = "4deeb38b4c80ac90a8d4796f83da941b0d76c23783550d15d37eb43ccddcb5bc" dependencies = [ "boxcar", "crossbeam-queue", @@ -2056,15 +2056,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55a7ef0a84e336f7c5f0332d81727f5629fe042d2aa556c75307afebc9f78a5" +checksum = "a4e6166fa2802d86a77dbcae1bfe75f0ac46fdf952660c233ed64855a53dd603" [[package]] name = "salsa-macros" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d0e88a9c0c0d231a63f83dcd1a2c5e5d11044fac4b65bc9ad3b68ab48b0a0ab" +checksum = "bf358e645a835d9901ee4d812d9812266e046ee92a28d2e37a73b7169a6503b7" dependencies = [ "heck", "proc-macro2", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 6fa171702dd4..191820d4e3f5 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,7 +131,7 @@ process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" -salsa = "0.20.0" +salsa = "0.21.0" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 1d73ba804a68..9275a58687ff 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -3,7 +3,7 @@ mod change; mod input; -use std::hash::BuildHasherDefault; +use std::{cell::RefCell, hash::BuildHasherDefault, panic, sync::Once}; pub use crate::{ change::FileChange, @@ -60,7 +60,7 @@ impl Files { match self.files.get(&file_id) { Some(text) => *text, None => { - panic!("Unable to fetch file text for `vfs::FileId`: {:?}; this is a bug", file_id) + panic!("Unable to fetch file text for `vfs::FileId`: {file_id:?}; this is a bug") } } } @@ -101,8 +101,7 @@ impl Files { let source_root = match self.source_roots.get(&source_root_id) { Some(source_root) => source_root, None => panic!( - "Unable to fetch `SourceRootInput` with `SourceRootId` ({:?}); this is a bug", - source_root_id + "Unable to fetch `SourceRootInput` with `SourceRootId` ({source_root_id:?}); this is a bug" ), }; @@ -132,8 +131,7 @@ impl Files { let file_source_root = match self.file_source_roots.get(&id) { Some(file_source_root) => file_source_root, None => panic!( - "Unable to get `FileSourceRootInput` with `vfs::FileId` ({:?}); this is a bug", - id + "Unable to get `FileSourceRootInput` with `vfs::FileId` ({id:?}); this is a bug", ), }; *file_source_root @@ -384,3 +382,51 @@ fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> { let source_root = db.file_source_root(file_id); db.source_root_crates(source_root.source_root_id(db)) } + +#[must_use] +pub struct DbPanicContext { + // prevent arbitrary construction + _priv: (), +} + +impl Drop for DbPanicContext { + fn drop(&mut self) { + Self::with_ctx(|ctx| assert!(ctx.pop().is_some())); + } +} + +impl DbPanicContext { + pub fn enter(frame: String) -> DbPanicContext { + #[expect(clippy::print_stderr, reason = "already panicking anyway")] + fn set_hook() { + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |panic_info| { + DbPanicContext::with_ctx(|ctx| { + if !ctx.is_empty() { + eprintln!("Panic context:"); + for frame in ctx.iter() { + eprintln!("> {frame}\n"); + } + } + }); + if let Some(backtrace) = salsa::Backtrace::capture() { + eprintln!("{backtrace}"); + } + default_hook(panic_info); + })); + } + + static SET_HOOK: Once = Once::new(); + SET_HOOK.call_once(set_hook); + + Self::with_ctx(|ctx| ctx.push(frame)); + DbPanicContext { _priv: () } + } + + fn with_ctx(f: impl FnOnce(&mut Vec)) { + thread_local! { + static CTX: RefCell> = const { RefCell::new(Vec::new()) }; + } + CTX.with(|ctx| f(&mut ctx.borrow_mut())); + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index c042c26bd188..e3b372c91494 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -7,6 +7,7 @@ use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::Path use hir::{ChangeWithProcMacros, Crate}; use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; +use ide_db::base_db; use itertools::Either; use paths::Utf8PathBuf; use profile::StopWatch; @@ -310,7 +311,7 @@ impl flags::RustcTests { let tester = AssertUnwindSafe(&mut tester); let p = p.clone(); move || { - let _guard = stdx::panic_context::enter(p.display().to_string()); + let _guard = base_db::DbPanicContext::enter(p.display().to_string()); { tester }.0.test(p); } }) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 9b1463b1126b..438a2a0ba1ea 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -5,7 +5,7 @@ use std::mem; use cargo_metadata::PackageId; use ide::FileId; -use ide_db::FxHashMap; +use ide_db::{FxHashMap, base_db::DbPanicContext}; use itertools::Itertools; use rustc_hash::FxHashSet; use stdx::iter_eq_by; @@ -215,7 +215,7 @@ pub(crate) fn fetch_native_diagnostics( kind: NativeDiagnosticsFetchKind, ) -> Vec<(FileId, Vec)> { let _p = tracing::info_span!("fetch_native_diagnostics").entered(); - let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned()); + let _ctx = DbPanicContext::enter("fetch_native_diagnostics".to_owned()); // the diagnostics produced may point to different files not requested by the concrete request, // put those into here and filter later diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index 3b76edf528b6..f04ada38893a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -4,7 +4,10 @@ use std::{ panic, thread, }; -use ide_db::base_db::salsa::{self, Cancelled}; +use ide_db::base_db::{ + DbPanicContext, + salsa::{self, Cancelled}, +}; use lsp_server::{ExtractError, Response, ResponseError}; use serde::{Serialize, de::DeserializeOwned}; use stdx::thread::ThreadIntent; @@ -56,7 +59,7 @@ impl RequestDispatcher<'_> { tracing::info_span!("request", method = ?req.method, "request_id" = ?req.id).entered(); tracing::debug!(?params); let result = { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(self.global_state, params) }; if let Ok(response) = result_to_response::(req.id, result) { @@ -86,7 +89,7 @@ impl RequestDispatcher<'_> { let global_state_snapshot = self.global_state.snapshot(); let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(global_state_snapshot, params) }); @@ -257,7 +260,7 @@ impl RequestDispatcher<'_> { } .spawn(intent, move || { let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(world, params) }); match thread_result_to_response::(req.id.clone(), result) { @@ -421,11 +424,8 @@ impl NotificationDispatcher<'_> { tracing::debug!(?params); - let _pctx = stdx::panic_context::enter(format!( - "\nversion: {}\nnotification: {}", - version(), - N::METHOD - )); + let _pctx = + DbPanicContext::enter(format!("\nversion: {}\nnotification: {}", version(), N::METHOD)); if let Err(e) = f(self.global_state, params) { tracing::error!(handler = %N::METHOD, error = %e, "notification handler failed"); } diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index d1e75d97d7a7..7bb88ac3658c 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -94,16 +94,11 @@ const _: () = { } } impl zalsa_struct_::Configuration for SyntaxContext { + const LOCATION: salsa::plumbing::Location = + salsa::plumbing::Location { file: file!(), line: line!() }; const DEBUG_NAME: &'static str = "SyntaxContextData"; type Fields<'a> = SyntaxContextData; type Struct<'a> = SyntaxContext; - fn struct_from_id<'db>(id: salsa::Id) -> Self::Struct<'db> { - SyntaxContext::from_salsa_id(id) - } - fn deref_struct(s: Self::Struct<'_>) -> salsa::Id { - s.as_salsa_id() - .expect("`SyntaxContext::deref_structs()` called on a root `SyntaxContext`") - } } impl SyntaxContext { pub fn ingredient(db: &Db) -> &zalsa_struct_::IngredientImpl diff --git a/src/tools/rust-analyzer/xtask/src/util.rs b/src/tools/rust-analyzer/xtask/src/util.rs index a740ad6afdcb..e5404d571717 100644 --- a/src/tools/rust-analyzer/xtask/src/util.rs +++ b/src/tools/rust-analyzer/xtask/src/util.rs @@ -37,7 +37,7 @@ pub(crate) fn detect_target(sh: &Shell) -> String { Ok(target) => target, _ => match cmd!(sh, "rustc --print=host-tuple").read() { Ok(target) => target, - Err(e) => panic!("Failed to detect target: {}\nPlease set RA_TARGET explicitly", e), + Err(e) => panic!("Failed to detect target: {e}\nPlease set RA_TARGET explicitly"), }, } } From e9d2fefe0cfa083965b83288f38e408df7f1cdd1 Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 30 Apr 2025 01:29:44 +0800 Subject: [PATCH 083/302] stop check paren if has different ctx --- compiler/rustc_lint/src/unused.rs | 16 +++++ ...sed-parens-for-macro-call-with-brace.fixed | 28 ++++++++ ...unused-parens-for-macro-call-with-brace.rs | 28 ++++++++ ...ed-parens-for-macro-call-with-brace.stderr | 67 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.rs create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 806bca78f787..50a27d7e84f5 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -942,6 +942,22 @@ trait UnusedDelimLint { match s.kind { StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some((init, els)) = local.kind.init_else_opt() { + if els.is_some() + && let ExprKind::Paren(paren) = &init.kind + && !init.span.eq_ctxt(paren.span) + { + // This branch prevents cases where parentheses wrap an expression + // resulting from macro expansion, such as: + // ``` + // macro_rules! x { + // () => { None:: }; + // } + // let Some(_) = (x!{}) else { return }; + // // -> let Some(_) = (None::) else { return }; + // // ~ ~ No Lint + // ``` + return; + } let ctx = match els { None => UnusedDelimsCtx::AssignedValue, Some(_) => UnusedDelimsCtx::AssignedValueLetElse, diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed b/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed new file mode 100644 index 000000000000..4c9995fcb61a --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed @@ -0,0 +1,28 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +fn main() { + macro_rules! x { + () => { None:: }; + } + + let Some(_) = (x!{}) else { return }; // no error + let Some(_) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around assigned value + + let Some(_) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around pattern + + let _ = x!{}; + let _ = x!{}; + //~^ ERROR: unnecessary parentheses around assigned value + + if let Some(_) = x!{} {}; + if let Some(_) = x!{} {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression + + while let Some(_) = x!{} {}; + while let Some(_) = x!{} {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression +} diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs b/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs new file mode 100644 index 000000000000..59e215a48cca --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs @@ -0,0 +1,28 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +fn main() { + macro_rules! x { + () => { None:: }; + } + + let Some(_) = (x!{}) else { return }; // no error + let Some(_) = ((x!{})) else { return }; + //~^ ERROR: unnecessary parentheses around assigned value + + let Some((_)) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around pattern + + let _ = x!{}; + let _ = (x!{}); + //~^ ERROR: unnecessary parentheses around assigned value + + if let Some(_) = x!{} {}; + if let Some(_) = (x!{}) {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression + + while let Some(_) = x!{} {}; + while let Some(_) = (x!{}) {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression +} diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr b/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr new file mode 100644 index 000000000000..8d3b4fe493e2 --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr @@ -0,0 +1,67 @@ +error: unnecessary parentheses around assigned value + --> $DIR/unused-parens-for-macro-call-with-brace.rs:11:19 + | +LL | let Some(_) = ((x!{})) else { return }; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-for-macro-call-with-brace.rs:3:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let Some(_) = ((x!{})) else { return }; +LL + let Some(_) = (x!{}) else { return }; + | + +error: unnecessary parentheses around pattern + --> $DIR/unused-parens-for-macro-call-with-brace.rs:14:14 + | +LL | let Some((_)) = (x!{}) else { return }; + | ^ ^ + | +help: remove these parentheses + | +LL - let Some((_)) = (x!{}) else { return }; +LL + let Some(_) = (x!{}) else { return }; + | + +error: unnecessary parentheses around assigned value + --> $DIR/unused-parens-for-macro-call-with-brace.rs:18:13 + | +LL | let _ = (x!{}); + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = (x!{}); +LL + let _ = x!{}; + | + +error: unnecessary parentheses around `let` scrutinee expression + --> $DIR/unused-parens-for-macro-call-with-brace.rs:22:22 + | +LL | if let Some(_) = (x!{}) {}; + | ^ ^ + | +help: remove these parentheses + | +LL - if let Some(_) = (x!{}) {}; +LL + if let Some(_) = x!{} {}; + | + +error: unnecessary parentheses around `let` scrutinee expression + --> $DIR/unused-parens-for-macro-call-with-brace.rs:26:25 + | +LL | while let Some(_) = (x!{}) {}; + | ^ ^ + | +help: remove these parentheses + | +LL - while let Some(_) = (x!{}) {}; +LL + while let Some(_) = x!{} {}; + | + +error: aborting due to 5 previous errors + From 3f92794939d6cdc4919aa44e25fc1dafa80ba8de Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Apr 2025 19:43:36 +0200 Subject: [PATCH 084/302] Split out salsa_macros Does not do much yet due to tracing pulling syn but oh well --- src/tools/rust-analyzer/Cargo.lock | 6 ++++++ src/tools/rust-analyzer/Cargo.toml | 3 ++- .../rust-analyzer/crates/base-db/Cargo.toml | 1 + .../rust-analyzer/crates/base-db/src/input.rs | 2 +- .../rust-analyzer/crates/base-db/src/lib.rs | 19 +++++++++++-------- .../rust-analyzer/crates/hir-def/Cargo.toml | 1 + .../crates/hir-def/src/lang_item.rs | 4 ++-- .../rust-analyzer/crates/hir-def/src/lib.rs | 14 +++++++------- .../crates/hir-def/src/test_db.rs | 6 +++--- .../crates/hir-expand/Cargo.toml | 1 + .../crates/hir-expand/src/change.rs | 3 +-- .../rust-analyzer/crates/hir-expand/src/db.rs | 2 +- .../crates/hir-expand/src/lib.rs | 4 ++-- .../rust-analyzer/crates/hir-ty/Cargo.toml | 1 + .../rust-analyzer/crates/hir-ty/src/lower.rs | 4 ++-- .../crates/hir-ty/src/test_db.rs | 6 +++--- .../rust-analyzer/crates/ide-db/Cargo.toml | 1 + .../rust-analyzer/crates/ide-db/src/lib.rs | 6 +++--- .../crates/query-group-macro/Cargo.toml | 1 + .../crates/query-group-macro/src/lib.rs | 8 ++++---- .../crates/query-group-macro/src/queries.rs | 2 +- .../query-group-macro/tests/interned.rs | 2 +- .../query-group-macro/tests/logger_db.rs | 4 ++-- .../query-group-macro/tests/old_and_new.rs | 8 ++++---- .../query-group-macro/tests/supertrait.rs | 2 +- 25 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 1542084d726a..d257988a57a0 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -85,6 +85,7 @@ dependencies = [ "query-group-macro", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "semver", "span", "syntax", @@ -630,6 +631,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustc_apfloat", "salsa", + "salsa-macros", "smallvec", "span", "stdx", @@ -660,6 +662,7 @@ dependencies = [ "query-group-macro", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "smallvec", "span", "stdx", @@ -700,6 +703,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustc_apfloat", "salsa", + "salsa-macros", "scoped-tls", "smallvec", "span", @@ -936,6 +940,7 @@ dependencies = [ "rayon", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "span", "stdx", "syntax", @@ -1729,6 +1734,7 @@ dependencies = [ "proc-macro2", "quote", "salsa", + "salsa-macros", "syn", ] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 191820d4e3f5..a29717d67abe 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,7 +131,8 @@ process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" -salsa = "0.21.0" +salsa = { version = "0.21.0", default-features = false, features = ["rayon","salsa_unstable"] } +salsa-macros = "0.21.0" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 441434504c29..e2e3253773fe 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -15,6 +15,7 @@ rust-version.workspace = true la-arena.workspace = true dashmap.workspace = true salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true rustc-hash.workspace = true triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 499c9b3716b2..9660e6e87cca 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -392,7 +392,7 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; -#[salsa::input] +#[salsa_macros::input] #[derive(Debug)] pub struct Crate { #[return_ref] diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 9275a58687ff..f7f4e024ef23 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,4 +1,8 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. + +pub use salsa; +pub use salsa_macros; + // FIXME: Rename this crate, base db is non descriptive mod change; mod input; @@ -17,7 +21,6 @@ pub use crate::{ use dashmap::{DashMap, mapref::entry::Entry}; pub use query_group::{self}; use rustc_hash::{FxHashSet, FxHasher}; -pub use salsa::{self}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; use span::Edition; @@ -28,7 +31,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet} #[macro_export] macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { - #[salsa::interned(no_lifetime)] + #[salsa_macros::interned(no_lifetime)] pub struct $id { pub loc: $loc, } @@ -161,7 +164,7 @@ impl Files { } } -#[salsa::interned(no_lifetime, debug, constructor=from_span)] +#[salsa_macros::interned(no_lifetime, debug, constructor=from_span)] pub struct EditionedFileId { pub editioned_file_id: span::EditionedFileId, } @@ -196,18 +199,18 @@ impl EditionedFileId { } } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct FileText { pub text: Arc, pub file_id: vfs::FileId, } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct FileSourceRootInput { pub source_root_id: SourceRootId, } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct SourceRootInput { pub source_root: Arc, } @@ -274,7 +277,7 @@ pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet FileText; @@ -353,7 +356,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse Option<&[SyntaxError]> { - #[salsa::tracked(return_ref)] + #[salsa_macros::tracked(return_ref)] fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option> { let errors = db.parse(file_id).errors(); match &*errors { diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index f97597ffe5a6..c1c89e8d1cc3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -28,6 +28,7 @@ triomphe.workspace = true rustc_apfloat = "0.2.2" text-size.workspace = true salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true ra-ap-rustc_parse_format.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 6a4ac199b340..51a833b5f150 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -84,7 +84,7 @@ impl LangItemTarget { } /// Salsa query. This will look for lang items in a specific crate. -#[salsa::tracked(return_ref)] +#[salsa_macros::tracked(return_ref)] pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); @@ -153,7 +153,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option for GenericDefId { } } -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum CallableDefId { FunctionId(FunctionId), StructId(StructId), @@ -906,7 +906,7 @@ impl From for AttrDefId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum VariantId { EnumVariantId(EnumVariantId), StructId(StructId), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 2f7675134ca7..470975482951 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -19,7 +19,7 @@ use crate::{ src::HasSource, }; -#[salsa::db] +#[salsa_macros::db] #[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, @@ -44,7 +44,7 @@ impl Default for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for TestDB { fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { let mut events = self.events.lock().unwrap(); @@ -63,7 +63,7 @@ impl fmt::Debug for TestDB { impl panic::RefUnwindSafe for TestDB {} -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index b83efca25528..ed818c5be3f7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -21,6 +21,7 @@ smallvec.workspace = true triomphe.workspace = true query-group.workspace = true salsa.workspace = true +salsa-macros.workspace = true # local deps stdx.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index 6873cb7eaf9c..3959741e6f13 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -1,7 +1,6 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use base_db::{CrateGraphBuilder, FileChange, SourceRoot}; -use salsa::Durability; +use base_db::{CrateGraphBuilder, FileChange, SourceRoot, salsa::Durability}; use span::FileId; use triomphe::Arc; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 67391dbd955a..7cb1b6c02075 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -144,7 +144,7 @@ pub trait ExpandDatabase: RootQueryDb { fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext; } -#[salsa::interned(no_lifetime, id = span::SyntaxContext)] +#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext)] pub struct SyntaxContextWrapper { pub data: SyntaxContext, } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index ad35f7000a14..d844d8f41eef 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -1050,7 +1050,7 @@ impl ExpandTo { intern::impl_internable!(ModPath, attrs::AttrInput); -#[salsa::interned(no_lifetime, debug)] +#[salsa_macros::interned(no_lifetime, debug)] #[doc(alias = "MacroFileId")] pub struct MacroCallId { pub loc: MacroCallLoc, @@ -1070,7 +1070,7 @@ impl From for span::MacroCallId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum HirFileId { FileId(EditionedFileId), MacroFile(MacroCallId), diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 69ad7703c2ca..efa544cf3965 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -34,6 +34,7 @@ indexmap.workspace = true rustc_apfloat = "0.2.2" query-group.workspace = true salsa.workspace = true +salsa-macros.workspace = true ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 6d7e58bea6a2..9def39d5f979 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1468,7 +1468,7 @@ fn type_for_enum_variant_constructor( } } -#[salsa::tracked(cycle_result = type_for_adt_cycle_result)] +#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)] fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders { type_for_adt(db, adt) } @@ -1533,7 +1533,7 @@ pub enum TyDefId { } impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum ValueTyDefId { FunctionId(FunctionId), StructId(StructId), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index d2bba120b68e..bcd8aa6c4e95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -16,7 +16,7 @@ use syntax::TextRange; use test_utils::extract_annotations; use triomphe::Arc; -#[salsa::db] +#[salsa_macros::db] #[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, @@ -47,7 +47,7 @@ impl fmt::Debug for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) @@ -102,7 +102,7 @@ impl SourceDatabase for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for TestDB { fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { let mut events = self.events.lock().unwrap(); diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index f1d6b605b002..583318de26df 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -24,6 +24,7 @@ arrayvec.workspace = true indexmap.workspace = true memchr = "2.7.4" salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true triomphe.workspace = true nohash-hasher.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index a433f184e765..63cc7cde2808 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -76,7 +76,7 @@ pub type FxIndexMap = pub type FilePosition = FilePositionWrapper; pub type FileRange = FileRangeWrapper; -#[salsa::db] +#[salsa_macros::db] pub struct RootDatabase { // FIXME: Revisit this commit now that we migrated to the new salsa, given we store arcs in this // db directly now @@ -91,7 +91,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for RootDatabase { fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {} } @@ -118,7 +118,7 @@ impl fmt::Debug for RootDatabase { } } -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for RootDatabase { fn file_text(&self, file_id: vfs::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml index 8aeb26294231..8b03d8f8cc7a 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml +++ b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml @@ -20,3 +20,4 @@ syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] } [dev-dependencies] expect-test = "1.5.1" salsa.workspace = true +salsa-macros.workspace = true diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index 3ade12733a75..6b81928c91e1 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -178,7 +178,7 @@ pub(crate) fn query_group_impl( let supertraits = &item_trait.supertraits; let db_attr: Attribute = parse_quote! { - #[salsa::db] + #[salsa_macros::db] }; item_trait.attrs.push(db_attr); @@ -407,7 +407,7 @@ pub(crate) fn query_group_impl( .collect::>(); let input_struct = quote! { - #[salsa::input] + #[salsa_macros::input] pub(crate) struct #input_struct_name { #(#fields),* } @@ -418,7 +418,7 @@ pub(crate) fn query_group_impl( let create_data_method = quote! { #[allow(non_snake_case)] - #[salsa::tracked] + #[salsa_macros::tracked] fn #create_data_ident(db: &dyn #trait_name_ident) -> #input_struct_name { #input_struct_name::new(db, #(#field_params),*) } @@ -443,7 +443,7 @@ pub(crate) fn query_group_impl( item_trait.items.append(&mut lookup_signatures); let trait_impl = quote! { - #[salsa::db] + #[salsa_macros::db] impl #trait_name_ident for DB where DB: #supertraits, diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs index d4d40588bfc7..baac3e8bbfe7 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs @@ -49,7 +49,7 @@ impl ToTokens for TrackedQuery { }) .into_iter() .chain(self.lru.map(|lru| quote!(lru = #lru))); - let annotation = quote!(#[salsa::tracked( #(#options),* )]); + let annotation = quote!(#[salsa_macros::tracked( #(#options),* )]); let pat_and_tys = &self.pat_and_tys; let params = self diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs index 26ed316122a5..f738185b1fe7 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs @@ -6,7 +6,7 @@ use salsa::plumbing::AsId; mod logger_db; use logger_db::LoggerDb; -#[salsa::interned(no_lifetime)] +#[salsa_macros::interned(no_lifetime)] pub struct InternedString { data: String, } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs index 0bb86467c78b..bade0c2cd6fa 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -#[salsa::db] +#[salsa_macros::db] #[derive(Default, Clone)] pub(crate) struct LoggerDb { storage: salsa::Storage, @@ -12,7 +12,7 @@ struct Logger { logs: Arc>>, } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for LoggerDb { fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) { let event = event(); diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs index a18b23a7d8a9..cc57ba78455f 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs @@ -4,7 +4,7 @@ mod logger_db; use logger_db::LoggerDb; use query_group_macro::query_group; -#[salsa::input] +#[salsa_macros::input] struct Input { str: String, } @@ -30,7 +30,7 @@ fn invoke_length_query_actual(db: &dyn PartialMigrationDatabase, input: Input) - input.str(db).len() } -#[salsa::tracked] +#[salsa_macros::tracked] fn invoke_length_tracked_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { input.str(db).len() } @@ -87,12 +87,12 @@ fn invoke_tracked_query() { fn new_salsa_baseline() { let db = LoggerDb::default(); - #[salsa::input] + #[salsa_macros::input] struct Input { str: String, } - #[salsa::tracked] + #[salsa_macros::tracked] fn new_salsa_length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { input.str(db).len() } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs index 70073ac1de32..ad8ada3ef153 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs @@ -1,6 +1,6 @@ use query_group_macro::query_group; -#[salsa::db] +#[salsa_macros::db] pub trait SourceDb: salsa::Database { /// Text of the file. fn file_text(&self, id: usize) -> String; From bbcc6a24cdd3c77927e159bf4cbc55eca4c62281 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Apr 2025 19:02:11 +0200 Subject: [PATCH 085/302] add -Zmiri-deterministic-concurrency flag and use it for concurrency tests --- src/tools/miri/README.md | 52 ++++++++++++------- src/tools/miri/src/bin/miri.rs | 5 ++ .../concurrency/libc_pthread_join_self.rs | 2 +- .../libc_pthread_mutex_deadlock.rs | 2 + ...libc_pthread_rwlock_write_read_deadlock.rs | 2 + ...ibc_pthread_rwlock_write_write_deadlock.rs | 2 + .../fail-dep/concurrency/windows_join_main.rs | 2 +- .../fail-dep/concurrency/windows_join_self.rs | 2 +- .../fail-dep/libc/env-set_var-data-race.rs | 2 +- .../fail-dep/libc/eventfd_block_read_twice.rs | 2 +- .../libc/eventfd_block_write_twice.rs | 2 +- .../fail-dep/libc/libc-epoll-data-race.rs | 2 +- .../libc/libc_epoll_block_two_thread.rs | 2 +- .../libc/socketpair-close-while-blocked.rs | 2 +- .../fail-dep/libc/socketpair-data-race.rs | 2 +- .../libc/socketpair_block_read_twice.rs | 2 +- .../libc/socketpair_block_write_twice.rs | 2 +- .../both_borrows/retag_data_race_write.rs | 4 +- .../tests/fail/data_race/alloc_read_race.rs | 5 +- .../tests/fail/data_race/alloc_write_race.rs | 5 +- .../data_race/atomic_read_na_write_race1.rs | 4 +- .../data_race/atomic_read_na_write_race2.rs | 4 +- .../data_race/atomic_write_na_read_race1.rs | 4 +- .../data_race/atomic_write_na_read_race2.rs | 4 +- .../data_race/atomic_write_na_write_race1.rs | 4 +- .../data_race/atomic_write_na_write_race2.rs | 4 +- .../data_race/dangling_thread_async_race.rs | 4 +- .../fail/data_race/dangling_thread_race.rs | 4 +- .../fail/data_race/dealloc_read_race1.rs | 4 +- .../fail/data_race/dealloc_read_race2.rs | 4 +- .../fail/data_race/dealloc_read_race_stack.rs | 5 +- .../fail/data_race/dealloc_write_race1.rs | 4 +- .../fail/data_race/dealloc_write_race2.rs | 4 +- .../data_race/dealloc_write_race_stack.rs | 5 +- .../data_race/enable_after_join_to_main.rs | 4 +- .../tests/fail/data_race/fence_after_load.rs | 4 +- .../data_race/local_variable_alloc_race.rs | 2 +- .../data_race/local_variable_read_race.rs | 2 +- .../data_race/local_variable_write_race.rs | 2 +- .../data_race/mixed_size_read_read_write.rs | 4 +- .../fail/data_race/mixed_size_read_write.rs | 4 +- .../fail/data_race/mixed_size_write_write.rs | 4 +- .../tests/fail/data_race/read_write_race.rs | 4 +- .../fail/data_race/read_write_race_stack.rs | 5 +- .../fail/data_race/relax_acquire_race.rs | 5 +- .../tests/fail/data_race/release_seq_race.rs | 5 +- .../data_race/release_seq_race_same_thread.rs | 5 +- .../miri/tests/fail/data_race/rmw_race.rs | 5 +- .../tests/fail/data_race/stack_pop_race.rs | 5 +- .../tests/fail/data_race/write_write_race.rs | 6 +-- .../fail/data_race/write_write_race_stack.rs | 5 +- .../retag_data_race_protected_read.rs | 3 +- .../stacked_borrows/retag_data_race_read.rs | 3 +- .../tree_borrows/reservedim_spurious_write.rs | 2 +- .../tests/fail/tree_borrows/spurious_read.rs | 6 +-- .../tests/pass-dep/concurrency/apple-futex.rs | 2 +- .../concurrency/env-cleanup-data-race.rs | 2 +- .../pass-dep/concurrency/freebsd-futex.rs | 2 +- .../concurrency/windows_detach_terminated.rs | 2 +- .../pass-dep/concurrency/windows_init_once.rs | 2 +- .../concurrency/windows_join_multiple.rs | 2 +- .../pass-dep/libc/libc-epoll-blocking.rs | 2 +- .../miri/tests/pass-dep/libc/libc-eventfd.rs | 2 +- .../miri/tests/pass-dep/libc/libc-pipe.rs | 2 +- .../tests/pass-dep/libc/libc-socketpair.rs | 2 +- .../miri/tests/pass-dep/libc/pthread-sync.rs | 2 +- .../miri/tests/pass/concurrency/data_race.rs | 3 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 2 +- src/tools/miri/tests/pass/concurrency/sync.rs | 2 +- .../tests/pass/concurrency/sync_nopreempt.rs | 2 +- .../miri/tests/pass/panic/concurrent-panic.rs | 2 +- src/tools/miri/tests/pass/shims/env/var.rs | 2 +- .../pass/tree_borrows/read_retag_no_race.rs | 2 +- .../tests/pass/tree_borrows/spurious_read.rs | 2 +- 75 files changed, 129 insertions(+), 156 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 95e1770aa7ba..d318222f7ff3 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -277,22 +277,15 @@ Try running `cargo miri clean`. Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable. We first document the most relevant and most commonly used flags: -* `-Zmiri-address-reuse-rate=` changes the probability that a freed *non-stack* allocation - will be added to the pool for address reuse, and the probability that a new *non-stack* allocation - will be taken from the pool. Stack allocations never get added to or taken from the pool. The - default is `0.5`. -* `-Zmiri-address-reuse-cross-thread-rate=` changes the probability that an allocation which - attempts to reuse a previously freed block of memory will also consider blocks freed by *other - threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse - attempt is made, only addresses from the same thread will be considered. Reusing an address from - another thread induces synchronization between those threads, which can mask data races and weak - memory bugs. -* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). - You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. Note that setting it to - `1.0` will likely cause hangs, since it means programs using - `compare_exchange_weak` cannot make progress. +* `-Zmiri-deterministic-concurrency` makes Miri's concurrency-related behavior fully deterministic. + Strictly speaking, Miri is always fully deterministic when isolation is enabled (the default + mode), but this determinism is achieved by using an RNG with a fixed seed. Seemingly harmless + changes to the program, or just running it for a different target architecture, can thus lead to + completely different program behavior down the line. This flag disables the use of an RNG for + concurrency-related decisions. Therefore, Miri cannot find bugs that only occur under some + specific circumstances, but Miri's behavior will also be more stable across versions and targets. + This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0 + -Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -334,9 +327,6 @@ environment variable. We first document the most relevant and most commonly used This will necessarily miss some bugs as those operations are not efficiently and accurately implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is subject to these operations. -* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active - thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables - preemption. * `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can tell what it is doing when a program just keeps running. You can customize how frequently the report is printed via `-Zmiri-report-progress=`, which prints the report every N basic @@ -365,6 +355,22 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. +* `-Zmiri-address-reuse-rate=` changes the probability that a freed *non-stack* allocation + will be added to the pool for address reuse, and the probability that a new *non-stack* allocation + will be taken from the pool. Stack allocations never get added to or taken from the pool. The + default is `0.5`. +* `-Zmiri-address-reuse-cross-thread-rate=` changes the probability that an allocation which + attempts to reuse a previously freed block of memory will also consider blocks freed by *other + threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse + attempt is made, only addresses from the same thread will be considered. Reusing an address from + another thread induces synchronization between those threads, which can mask data races and weak + memory bugs. +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. Note that setting it to + `1.0` will likely cause hangs, since it means programs using + `compare_exchange_weak` cannot make progress. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -383,6 +389,10 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. +* `-Zmiri-fixed-schedule` disables preemption (like `-Zmiri-preemption-rate=0.0`) and furthermore + disables the randomization of the next thread to be picked, instead fixing a round-robin schedule. + Note however that other aspects of Miri's concurrency behavior are still randomize; use + `-Zmiri-deterministic-concurrency` to disable them all. * `-Zmiri-native-lib=` is an experimental flag for providing support for calling native functions from inside the interpreter via FFI. The flag is supported only on Unix systems. Functions not provided by that file are still executed via the usual Miri shims. @@ -412,6 +422,10 @@ to Miri failing to detect cases of undefined behavior in a program. without an explicit value), `none` means it never recurses, `scalar` means it only recurses for types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as individual scalars or pairs of scalars). Setting this to `none` is **unsound**. +* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active + thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables + preemption. Note that even without preemption, the schedule is still non-deterministic: + if a thread blocks or yields, the next thread is chosen randomly. * `-Zmiri-provenance-gc=` configures how often the pointer provenance garbage collector runs. The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting this to `0` disables the garbage collector, which causes some programs to have explosive memory diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index e95feb54fa87..dce2ac77c2ac 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -575,6 +575,11 @@ fn main() { miri_config.retag_fields = RetagFields::Yes; } else if arg == "-Zmiri-fixed-schedule" { miri_config.fixed_scheduling = true; + } else if arg == "-Zmiri-deterministic-concurrency" { + miri_config.fixed_scheduling = true; + miri_config.address_reuse_cross_thread_rate = 0.0; + miri_config.cmpxchg_weak_failure_rate = 0.0; + miri_config.weak_memory_emulation = false; } else if let Some(retag_fields) = arg.strip_prefix("-Zmiri-retag-fields=") { miri_config.retag_fields = match retag_fields { "all" => RetagFields::Yes, diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs index a3db0fd25dc0..f75f306e5a63 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency // Joining itself is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs index e3d5da26aeae..68dce8f86542 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs index 3a985122e22e..3a932404238d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs index 6d7bb80d8e6c..3b2173884635 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index 044d9a88ddc0..2980d257a292 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock // On windows, joining main is not UB, but it will block a thread forever. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs index 812fab445d1e..85672ec860f5 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock // On windows, a thread joining itself is not UB, but it will deadlock. diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 16706fd47448..5c80f6425eaa 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency //@ignore-target: windows # No libc env support on Windows use std::{env, thread}; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs index 168711d4d344..9dc554030c0e 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs index cc71aaf1a141..5297a3297750 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs index f9a4a4e5b2bb..314ce90cfb5d 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs @@ -4,7 +4,7 @@ //! to be considered synchronized. //@only-target: linux android illumos // ensure deterministic schedule -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs index c5c1db64037d..f6f2e2b93121 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //~^ERROR: deadlocked //~^^ERROR: deadlocked //@only-target: linux android illumos diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs index 1f6bb430ab20..0699dec6556d 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs @@ -2,7 +2,7 @@ //! faulty logic around `release_clock` that led to this code not reporting a data race. //~^^ERROR: deadlock //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs index b864347e2343..37fac436ff3e 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs @@ -1,7 +1,7 @@ //! This is a regression test for : we had some //! faulty logic around `release_clock` that led to this code not reporting a data race. //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread; fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs index c7bcdd54ec7b..b38398595002 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs index aaf9ead20003..7d84d87ebbb1 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs index 09924cd61aca..31f1a22f9f6d 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs @@ -1,8 +1,6 @@ //! Make sure that a retag acts like a write for the data race model. //@revisions: stack tree -//@compile-flags: -Zmiri-fixed-schedule -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@[tree]compile-flags: -Zmiri-tree-borrows #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs index e3f602511210..7c5116989943 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem::MaybeUninit; use std::ptr::null_mut; diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs index 0a010f68abbb..ba8a888de9ea 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs index de3bac474dbe..8cce54603ce5 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs index 123050331cdd..b6c0ef37cb92 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs index 88ce531a6949..03ae6895c574 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs index 963ce28065fa..4a5edf5cc14d 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs index cfbcec9cc2b1..e8d930a51dee 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs index 1e76f0faa2ab..4c67d2d76541 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs index c9fa6a86443a..fbb2c01e5a9a 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs index d4bcc9abca33..7431bc589ff9 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs index f1458131c48a..999cc2392f5a 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs index 8a8595b97a0b..bd3b037e5838 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs index de79076f59d8..e3d06660aab3 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs index d42a89eae3cd..90e87f8c4956 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs index a3d7770c2cef..d9b1af80af49 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs index 770283a7be2d..c1ab1942c688 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs index 6820ec46058e..67af6862737d 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs index df5730ae1bb7..b1eb1dda6d88 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering, fence}; diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs index 208b974cc7b6..647f209e8bf8 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs @@ -1,4 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency #![feature(core_intrinsics)] #![feature(custom_mir)] diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs index 4a622e5d1b91..f83d6c89fe5f 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs @@ -1,4 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs index e80f2a0c037f..ee1bef7ba5c0 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs @@ -1,4 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs index 6496fb30b762..720602d011e3 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs @@ -1,6 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency // Two variants: the atomic store matches the size of the first or second atomic load. //@revisions: match_first_load match_second_load diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs index 08fe0965aef2..78bba173ed7d 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs @@ -1,6 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency // Two revisions, depending on which access goes first. //@revisions: read_write write_read diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs index dd3db5a11d83..808280a4b311 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs @@ -1,6 +1,4 @@ -//@compile-flags:-Zmiri-fixed-schedule -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency //@revisions: fst snd use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.rs b/src/tools/miri/tests/fail/data_race/read_write_race.rs index dfe9de155ec3..2aadef36c5b9 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs index f02c0b23e524..cca39bb002c1 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs index 1d9cebb6c74a..262c039e4ae1 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.rs b/src/tools/miri/tests/fail/data_race/release_seq_race.rs index 367160506358..8aeb6ee6ef1d 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs index 8c223ee4ac19..f465160718f4 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.rs b/src/tools/miri/tests/fail/data_race/rmw_race.rs index d06c13a8f7f9..39588c15ec7e 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.rs +++ b/src/tools/miri/tests/fail/data_race/rmw_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs index 95d4145e5e73..5138bcbf8f74 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread; diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.rs b/src/tools/miri/tests/fail/data_race/write_write_race.rs index 7d7516449c3a..b1a6b08b4c88 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race.rs @@ -1,7 +1,5 @@ -// We want to control preemption here. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs index 6707de52e3f1..cd21b0a8fa6c 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs index 9fb910a3de4a..6ff69554387e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs @@ -1,5 +1,4 @@ -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency use std::thread; #[derive(Copy, Clone)] diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index a91931312bcf..f46f13a39e7a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -1,6 +1,5 @@ //! Make sure that a retag acts like a read for the data race model. -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 19c6e1bfcc17..024a14600b1b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -1,7 +1,7 @@ // Illustrating a problematic interaction between Reserved, interior mutability, // and protectors, that makes spurious writes fail in the previous model of Tree Borrows. // As for all similar tests, we disable preemption so that the error message is deterministic. -//@compile-flags: -Zmiri-tree-borrows -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-tree-borrows -Zmiri-deterministic-concurrency // // One revision without spurious read (default source code) and one with spurious read. // Both are expected to be UB. Both revisions are expected to have the *same* error diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs index 19f56730f365..4ca0fb943381 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs @@ -1,8 +1,8 @@ // We ensure a deterministic execution. // Note that we are *also* using barriers: the barriers enforce the -// specific interleaving of operations that we want, but only the preemption -// rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-fixed-schedule +// specific interleaving of operations that we want, but we need to disable +// preemption to ensure that the error message is also deterministic. +//@compile-flags: -Zmiri-deterministic-concurrency //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs index d71104667628..a28f08c3bb1a 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs @@ -1,5 +1,5 @@ //@only-target: darwin -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::time::{Duration, Instant}; use std::{io, ptr, thread}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index 4c42e97b66c8..91cf24a944ad 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency //@ignore-target: windows # No libc env support on Windows use std::ffi::CStr; diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs index 36dbb1bb4fd5..b10ded8e4d00 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs @@ -1,5 +1,5 @@ //@only-target: freebsd -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-disable-isolation +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-isolation use std::mem::{self, MaybeUninit}; use std::ptr::{self, addr_of}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs index aabd542f7c74..41b26c84393d 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::os::windows::io::IntoRawHandle; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs index f02ad3d4edd9..0a1fb1175079 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::ptr::null_mut; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs index 5a62c41927a9..acd9270ad16a 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::os::windows::io::IntoRawHandle; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index ae9bf6995e62..54ebfa9d198d 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index 12e12aa7138b..56d215d0ed63 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index 71e0467b3eb8..05f6c870c3d7 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc pipe on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread; fn main() { test_pipe(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index f4277791aeb9..9e48410f7045 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc socketpair on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index fae517f8e19f..255944662940 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index 76b31a76ccf1..d5dd1deb2d9d 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -1,4 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-fixed-schedule +// This tests carefully crafted schedules to ensure they are not considered races. +//@compile-flags: -Zmiri-deterministic-concurrency use std::sync::atomic::*; use std::thread::{self, spawn}; diff --git a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs index 968d5237ead8..ecc4ca59bd18 100644 --- a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs +++ b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-disable-data-race-detector // Avoid non-determinism -//@compile-flags: -Zmiri-fixed-schedule -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread::spawn; diff --git a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs index 55d6e0660c9a..4361f1da9240 100644 --- a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,5 +1,5 @@ // This specifically tests behavior *without* preemption. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 6e726ee0e093..a92359758dad 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -1,7 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs index 7c465d7ad568..bea8f87243aa 100644 --- a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-strict-provenance -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.rs b/src/tools/miri/tests/pass/panic/concurrent-panic.rs index d4d5eecd9122..4bf645960f70 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.rs +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index 44eb69cc6847..31e59c4a41cb 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::{env, thread}; fn main() { diff --git a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs index 19f90e5ee126..71b7817a9c70 100644 --- a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs +++ b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs @@ -2,7 +2,7 @@ // This test relies on a specific interleaving that cannot be enforced // with just barriers. We must remove preemption so that the execution and the // error messages are deterministic. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::ptr::addr_of_mut; use std::sync::{Arc, Barrier}; use std::thread; diff --git a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs index 061a5dd9e8e6..840832c633cf 100644 --- a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs @@ -2,7 +2,7 @@ // Note that we are *also* using barriers: the barriers enforce the // specific interleaving of operations that we want, but only the preemption // rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; From dd20225681cf581066afab23db0c0d854806370d Mon Sep 17 00:00:00 2001 From: Jon Bauman Date: Tue, 29 Apr 2025 11:24:31 -0700 Subject: [PATCH 086/302] Update rc.rs docs `wrapped_add` is used, not `checked_add` --- library/alloc/src/rc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 619d9f258e34..247afc628326 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3536,7 +3536,7 @@ impl Default for Weak { } } -// NOTE: We checked_add here to deal with mem::forget safely. In particular +// NOTE: We wrapping_add here to deal with mem::forget safely. In particular // if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then // you can free the allocation while outstanding Rcs (or Weaks) exist. // We abort because this is such a degenerate scenario that we don't care about From 1b677ce14ff759dacadd5d4b05dd27a00bfd68c2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 30 Apr 2025 07:34:00 +0200 Subject: [PATCH 087/302] chore: Adjust panic context printing --- .../rust-analyzer/crates/base-db/src/lib.rs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index f7f4e024ef23..a67fbf75c02f 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -387,10 +387,8 @@ fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> { } #[must_use] -pub struct DbPanicContext { - // prevent arbitrary construction - _priv: (), -} +#[non_exhaustive] +pub struct DbPanicContext; impl Drop for DbPanicContext { fn drop(&mut self) { @@ -404,18 +402,18 @@ impl DbPanicContext { fn set_hook() { let default_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { + default_hook(panic_info); + if let Some(backtrace) = salsa::Backtrace::capture() { + eprintln!("{backtrace:#}"); + } DbPanicContext::with_ctx(|ctx| { if !ctx.is_empty() { - eprintln!("Panic context:"); - for frame in ctx.iter() { - eprintln!("> {frame}\n"); + eprintln!("additional context:"); + for (idx, frame) in ctx.iter().enumerate() { + eprintln!("{idx:>4}: {frame}\n"); } } }); - if let Some(backtrace) = salsa::Backtrace::capture() { - eprintln!("{backtrace}"); - } - default_hook(panic_info); })); } @@ -423,7 +421,7 @@ impl DbPanicContext { SET_HOOK.call_once(set_hook); Self::with_ctx(|ctx| ctx.push(frame)); - DbPanicContext { _priv: () } + DbPanicContext } fn with_ctx(f: impl FnOnce(&mut Vec)) { From 146d8b95c88a9705449a2e3c65867efeed09602b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 30 Apr 2025 09:14:12 +0200 Subject: [PATCH 088/302] Update to LLVM 20.1.4 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index a9865ceca081..8448283b4bd3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit a9865ceca08101071e25f3bba97bba8bf0ea9719 +Subproject commit 8448283b4bd34ea00d76fd4f18ec730b549d6e1d From b9e0ecdd7626e76f0b72ada922e5c07eae75cdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 30 Apr 2025 13:02:30 +0200 Subject: [PATCH 089/302] transmutability: merge contiguous runs with a common destination --- compiler/rustc_transmute/src/layout/dfa.rs | 24 ++++++++++++++----- .../src/maybe_transmutable/tests.rs | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index 05afa28db31a..6d072c336af2 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -266,7 +266,7 @@ where } #[cfg(test)] - pub(crate) fn from_edges>( + pub(crate) fn from_edges>( start: u32, accept: u32, edges: &[(u32, B, u32)], @@ -275,8 +275,8 @@ where let accept = State(accept); let mut transitions: Map> = Map::default(); - for (src, edge, dst) in edges.iter().copied() { - transitions.entry(State(src)).or_default().push((edge.into(), State(dst))); + for &(src, ref edge, dst) in edges.iter() { + transitions.entry(State(src)).or_default().push((edge.clone().into(), State(dst))); } let transitions = transitions @@ -401,12 +401,24 @@ mod edge_set { mut join: impl FnMut(Option, Option) -> S, ) -> EdgeSet where - S: Copy, + S: Copy + Eq, { + let mut runs: SmallVec<[(Byte, S); 1]> = SmallVec::new(); let xs = self.runs.iter().copied(); let ys = other.runs.iter().copied(); - // FIXME(@joshlf): Merge contiguous runs with common destination. - EdgeSet { runs: union(xs, ys).map(|(range, (x, y))| (range, join(x, y))).collect() } + for (range, (x, y)) in union(xs, ys) { + let state = join(x, y); + match runs.last_mut() { + // Merge contiguous runs with a common destination. + Some(&mut (ref mut last_range, ref mut last_state)) + if last_range.end == range.start && *last_state == state => + { + last_range.end = range.end + } + _ => runs.push((range, state)), + } + } + EdgeSet { runs } } } } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index fbb4639dbd63..0227ad71ae66 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -314,7 +314,7 @@ mod union { let u = s.clone().union(t.clone(), new_state); let expected_u = - Dfa::from_edges(b, a, &[(b, 0, c), (b, 1, d), (d, 1, a), (d, 0, a), (c, 0, a)]); + Dfa::from_edges(b, a, &[(b, 0..=0, c), (b, 1..=1, d), (d, 0..=1, a), (c, 0..=0, a)]); assert_eq!(u, expected_u); From d6ae459af8da8f5c751ad5cd8765a48778e419bb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 30 Apr 2025 15:09:34 +0200 Subject: [PATCH 090/302] Stabilize proc_macro::Span::{file, local_file}. --- library/proc_macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 36a1c57b0201..7dbb9dadd881 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -544,7 +544,7 @@ impl Span { /// /// This might not correspond to a valid file system path. /// It might be remapped, or might be an artificial path such as `""`. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] pub fn file(&self) -> String { self.0.file() } @@ -554,7 +554,7 @@ impl Span { /// This is the actual path on disk. It is unaffected by path remapping. /// /// This path should not be embedded in the output of the macro; prefer `file()` instead. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] pub fn local_file(&self) -> Option { self.0.local_file().map(|s| PathBuf::from(s)) } From 2a053c7a1532da2d8f60ac5a8f92b3e4e80d82d5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 30 Apr 2025 15:14:20 +0200 Subject: [PATCH 091/302] Update doc comments. --- library/proc_macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 7dbb9dadd881..79e9b8430b8d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -543,13 +543,13 @@ impl Span { /// The path to the source file in which this span occurs, for display purposes. /// /// This might not correspond to a valid file system path. - /// It might be remapped, or might be an artificial path such as `""`. + /// It might be remapped (e.g. `"/src/lib.rs"`) or an artificial path (e.g. `""`). #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] pub fn file(&self) -> String { self.0.file() } - /// The path to the source file in which this span occurs on disk. + /// The path to the source file in which this span occurs on the local file system. /// /// This is the actual path on disk. It is unaffected by path remapping. /// From 09188e63f2ccb82b268cec305777266818f29542 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 30 Apr 2025 15:51:58 +0200 Subject: [PATCH 092/302] fix: Improve parser recovery a bit --- .../macro_expansion_tests/builtin_fn_macro.rs | 2 -- .../ide-completion/src/context/analysis.rs | 6 ++-- .../crates/parser/src/grammar/expressions.rs | 2 +- .../parser/src/grammar/expressions/atom.rs | 4 +-- .../crates/parser/src/grammar/items.rs | 3 ++ .../crates/parser/src/grammar/paths.rs | 2 +- .../crates/parser/src/grammar/patterns.rs | 15 ++++++++-- .../crates/parser/src/grammar/types.rs | 5 ++++ .../parser/test_data/generated/runner.rs | 4 +++ .../test_data/parser/err/0022_bad_exprs.rast | 7 +++-- .../comma_after_default_values_syntax.rast | 9 +++--- .../inline/err/struct_field_recover.rast | 30 +++++++++++++++++++ .../parser/inline/err/struct_field_recover.rs | 1 + .../inline/err/type_in_array_recover.rast | 15 ++++++++++ .../inline/err/type_in_array_recover.rs | 1 + 15 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index a3b48831a0b0..e21d1415aa29 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -285,8 +285,6 @@ fn main() { /* parse error: expected expression */ builtin #format_args (x = ); /* parse error: expected expression */ -/* parse error: expected R_PAREN */ -/* parse error: expected expression, item or let statement */ builtin #format_args (x = , x = 2); /* parse error: expected expression */ builtin #format_args ("{}", x = ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 595997358966..822dae2578e7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -661,9 +661,8 @@ fn expected_type_and_name( )) } else { cov_mark::hit!(expected_type_struct_field_without_leading_char); - let expr_field = token.prev_sibling_or_token()? - .into_node() - .and_then(ast::RecordExprField::cast)?; + cov_mark::hit!(expected_type_struct_field_followed_by_comma); + let expr_field = previous_non_trivia_token(token.clone())?.parent().and_then(ast::RecordExprField::cast)?; let (_, _, ty) = sema.resolve_record_field(&expr_field)?; Some(( Some(ty), @@ -681,7 +680,6 @@ fn expected_type_and_name( .or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original)); (ty, field_name) } else { - cov_mark::hit!(expected_type_struct_field_followed_by_comma); (field_ty, field_name) } }, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 34dcf2a18229..0ac25da32941 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -4,7 +4,7 @@ use crate::grammar::attributes::ATTRIBUTE_FIRST; use super::*; -pub(super) use atom::{LITERAL_FIRST, literal}; +pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal}; pub(crate) use atom::{block_expr, match_arm_list}; #[derive(PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index c66afed91c51..5faf6fc2759e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -46,7 +46,6 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = T!['['], T![|], T![async], - T![box], T![break], T![const], T![continue], @@ -68,7 +67,8 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = LIFETIME_IDENT, ])); -pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]); +pub(in crate::grammar) const EXPR_RECOVERY_SET: TokenSet = + TokenSet::new(&[T!['}'], T![')'], T![']'], T![,]]); pub(super) fn atom_expr( p: &mut Parser<'_>, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index f5f003be4891..b9f4866574a6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -32,6 +32,9 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![impl], T![trait], T![const], + T![async], + T![unsafe], + T![extern], T![static], T![let], T![mod], diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 3410505cd46d..770827c6b0d4 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -81,7 +81,7 @@ fn path_for_qualifier( } const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = - items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); + expressions::EXPR_RECOVERY_SET.union(items::ITEM_RECOVERY_SET); const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index 460051a0f4a5..4dd44c030f30 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -199,8 +199,19 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { } } -const PAT_RECOVERY_SET: TokenSet = - TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]); +const PAT_RECOVERY_SET: TokenSet = TokenSet::new(&[ + T![let], + T![if], + T![while], + T![loop], + T![match], + T![')'], + T![']'], + T!['}'], + T![,], + T![=], + T![&], +]); fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option { let m = match p.current() { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 0133b7d5d820..9d31e435cf98 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -20,10 +20,15 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[ pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![')'], + // test_err type_in_array_recover + // const _: [&]; + T![']'], + T!['}'], T![>], T![,], // test_err struct_field_recover // struct S { f pub g: () } + // struct S { f: pub g: () } T![pub], ]); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 6c9d02aaa8f8..24db9478ee56 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -870,6 +870,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs"); } #[test] + fn type_in_array_recover() { + run_and_expect_errors("test_data/parser/inline/err/type_in_array_recover.rs"); + } + #[test] fn unsafe_block_in_mod() { run_and_expect_errors("test_data/parser/inline/err/unsafe_block_in_mod.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast index d97fc6c72091..1a8e881dd9e0 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast @@ -35,8 +35,8 @@ SOURCE_FILE WHITESPACE " " LET_STMT LET_KW "let" - ERROR - R_BRACK "]" + ERROR + R_BRACK "]" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" @@ -149,7 +149,8 @@ error 17: expected expression, item or let statement error 25: expected a name error 26: expected `;`, `{`, or `(` error 30: expected pattern -error 31: expected SEMICOLON +error 30: expected SEMICOLON +error 30: expected expression, item or let statement error 53: expected expression error 54: expected R_PAREN error 54: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast index feb617e1aa2a..b57066f2fb38 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast @@ -23,8 +23,7 @@ SOURCE_FILE L_CURLY "{" WHITESPACE " " DOT2 ".." - ERROR - COMMA "," + COMMA "," WHITESPACE " " R_CURLY "}" SEMICOLON ";" @@ -39,8 +38,7 @@ SOURCE_FILE L_CURLY "{" WHITESPACE " " DOT2 ".." - ERROR - COMMA "," + COMMA "," WHITESPACE " " RECORD_EXPR_FIELD NAME_REF @@ -55,5 +53,6 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 21: expected expression +error 21: cannot use a comma after the base struct error 36: expected expression -error 37: expected COMMA +error 36: cannot use a comma after the base struct diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast index 458d7f4e2fa2..5a12c21b647d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast @@ -26,6 +26,36 @@ SOURCE_FILE WHITESPACE " " R_CURLY "}" WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "S" + WHITESPACE " " + RECORD_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_FIELD + NAME + IDENT "f" + COLON ":" + WHITESPACE " " + RECORD_FIELD + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + NAME + IDENT "g" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" error 12: expected COLON error 12: expected type error 12: expected COMMA +error 38: expected type +error 38: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs index da32227adcd7..5b1e5a5b8a21 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs @@ -1 +1,2 @@ struct S { f pub g: () } +struct S { f: pub g: () } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast new file mode 100644 index 000000000000..db76e8d7c88a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast @@ -0,0 +1,15 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + SLICE_TYPE + L_BRACK "[" + REF_TYPE + AMP "&" + R_BRACK "]" + SEMICOLON ";" + WHITESPACE "\n" +error 11: expected type diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs new file mode 100644 index 000000000000..039bf8299779 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs @@ -0,0 +1 @@ +const _: [&]; From d9c060b88be29569e615496e20bdcf8ecdf780f8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 29 Apr 2025 15:39:33 -0400 Subject: [PATCH 093/302] Optimize the codegen for `Span::from_expansion` --- compiler/rustc_span/src/span_encoding.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 9d6c7d2a42a3..a4a47dc99b08 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -306,8 +306,21 @@ impl Span { /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { - // If the span is fully inferred then ctxt > MAX_CTXT - self.inline_ctxt().map_or(true, |ctxt| !ctxt.is_root()) + let ctxt = match_span_kind! { + self, + // All branches here, except `InlineParent`, actually return `span.ctxt_or_parent_or_marker`. + // Since `Interned` is selected if the field contains `CTXT_INTERNED_MARKER` returning that value + // as the context allows the compiler to optimize out the branch that selects between either + // `Interned` and `PartiallyInterned`. + // + // Interned contexts can never be the root context and `CTXT_INTERNED_MARKER` has a different value + // than the root context so this works for checking is this is an expansion. + InlineCtxt(span) => SyntaxContext::from_u16(span.ctxt), + InlineParent(_span) => SyntaxContext::root(), + PartiallyInterned(span) => SyntaxContext::from_u16(span.ctxt), + Interned(_span) => SyntaxContext::from_u16(CTXT_INTERNED_MARKER), + }; + !ctxt.is_root() } /// Returns `true` if this is a dummy span with any hygienic context. From 00f25a8e1cf7d749946a6a9fb7327bf4710c931f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Apr 2025 16:52:25 +0200 Subject: [PATCH 094/302] interpret: better error message for out-of-bounds pointer arithmetic and accesses --- compiler/rustc_const_eval/messages.ftl | 70 +++++++++---------- compiler/rustc_const_eval/src/errors.rs | 33 +++------ .../src/interpret/intrinsics.rs | 10 ++- .../rustc_const_eval/src/interpret/memory.rs | 16 ++--- .../src/interpret/validity.rs | 2 +- .../rustc_middle/src/mir/interpret/error.rs | 8 +-- .../src/borrow_tracker/stacked_borrows/mod.rs | 2 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- .../miri/src/shims/unix/android/thread.rs | 2 +- src/tools/miri/src/shims/unix/fd.rs | 4 +- .../miri/tests/fail-dep/libc/affinity.stderr | 4 +- .../tests/fail-dep/libc/memchr_null.stderr | 4 +- .../tests/fail-dep/libc/memcmp_null.stderr | 4 +- .../tests/fail-dep/libc/memcmp_zero.stderr | 4 +- .../tests/fail-dep/libc/memcpy_zero.stderr | 4 +- .../tests/fail-dep/libc/memrchr_null.stderr | 4 +- .../fail/both_borrows/issue-miri-1050-1.rs | 2 +- .../issue-miri-1050-1.stack.stderr | 4 +- .../issue-miri-1050-1.tree.stderr | 4 +- .../issue-miri-1050-2.stack.stderr | 4 +- .../issue-miri-1050-2.tree.stderr | 4 +- .../dangling_pointer_offset.rs | 2 +- .../dangling_pointer_offset.stderr | 4 +- ...dangling_pointer_project_underscore_let.rs | 2 +- ...ling_pointer_project_underscore_let.stderr | 4 +- ..._project_underscore_let_type_annotation.rs | 2 +- ...ject_underscore_let_type_annotation.stderr | 4 +- ...ngling_pointer_project_underscore_match.rs | 2 +- ...ng_pointer_project_underscore_match.stderr | 4 +- .../dangling_pointer_to_raw_pointer.stderr | 4 +- .../deref-invalid-ptr.stderr | 4 +- .../null_pointer_deref.stderr | 4 +- .../null_pointer_write.stderr | 4 +- .../out_of_bounds_project.rs | 2 +- .../out_of_bounds_project.stderr | 4 +- .../dangling_pointers/out_of_bounds_read.rs | 2 +- .../out_of_bounds_read.stderr | 4 +- .../dangling_pointers/out_of_bounds_write.rs | 2 +- .../out_of_bounds_write.stderr | 4 +- .../storage_dead_dangling.stderr | 4 +- .../wild_pointer_deref.stderr | 4 +- .../cast_int_to_fn_ptr.stderr | 4 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 4 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 4 +- .../intrinsics/ptr_offset_out_of_bounds.rs | 2 +- .../ptr_offset_out_of_bounds.stderr | 4 +- .../ptr_offset_out_of_bounds_neg.rs | 2 +- .../ptr_offset_out_of_bounds_neg.stderr | 4 +- .../fail/intrinsics/ptr_offset_overflow.rs | 2 +- .../intrinsics/ptr_offset_overflow.stderr | 4 +- .../miri/tests/fail/intrinsics/simd-gather.rs | 2 +- .../tests/fail/intrinsics/simd-gather.stderr | 4 +- .../tests/fail/intrinsics/simd-scatter.rs | 2 +- .../tests/fail/intrinsics/simd-scatter.stderr | 4 +- .../int_copy_looses_provenance3.stderr | 4 +- .../pointer_partial_overwrite.stderr | 4 +- .../provenance/provenance_transmute.stderr | 4 +- .../ptr_copy_loses_partial_provenance0.stderr | 4 +- .../ptr_copy_loses_partial_provenance1.stderr | 4 +- .../fail/provenance/ptr_int_unexposed.stderr | 4 +- .../tests/fail/provenance/ptr_invalid.stderr | 4 +- .../fail/provenance/ptr_invalid_offset.stderr | 4 +- src/tools/miri/tests/fail/rc_as_ptr.stderr | 4 +- .../tests/fail/reading_half_a_pointer.stderr | 4 +- .../fail/shims/backtrace/bad-backtrace-ptr.rs | 2 +- .../shims/backtrace/bad-backtrace-ptr.stderr | 4 +- src/tools/miri/tests/fail/zst_local_oob.rs | 2 +- .../miri/tests/fail/zst_local_oob.stderr | 4 +- tests/ui/const-ptr/forbidden_slices.stderr | 4 +- tests/ui/const-ptr/out_of_bounds_read.stderr | 6 +- tests/ui/consts/const-compare-bytes-ub.stderr | 10 +-- tests/ui/consts/const-deref-ptr.stderr | 2 +- .../consts/const-eval/const_raw_ptr_ops2.rs | 4 +- .../const-eval/const_raw_ptr_ops2.stderr | 4 +- .../const-eval/nonnull_as_ref_ub.stderr | 2 +- tests/ui/consts/const-eval/raw-pointer-ub.rs | 2 +- .../consts/const-eval/raw-pointer-ub.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 2 +- tests/ui/consts/copy-intrinsic.rs | 4 +- tests/ui/consts/copy-intrinsic.stderr | 4 +- tests/ui/consts/offset_ub.stderr | 18 ++--- 81 files changed, 202 insertions(+), 213 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index dd481e04abbd..f4defd2aa134 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -12,6 +12,27 @@ const_eval_already_reported = const_eval_assume_false = `assume` called with `false` +const_eval_bad_pointer_op = {$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +} +const_eval_bad_pointer_op_attempting = {const_eval_bad_pointer_op}: {$operation -> + [MemoryAccess] attempting to access {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + *[Dereferenceable] pointer must {$inbounds_size -> + [0] point to some allocation + [1] be dereferenceable for 1 byte + *[x] be dereferenceable for {$inbounds_size} bytes + } + } + const_eval_bounds_check_failed = indexing out of bounds: the len is {$len} but the index is {$index} const_eval_call_nonzero_intrinsic = @@ -39,9 +60,9 @@ const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges const_eval_dangling_int_pointer = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance) + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which is a dangling pointer (it has no provenance) const_eval_dangling_null_pointer = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer + {const_eval_bad_pointer_op_attempting}, but got null pointer const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind} const_eval_dead_local = @@ -77,21 +98,6 @@ const_eval_error = {$error_kind -> const_eval_exact_div_has_remainder = exact_div: {$a} cannot be divided by {$b} without remainder -const_eval_expected_inbounds_pointer = - expected a pointer to {$inbounds_size_abs -> - [0] some allocation - *[x] {$inbounds_size_is_neg -> - [false] {$inbounds_size_abs -> - [1] 1 byte of memory - *[x] {$inbounds_size_abs} bytes of memory - } - *[true] the end of {$inbounds_size_abs -> - [1] 1 byte of memory - *[x] {$inbounds_size_abs} bytes of memory - } - } - } - const_eval_extern_static = cannot access extern static `{$did}` const_eval_extern_type_field = `extern type` field does not have a known offset @@ -111,7 +117,6 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here -const_eval_in_bounds_test = out-of-bounds pointer use const_eval_incompatible_calling_conventions = calling a function with calling convention {$callee_conv} using calling convention {$caller_conv} @@ -206,7 +211,6 @@ const_eval_long_running = const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} -const_eval_memory_access_test = memory access failed const_eval_memory_exhausted = tried to allocate more memory than available to compiler @@ -287,8 +291,6 @@ const_eval_offset_from_out_of_bounds = `{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation const_eval_offset_from_overflow = `{$name}` called when first pointer is too far ahead of second -const_eval_offset_from_test = - out-of-bounds `offset_from` origin const_eval_offset_from_underflow = `{$name}` called when first pointer is too far before second const_eval_offset_from_unsigned_overflow = @@ -312,27 +314,25 @@ const_eval_partial_pointer_overwrite = unable to overwrite parts of a pointer in memory at {$ptr} const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` -const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic + const_eval_pointer_out_of_bounds = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg -> - [true] which points to before the beginning of the allocation - *[false] {$inbounds_size_is_neg -> - [true] {$ptr_offset_abs -> - [0] which is at the beginning of the allocation - *[other] which does not have enough space to the beginning of the allocation - } - *[false] {$alloc_size_minus_ptr_offset -> - [0] which is at or beyond the end of the allocation of size {$alloc_size -> + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> [1] 1 byte *[x] {$alloc_size} bytes } - [1] which is only 1 byte from the end of the allocation - *[x] which is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - } } + const_eval_pointer_use_after_free = - {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling + {const_eval_bad_pointer_op}: {$alloc_id} has been freed, so this pointer is dangling const_eval_ptr_as_bytes_1 = this code performed an operation that depends on the underlying bytes representing a pointer const_eval_ptr_as_bytes_2 = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 6472aaa57581..826ea0e58ecc 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -5,15 +5,14 @@ use either::Either; use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, + Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ - CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, - InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo, + Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, + UnsupportedOpInfo, ValidationErrorInfo, }; use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::{Span, Symbol}; @@ -498,19 +497,6 @@ pub trait ReportErrorExt { } } -fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String { - use crate::fluent_generated::*; - - let msg = match msg { - CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test, - CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test, - CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test, - CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test, - }; - - dcx.eagerly_translate_to_string(msg, [].into_iter()) -} - impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { fn diagnostic_message(&self) -> DiagMessage { use UndefinedBehaviorInfo::*; @@ -564,7 +550,6 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { fn add_args(self, diag: &mut Diag<'_, G>) { use UndefinedBehaviorInfo::*; - let dcx = diag.dcx; match self { Ub(_) => {} Custom(custom) => { @@ -612,12 +597,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("vtable_dyn_type", vtable_dyn_type.to_string()); } PointerUseAfterFree(alloc_id, msg) => { - diag.arg("alloc_id", alloc_id) - .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg)); } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { diag.arg("alloc_size", alloc_size.bytes()); - diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); diag.arg("pointer", { let mut out = format!("{:?}", alloc_id); if ptr_offset > 0 { @@ -627,14 +610,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { } out }); + diag.arg("inbounds_size", inbounds_size); diag.arg("inbounds_size_is_neg", inbounds_size < 0); diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); + diag.arg("ptr_offset", ptr_offset); diag.arg("ptr_offset_is_neg", ptr_offset < 0); diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs()); diag.arg( "alloc_size_minus_ptr_offset", alloc_size.bytes().saturating_sub(ptr_offset as u64), ); + diag.arg("operation", format!("{:?}", msg)); } DanglingIntPointer { addr, inbounds_size, msg } => { if addr != 0 { @@ -644,9 +630,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { ); } + diag.arg("inbounds_size", inbounds_size); diag.arg("inbounds_size_is_neg", inbounds_size < 0); diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); - diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg("operation", format!("{:?}", msg)); } AlignmentCheckFailed(Misalignment { required, has }, msg) => { diag.arg("required", required.bytes()); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 97d066ffe3fa..3f9619a79a88 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -349,7 +349,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Check that the memory between them is dereferenceable at all, starting from the // origin pointer: `dist` is `a - b`, so it is based on `b`. - self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest) + self.check_ptr_access_signed(b, dist, CheckInAllocMsg::Dereferenceable) .map_err_kind(|_| { // This could mean they point to different allocations, or they point to the same allocation // but not the entire range between the pointers is in-bounds. @@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.check_ptr_access_signed( a, dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large - CheckInAllocMsg::OffsetFromTest, + CheckInAllocMsg::Dereferenceable, ) .map_err_kind(|_| { // Make the error more specific. @@ -652,7 +652,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { offset_bytes: i64, ) -> InterpResult<'tcx, Pointer>> { // The offset must be in bounds starting from `ptr`. - self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; + self.check_ptr_access_signed( + ptr, + offset_bytes, + CheckInAllocMsg::InboundsPointerArithmetic, + )?; // This also implies that there is no overflow, so we are done. interp_ok(ptr.wrapping_signed_offset(offset_bytes, self)) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9d8130661b04..43bf48a9b961 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -351,7 +351,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "static_mem" ) } - None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), + None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)), }) .into(); }; @@ -414,10 +414,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { - let (size, align) = this - .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; + let (size, align) = + this.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccess)?; interp_ok((size, align, (alloc_id, offset, prov))) }, ) @@ -613,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), - None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)), + None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); // Thread-local statics do not have a constant address. They *must* be accessed via @@ -707,7 +707,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size_i64, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { let alloc = this.get_alloc_raw(alloc_id)?; interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) @@ -809,7 +809,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size_i64, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) @@ -1615,7 +1615,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { err_ub!(DanglingIntPointer { addr: offset, inbounds_size: size, - msg: CheckInAllocMsg::InboundsTest + msg: CheckInAllocMsg::Dereferenceable }) }) .into() diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index c86af5a9a4b1..8f39afa642ae 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -510,7 +510,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.check_ptr_access( place.ptr(), size, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message + CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message ), self.path, Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind }, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 890756a17cae..6ff3cac049b3 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -221,13 +221,11 @@ pub enum InvalidProgramInfo<'tcx> { #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { /// We are access memory. - MemoryAccessTest, + MemoryAccess, /// We are doing pointer arithmetic. - PointerArithmeticTest, - /// We are doing pointer offset_from. - OffsetFromTest, + InboundsPointerArithmetic, /// None of the above -- generic/unspecific inbounds test. - InboundsTest, + Dereferenceable, } /// Details of which pointer is not aligned. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 18a5a0612bb0..0704ed199dbb 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -594,7 +594,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::Dereferenceable)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'tcx>, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f39a606513d5..65042f266808 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -197,7 +197,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Make sure the new permission makes sense as the initial permission of a fresh tag. assert!(new_perm.initial_state.is_initial()); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::Dereferenceable)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'tcx>, diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index c7e2c4d507b2..30ec0aefcbf1 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -42,7 +42,7 @@ pub fn prctl<'tcx>( ecx.check_ptr_access( name.to_pointer(ecx)?, Size::from_bytes(TASK_COMM_LEN), - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, )?; let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?; assert_eq!(res, ThreadNameResult::Ok); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 41be9df7e2da..156814a26fa7 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -226,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Reading from FD {}, size {}", fd_num, count); // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?; // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. @@ -292,7 +292,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Isolation check is done via `FileDescription` trait. // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?; // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr index 5a226c6a44b8..cc3daa47e00b 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation +error: Undefined Behavior: memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation --> tests/fail-dep/libc/affinity.rs:LL:CC | LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr index 6d3ff176c355..5690277a0460 100644 --- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memchr_null.rs:LL:CC | LL | libc::memchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr index a4ca205c3770..bd3a0719fa33 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memcmp_null.rs:LL:CC | LL | libc::memcmp(ptr::null(), ptr::null(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr index d7b046c18235..2044c1547617 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail-dep/libc/memcmp_zero.rs:LL:CC | LL | libc::memcmp(ptr.cast(), ptr.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr index 336113e34408..789e9daf43bc 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail-dep/libc/memcpy_zero.rs:LL:CC | LL | libc::memcpy(to.cast(), from.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr index ce759f3e17a5..27e7a9855d10 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memrchr_null.rs:LL:CC | LL | libc::memrchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs index 49de3dd0b105..dd7dae9cecf9 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -//@error-in-other-file: expected a pointer to 4 bytes of memory +//@error-in-other-file: pointer not dereferenceable fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index cd27bb818e76..0e6d838dfff6 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index cd27bb818e76..0e6d838dfff6 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index 04e5765371e7..861173f54968 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index 04e5765371e7..861173f54968 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs index 65eca07a0708..54b3280e71ac 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs @@ -6,6 +6,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/ + let x = unsafe { p.offset(42) }; //~ ERROR: /in-bounds pointer arithmetic failed: .* has been freed/ panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr index 076d68804618..fd1a5e7faafe 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC | LL | let x = unsafe { p.offset(42) }; - | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs index 22a5ce8ea741..02ea09efab63 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs @@ -7,6 +7,6 @@ fn main() { &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - let _ = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic + let _ = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr index ffb525e39814..ffb8bc9507b5 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let _ = (*p).1; - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs index fc10a826c1e1..7ab295cb6c6c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs @@ -7,6 +7,6 @@ fn main() { &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - let _: u8 = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic + let _: u8 = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr index 14dfa43b2d68..cf3e1db13d3d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC | LL | let _: u8 = (*p).1; - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs index 8541da848578..2855dd13fdc4 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs @@ -8,7 +8,7 @@ fn main() { }; unsafe { match (*p).1 { - //~^ ERROR: out-of-bounds pointer arithmetic + //~^ ERROR: in-bounds pointer arithmetic failed _ => {} } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr index ff39e1475738..e2d04433b639 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC | LL | match (*p).1 { - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index 99194d6e0725..5a2b85696abc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | unsafe { &(*x).0 as *const i32 } - | ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 09a201983b1f..ad4280c2d744 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) + | ^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr index d87a8bc59e95..3135db9dc6d5 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer --> tests/fail/dangling_pointers/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr index 39d861a63882..012b38ee5a6c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer --> tests/fail/dangling_pointers/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs index b596ba428ae5..7a2ad483d015 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs @@ -7,6 +7,6 @@ fn main() { let ptr = addr_of!(v).cast::<(u32, u32, u32)>(); unsafe { let _field = addr_of!((*ptr).1); // still just in-bounds - let _field = addr_of!((*ptr).2); //~ ERROR: out-of-bounds pointer arithmetic + let _field = addr_of!((*ptr).2); //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr index 27a437c7483d..c11ccdb45a7f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation --> tests/fail/dangling_pointers/out_of_bounds_project.rs:LL:CC | LL | let _field = addr_of!((*ptr).2); - | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs index 595a229baa5a..78a7b7e460be 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: expected a pointer to 2 bytes of memory + let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: attempting to access 2 bytes panic!("this should never print: {}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr index 813bcef54f12..1de4b806da20 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC | LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs index 054e1c66cc18..f83601b44f8d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -1,5 +1,5 @@ fn main() { let mut v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: expected a pointer to 2 bytes of memory + unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: attempting to access 2 bytes } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr index 1056a739a436..db16d70704e8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC | LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 9061121494d0..e97427ab7ebc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 3e7aac4724dc..79e27fa34617 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index f2d9933188d7..37d3beefcd7b 100644 --- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/function_pointers/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) - | ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index c87ce321784b..b7ed36f6428f 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/intrinsics/ptr_offset_int_plus_int.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 78239d501378..29d9e1c64bd7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs index 905fc678f6d5..e44d398c998c 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs @@ -1,6 +1,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(5) }; //~ERROR: expected a pointer to 5 bytes of memory + let x = unsafe { x.offset(5) }; //~ERROR: is only 4 bytes from the end of the allocation panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr index 4f6b45b897b4..143fae8587b6 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation --> tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC | LL | let x = unsafe { x.offset(5) }; - | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs index bd1d5c064c06..5ad173735669 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs @@ -1,6 +1,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; //~ERROR: expected a pointer to the end of 1 byte of memory + let x = unsafe { x.offset(-1) }; //~ERROR: is at the beginning of the allocation panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr index 2dd4c943e864..14163d924041 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC | LL | let x = unsafe { x.offset(-1) }; - | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation + | ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs index 683943122327..6767b1f117a8 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -3,6 +3,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(isize::MIN) }; //~ERROR: out-of-bounds pointer arithmetic + let x = unsafe { x.offset(isize::MIN) }; //~ERROR: in-bounds pointer arithmetic failed panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr index d03c9f870e24..af08bfb3c947 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation --> tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC | LL | let x = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs index b83739524517..45a3dfa57724 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs @@ -6,6 +6,6 @@ fn main() { let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - //~^ERROR: expected a pointer to 1 byte of memory + //~^ERROR: attempting to access 1 byte } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr index ee1c90096108..e91d5d2185f3 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> tests/fail/intrinsics/simd-gather.rs:LL:CC | LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs index bb8c9dbe4c7a..4e727edd6244 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs @@ -6,7 +6,7 @@ fn main() { let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( - //~^ERROR: expected a pointer to 1 byte of memory + //~^ERROR: attempting to access 1 byte &mut vec, Mask::splat(true), idxs, diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index aaacb94f458d..56c8e7b38b64 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> tests/fail/intrinsics/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( @@ -7,7 +7,7 @@ LL | | &mut vec, LL | | Mask::splat(true), LL | | idxs, LL | | ); - | |_________^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes + | |_________^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr index 62e3bd2e954c..4e741fe8329b 100644 --- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/int_copy_looses_provenance3.rs:LL:CC | LL | let _val = unsafe { *ptr }; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 6bc92fffd5af..370f9463b73c 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; - | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 7403f4382de2..38e2e19009a9 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr index 5ed83951c60a..5225ab328652 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs:LL:CC | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr index 3675653cbe79..c17c98fa1056 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs:LL:CC | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr index 1b6518612efc..78290d4ed63b 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr index 84347ec7a11d..ff73fbb9d1b3 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr index 3910bc4df4b0..07556540f13e 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr index 0fcb0faf4971..e1d0e5780a07 100644 --- a/src/tools/miri/tests/fail/rc_as_ptr.stderr +++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling --> tests/fail/rc_as_ptr.rs:LL:CC | LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr index 921796441694..61fb9cd4e526 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/reading_half_a_pointer.rs:LL:CC | LL | let _val = *x; - | ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs index 75f7aae9718d..a398eb1ae0c2 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: got a null pointer + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer } } diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 7ae9558fad70..126f41fbb0e6 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail/shims/backtrace/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/zst_local_oob.rs b/src/tools/miri/tests/fail/zst_local_oob.rs index ab48b7d330b3..2bf184c72bae 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.rs +++ b/src/tools/miri/tests/fail/zst_local_oob.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR: expected a pointer to 1 byte of memory + let _val = unsafe { *x }; //~ ERROR: attempting to access 1 byte } diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr index 26911948eff7..e9423096226e 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.stderr +++ b/src/tools/miri/tests/fail/zst_local_oob.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes --> tests/fail/zst_local_oob.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes + | ^^ memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 6f2da272ad3f..c73d2ca938cb 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -114,7 +114,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - | ^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC10 which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -169,7 +169,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:79:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation + | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index b396fc4d71bc..1d625a26b78c 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:8:33 | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::const_ptr::::read` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::mut_ptr::::read` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 9ef5c8ad43a1..0e77310c6bab 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -2,31 +2,31 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got null pointer error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC1 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:29:9 diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index 070685e0b9d9..37502864947a 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 8 bytes, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs index ca96cfd9d193..0e88aa80c797 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -5,6 +5,6 @@ const Z: i32 = unsafe { *(&1 as *const i32) }; // bad, will thus error in miri const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE is a dangling pointer +//~| NOTE dangling pointer const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE is a dangling pointer +//~| NOTE dangling pointer diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index b0c864652e55..a8a5560ccb9c 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index bd6dafb93665..1996cd2721ec 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 478e93a910e0..13a95f9b78f9 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -39,7 +39,7 @@ const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: expected a pointer to 8 bytes of memory + //~^NOTE: is only 4 bytes from the end of the allocation }; fn main() {} diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 4fff293b2eef..ed5793c84c57 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -31,7 +31,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:41:16 | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 which is only 4 bytes from the end of the allocation + | ^^^^ memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 0e4926eb49ed..6921587ea1d9 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-nonnull.rs:20:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 255 bytes of memory, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 5ae467878001..da483d671f97 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -32,7 +32,7 @@ const COPY_OOB_1: () = unsafe { copy_nonoverlapping(0x100 as *const i32, dangle, 0); // Non-zero-sized copy is not. copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE got 0x100[noalloc] which is a dangling pointer + //~| NOTE which is a dangling pointer }; const COPY_OOB_2: () = unsafe { let x = 0i32; @@ -41,7 +41,7 @@ const COPY_OOB_2: () = unsafe { copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); // Non-zero-sized copy is not. copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE +0x28 which is at or beyond the end of the allocation + //~| NOTE is at or beyond the end of the allocation of size 4 bytes }; const COPY_SIZE_OVERFLOW: () = unsafe { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 41af3a2cd2dc..13321b5703a3 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:34:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:43:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:50:5 diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index a247ad254651..699b63dfd66d 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC0 which is at the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC0 which is at the beginning of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC2 which is only $BYTES bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -47,7 +47,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -56,7 +56,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -65,7 +65,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC3-0x2 which points to before the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -74,7 +74,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -83,7 +83,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::mut_ptr::::offset` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL @@ -92,7 +92,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL From f2930001aa6dd5f5056c69c96c1eaf4b31dfedd8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 25 Apr 2025 15:13:51 +0000 Subject: [PATCH 095/302] Use select in projection lookup --- .../traits/fulfillment_errors.rs | 44 ++++++++++--------- .../mismatch-two-relevant-impls.rs | 20 +++++++++ .../mismatch-two-relevant-impls.stderr | 20 +++++++++ 3 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 tests/ui/associated-types/mismatch-two-relevant-impls.rs create mode 100644 tests/ui/associated-types/mismatch-two-relevant-impls.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index ab2aa0ae4697..970160ba212a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -15,6 +15,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node}; use rustc_infer::infer::{InferOk, TypeTrace}; +use rustc_infer::traits::ImplSource; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::traits::select::OverflowError; @@ -48,8 +49,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, - ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, - TraitDynIncompatible, elaborate, + ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError, + SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -1495,32 +1496,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let secondary_span = (|| { + let secondary_span = self.probe(|_| { let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() else { return None; }; - let mut associated_items = vec![]; - self.tcx.for_each_relevant_impl( - self.tcx.trait_of_item(proj.projection_term.def_id)?, - proj.projection_term.self_ty(), - |impl_def_id| { - associated_items.extend( - self.tcx.associated_items(impl_def_id).in_definition_order().find( - |assoc| { - assoc.trait_item_def_id == Some(proj.projection_term.def_id) - }, - ), - ); - }, - ); - - let [associated_item]: &[ty::AssocItem] = &associated_items[..] else { + let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self) + .poly_select(&obligation.with( + self.tcx, + predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), + )) + else { return None; }; - match self.tcx.hir_get_if_local(associated_item.def_id) { + + let Ok(node) = + specialization_graph::assoc_def(self.tcx, impl_data.impl_def_id, proj.def_id()) + else { + return None; + }; + + if !node.is_final() { + return None; + } + + match self.tcx.hir_get_if_local(node.item.def_id) { Some( hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(_, Some(ty)), @@ -1543,7 +1545,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )), _ => None, } - })(); + }); self.note_type_err( &mut diag, diff --git a/tests/ui/associated-types/mismatch-two-relevant-impls.rs b/tests/ui/associated-types/mismatch-two-relevant-impls.rs new file mode 100644 index 000000000000..58fd567c2780 --- /dev/null +++ b/tests/ui/associated-types/mismatch-two-relevant-impls.rs @@ -0,0 +1,20 @@ +trait Tr { + type Assoc; +} + +struct W(T); + +impl Tr for W { + type Assoc = u32; +} + +impl Tr for W { + type Assoc = i32; +} + +fn needs_unit>() {} + +fn main() { + needs_unit::>(); + //~^ ERROR type mismatch resolving ` as Tr>::Assoc == ()` +} diff --git a/tests/ui/associated-types/mismatch-two-relevant-impls.stderr b/tests/ui/associated-types/mismatch-two-relevant-impls.stderr new file mode 100644 index 000000000000..2a1f3ef23ca7 --- /dev/null +++ b/tests/ui/associated-types/mismatch-two-relevant-impls.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving ` as Tr>::Assoc == ()` + --> $DIR/mismatch-two-relevant-impls.rs:18:18 + | +LL | needs_unit::>(); + | ^^^^^^ type mismatch resolving ` as Tr>::Assoc == ()` + | +note: expected this to be `()` + --> $DIR/mismatch-two-relevant-impls.rs:8:18 + | +LL | type Assoc = u32; + | ^^^ +note: required by a bound in `needs_unit` + --> $DIR/mismatch-two-relevant-impls.rs:15:21 + | +LL | fn needs_unit>() {} + | ^^^^^^^^^^ required by this bound in `needs_unit` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. From 0f81fca8ec623e849225a254ef6f639963ff54c0 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 30 Apr 2025 15:39:52 -0700 Subject: [PATCH 096/302] Change rustc_driver dependency on stable_mir crate This fixes issues with RustAnalyzer not finding stable_mir crate. It is also part of the long term architecture plan for these crates, since we are moving towards having stable_mir depend on rustc_smir and not the other way around. I believe this is an utility function that will come handy eventually for stable_mir users, but I'm keeping it as part of rustc_internal since it initializes the StableMir context and requires `TyCtxt`. Finally, I added the rustc_internal crate under a feature since the APIs from this module shall not be stabilized. --- Cargo.lock | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_driver_impl/src/pretty.rs | 2 +- compiler/stable_mir/Cargo.toml | 6 ++++++ compiler/stable_mir/src/lib.rs | 4 ++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60daa453c60d..821512a53c2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3583,13 +3583,13 @@ dependencies = [ "rustc_query_system", "rustc_resolve", "rustc_session", - "rustc_smir", "rustc_span", "rustc_target", "rustc_trait_selection", "rustc_ty_utils", "serde_json", "shlex", + "stable_mir", "tracing", "windows 0.59.0", ] diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index c823d11126e2..9da4f2dbc273 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -44,13 +44,13 @@ rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } rustc_session = { path = "../rustc_session" } -rustc_smir = { path = "../rustc_smir" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" +stable_mir = { path = "../stable_mir", features = ["rustc_internal"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 16d70af7e05d..ec77043cd128 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -10,8 +10,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_build::thir::print::{thir_flat, thir_tree}; use rustc_session::Session; use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; -use rustc_smir::rustc_internal::pretty::write_smir_pretty; use rustc_span::{FileName, Ident}; +use stable_mir::rustc_internal::pretty::write_smir_pretty; use tracing::debug; use {rustc_ast as ast, rustc_hir_pretty as pprust_hir}; diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 3a01ee5783ee..516c8e9c718b 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -5,3 +5,9 @@ edition = "2024" [dependencies] rustc_smir = { path = "../rustc_smir" } + +[features] +# Provides access to APIs that expose internals of the rust compiler. +# APIs enabled by this feature are unstable. They can be removed or modified +# at any point and they are not included in the crate's semantic versioning. +rustc_internal = [] diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index cc0fb52433d9..688f3936b26c 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -4,4 +4,8 @@ //! This is a transitional measure as described in [PR #139319](https://github.com/rust-lang/rust/pull/139319). //! Once the refactoring is complete, the `stable_mir` implementation will be moved back here. +/// Export the rustc_internal APIs. Note that this module has no stability +/// guarantees and it is not taken into account for semver. +#[cfg(feature = "rustc_internal")] +pub use rustc_smir::rustc_internal; pub use rustc_smir::stable_mir::*; From 1157b78d62d61501e521afa0244aebab45ec6ba0 Mon Sep 17 00:00:00 2001 From: Sayantan Chakraborty <142906350+sayantn@users.noreply.github.com> Date: Fri, 18 Apr 2025 12:06:02 +0530 Subject: [PATCH 097/302] Remove `avx512dq` and `avx512vl` implication for `avx512fp16` --- compiler/rustc_target/src/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..e7f50c1356aa 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -398,7 +398,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), - ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]), + ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]), From adb92aeb4a1f6cd8313fa880c19a39a8caefbded Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 05:48:51 +0000 Subject: [PATCH 098/302] rustc_target: Adjust RISC-V feature implication (Za64rs and Za128rs) The Za64rs extension (reservation set -- a primitive memory unit of LR/SC atomic operations -- is naturally aligned and *at most* 64 bytes) is a superset of the Za128rs extension (*at most* 128 bytes; note that smaller the reservation set is, more fine grained control over atomics). This commit handles this as a feature implication. --- compiler/rustc_target/src/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..9031e0530c58 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -507,7 +507,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), ("za128rs", Unstable(sym::riscv_target_feature), &[]), - ("za64rs", Unstable(sym::riscv_target_feature), &[]), + ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs ("zaamo", Unstable(sym::riscv_target_feature), &[]), ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), From c6ed7869a13194748653f48350225bc9e0ced2ca Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 06:05:41 +0000 Subject: [PATCH 099/302] rustc_target: RISC-V: Add atomics/memory-related extensions This commit adds a part of RISC-V extensions that are mandatory part of the RVA23U64 profile (application-class processor profile) and related to memory/atomic constraints. The Zic64b extension constrains the cache line to naturally-aligned 64 bytes that would make certain memory operations (like zeroing the memory using the Zicboz extension) easier. The Zicbom and Zicbop extensions enable managing cache block-based operations (the Zicbop contains hints that will work as a NOP when this extension is absent and the Zicbom contains control instructions). Of which, the Zicbom extension is going to be discoverable from the Linux kernel (as of the version 6.15-rc4) and this commit prepares for corresponding stdarch changes. The Zicc* extensions add certain constraints to "the main memory" (usually true on the user mode application on the application-class processor but those extensions make sure such constraints exist). --- compiler/rustc_target/src/target_features.rs | 7 +++++++ tests/ui/check-cfg/target_feature.stderr | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 9031e0530c58..99f39b34b629 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -531,7 +531,14 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zic64b", Unstable(sym::riscv_target_feature), &[]), + ("zicbom", Unstable(sym::riscv_target_feature), &[]), + ("zicbop", Unstable(sym::riscv_target_feature), &[]), ("zicboz", Unstable(sym::riscv_target_feature), &[]), + ("ziccamoa", Unstable(sym::riscv_target_feature), &[]), + ("ziccif", Unstable(sym::riscv_target_feature), &[]), + ("zicclsm", Unstable(sym::riscv_target_feature), &[]), + ("ziccrse", Unstable(sym::riscv_target_feature), &[]), ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zicond", Unstable(sym::riscv_target_feature), &[]), ("zicsr", Unstable(sym::riscv_target_feature), &[]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 4f7b8345e86a..174058773549 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -329,7 +329,14 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zfinx` `zhinx` `zhinxmin` +`zic64b` +`zicbom` +`zicbop` `zicboz` +`ziccamoa` +`ziccif` +`zicclsm` +`ziccrse` `zicntr` `zicond` `zicsr` From 501a539bbe74164384ebf42165b058bc01f6b5a2 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 06:53:22 +0000 Subject: [PATCH 100/302] rustc_target: RISC-V: Add BF16 extensions This commit adds three ratified unprivileged RISC-V extensions related to BFloat16 (BF16) handling. Although that they are far from stabilization due to ABI issues, they are optional extensions of the RVA23U64 profile (application-class processor profile) and going to be discoverable from the Linux kernel (as of version 6.15-rc4). This commit mainly prepares runtime detection of those extensions. --- compiler/rustc_target/src/target_features.rs | 3 +++ tests/ui/check-cfg/target_feature.stderr | 3 +++ 2 files changed, 6 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 99f39b34b629..009118f2d4ff 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -526,6 +526,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), ("zfa", Unstable(sym::riscv_target_feature), &["f"]), + ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), @@ -565,6 +566,8 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), + ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 174058773549..712ce941c54c 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -324,6 +324,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zcmop` `zdinx` `zfa` +`zfbfmin` `zfh` `zfhmin` `zfinx` @@ -363,6 +364,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zve64d` `zve64f` `zve64x` +`zvfbfmin` +`zvfbfwma` `zvfh` `zvfhmin` `zvkb` From d2068be4a0a6d654e7532d7c217d99489aa82312 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 30 Apr 2025 19:40:29 -0500 Subject: [PATCH 101/302] Rename `(Mapped)(RwLock|Mutex)Guard::try_map` to `filter_map`. 1. analogous to std::cell::Ref(Mut)::filter_map. 2. doesn't imply `Try` genericizability. --- library/std/src/sync/poison/mutex.rs | 22 +++++------ library/std/src/sync/poison/rwlock.rs | 54 +++++++++++++-------------- library/std/tests/sync/mutex.rs | 14 ++++--- library/std/tests/sync/rwlock.rs | 30 +++++++++------ 4 files changed, 61 insertions(+), 59 deletions(-) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index adb74bb6f3de..1c29c619edc3 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -253,11 +253,11 @@ unsafe impl Sync for MutexGuard<'_, T> {} /// The data protected by the mutex can be accessed through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// -/// This structure is created by the [`map`] and [`try_map`] methods on +/// This structure is created by the [`map`] and [`filter_map`] methods on /// [`MutexGuard`]. /// /// [`map`]: MutexGuard::map -/// [`try_map`]: MutexGuard::try_map +/// [`filter_map`]: MutexGuard::filter_map /// [`Condvar`]: crate::sync::Condvar #[must_use = "if unused the Mutex will immediately unlock"] #[must_not_suspend = "holding a MappedMutexGuard across suspend \ @@ -718,7 +718,7 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); @@ -739,17 +739,16 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> { /// The `Mutex` is already locked, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MutexGuard::try_map(...)`. A method would interfere with methods of the + /// `MutexGuard::filter_map(...)`. A method would interfere with methods of the /// same name on the contents of the `MutexGuard` used through `Deref`. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { &mut *orig.lock.data.get() }) { @@ -826,7 +825,7 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_mut() })); @@ -847,17 +846,16 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> { /// The `Mutex` is already locked, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedMutexGuard::try_map(...)`. A method would interfere with methods of the + /// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the /// same name on the contents of the `MutexGuard` used through `Deref`. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(mut orig: Self, f: F) -> Result, Self> + pub fn filter_map(mut orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_mut() }) { diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index a2abd4f692ec..6976c0a64e23 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -147,11 +147,11 @@ unsafe impl Sync for RwLockWriteGuard<'_, T> {} /// RAII structure used to release the shared read access of a lock when /// dropped, which can point to a subfield of the protected data. /// -/// This structure is created by the [`map`] and [`try_map`] methods +/// This structure is created by the [`map`] and [`filter_map`] methods /// on [`RwLockReadGuard`]. /// /// [`map`]: RwLockReadGuard::map -/// [`try_map`]: RwLockReadGuard::try_map +/// [`filter_map`]: RwLockReadGuard::filter_map #[must_use = "if unused the RwLock will immediately unlock"] #[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \ points can cause deadlocks, delays, \ @@ -176,11 +176,11 @@ unsafe impl Sync for MappedRwLockReadGuard<'_, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped, which can point to a subfield of the protected data. /// -/// This structure is created by the [`map`] and [`try_map`] methods +/// This structure is created by the [`map`] and [`filter_map`] methods /// on [`RwLockWriteGuard`]. /// /// [`map`]: RwLockWriteGuard::map -/// [`try_map`]: RwLockWriteGuard::try_map +/// [`filter_map`]: RwLockWriteGuard::filter_map #[must_use = "if unused the RwLock will immediately unlock"] #[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \ points can cause deadlocks, delays, \ @@ -788,7 +788,7 @@ impl Deref for MappedRwLockReadGuard<'_, T> { fn deref(&self) -> &T { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_ref() } } } @@ -799,7 +799,7 @@ impl Deref for MappedRwLockWriteGuard<'_, T> { fn deref(&self) -> &T { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_ref() } } } @@ -808,7 +808,7 @@ impl Deref for MappedRwLockWriteGuard<'_, T> { impl DerefMut for MappedRwLockWriteGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_mut() } } } @@ -838,7 +838,7 @@ impl Drop for RwLockWriteGuard<'_, T> { impl Drop for MappedRwLockReadGuard<'_, T> { fn drop(&mut self) { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.inner_lock.read_unlock(); } @@ -850,7 +850,7 @@ impl Drop for MappedRwLockWriteGuard<'_, T> { fn drop(&mut self) { self.poison_flag.done(&self.poison); // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.inner_lock.write_unlock(); } @@ -878,7 +878,7 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_ref() })); @@ -893,22 +893,21 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// The `RwLock` is already locked for reading, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RwLockReadGuard::try_map(...)`. A method would interfere with methods + /// `RwLockReadGuard::filter_map(...)`. A method would interfere with methods /// of the same name on the contents of the `RwLockReadGuard` used through /// `Deref`. /// /// # Panics /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, Self> where F: FnOnce(&T) -> Option<&U>, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_ref() }) { @@ -943,7 +942,7 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_ref() })); @@ -958,22 +957,21 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { /// The `RwLock` is already locked for reading, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with + /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with /// methods of the same name on the contents of the `MappedRwLockReadGuard` /// used through `Deref`. /// /// # Panics /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, Self> where F: FnOnce(&T) -> Option<&U>, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_ref() }) { @@ -1008,7 +1006,7 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); @@ -1029,22 +1027,21 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// The `RwLock` is already locked for writing, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods + /// `RwLockWriteGuard::filter_map(...)`. A method would interfere with methods /// of the same name on the contents of the `RwLockWriteGuard` used through /// `Deref`. /// /// # Panics /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { &mut *orig.lock.data.get() }) { @@ -1147,7 +1144,7 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_mut() })); @@ -1168,22 +1165,21 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// The `RwLock` is already locked for writing, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with + /// `MappedRwLockWriteGuard::filter_map(...)`. A method would interfere with /// methods of the same name on the contents of the `MappedRwLockWriteGuard` /// used through `Deref`. /// /// # Panics /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(mut orig: Self, f: F) -> Result, Self> + pub fn filter_map(mut orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. // The signature of the closure guarantees that it will not "leak" the lifetime of the reference // passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_mut() }) { diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs index 88fb448d1ebf..ac82914d6de4 100644 --- a/library/std/tests/sync/mutex.rs +++ b/library/std/tests/sync/mutex.rs @@ -409,13 +409,13 @@ fn panic_while_mapping_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); - let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MutexGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_lock() { - Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"), + Ok(_) => panic!("panicking in a MutexGuard::filter_map closure should poison the Mutex"), Err(TryLockError::WouldBlock) => { - panic!("panicking in a MutexGuard::try_map closure should unlock the mutex") + panic!("panicking in a MutexGuard::filter_map closure should unlock the mutex") } Err(TryLockError::Poisoned(_)) => {} } @@ -437,13 +437,15 @@ fn panic_while_mapping_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let guard = MutexGuard::map::<(), _>(guard, |val| val); - let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedMutexGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_lock() { - Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"), + Ok(_) => { + panic!("panicking in a MappedMutexGuard::filter_map closure should poison the Mutex") + } Err(TryLockError::WouldBlock) => { - panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex") + panic!("panicking in a MappedMutexGuard::filter_map closure should unlock the mutex") } Err(TryLockError::Poisoned(_)) => {} } diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index d2c784aefcf6..1d55a1769483 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -517,16 +517,20 @@ fn panic_while_mapping_read_unlocked_no_poison() { let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); - let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = RwLockReadGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => {} Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock") + panic!( + "panicking in a RwLockReadGuard::filter_map closure should release the read lock" + ) } Err(TryLockError::Poisoned(_)) => { - panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock") + panic!( + "panicking in a RwLockReadGuard::filter_map closure should not poison the RwLock" + ) } } @@ -549,16 +553,16 @@ fn panic_while_mapping_read_unlocked_no_poison() { let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedRwLockReadGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => {} Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock" + "panicking in a MappedRwLockReadGuard::filter_map closure should release the read lock" ), Err(TryLockError::Poisoned(_)) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock" + "panicking in a MappedRwLockReadGuard::filter_map closure should not poison the RwLock" ), } @@ -585,15 +589,17 @@ fn panic_while_mapping_write_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); - let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = RwLockWriteGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock") + panic!("panicking in a RwLockWriteGuard::filter_map closure should poison the RwLock") } Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock") + panic!( + "panicking in a RwLockWriteGuard::filter_map closure should release the write lock" + ) } Err(TryLockError::Poisoned(_)) => {} } @@ -617,15 +623,15 @@ fn panic_while_mapping_write_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedRwLockWriteGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock" + "panicking in a MappedRwLockWriteGuard::filter_map closure should poison the RwLock" ), Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock" + "panicking in a MappedRwLockWriteGuard::filter_map closure should release the write lock" ), Err(TryLockError::Poisoned(_)) => {} } From 482ad5c51e5cab94b43f823f3cc2f94c87553237 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 1 May 2025 08:34:22 +0800 Subject: [PATCH 102/302] Remove redundant min-llvm-version annotations for LoongArch tests --- tests/ui/abi/compatibility.rs | 1 - .../bad-reg.loongarch64_lp64d.stderr | 12 +++++------ .../bad-reg.loongarch64_lp64s.stderr | 20 +++++++++---------- tests/ui/asm/loongarch/bad-reg.rs | 1 - 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index be649029c863..68706f1e821a 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -40,7 +40,6 @@ //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch -//@[loongarch64] min-llvm-version: 20 //FIXME: wasm is disabled due to . //FIXME @ revisions: wasm //FIXME @[wasm] compile-flags: --target wasm32-unknown-unknown diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr index c88f3af76426..0e5441196501 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:23:18 + --> $DIR/bad-reg.rs:22:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:25:18 + --> $DIR/bad-reg.rs:24:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr index cb8e55a9722d..6d0410dc6a13 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:23:18 + --> $DIR/bad-reg.rs:22:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:25:18 + --> $DIR/bad-reg.rs:24:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:37:26 + --> $DIR/bad-reg.rs:36:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:39:26 + --> $DIR/bad-reg.rs:38:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:41:26 + --> $DIR/bad-reg.rs:40:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:43:26 + --> $DIR/bad-reg.rs:42:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs index db1c778e5a25..685b460bc922 100644 --- a/tests/ui/asm/loongarch/bad-reg.rs +++ b/tests/ui/asm/loongarch/bad-reg.rs @@ -1,7 +1,6 @@ //@ add-core-stubs //@ needs-asm-support //@ revisions: loongarch64_lp64d loongarch64_lp64s -//@ min-llvm-version: 20 //@[loongarch64_lp64d] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64_lp64d] needs-llvm-components: loongarch //@[loongarch64_lp64s] compile-flags: --target loongarch64-unknown-none-softfloat From f27ba892bd9cd535aa3674496dfa217b875539a6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 30 Apr 2025 17:52:10 -0700 Subject: [PATCH 103/302] Update hashbrown dependency to unblock ExtractIf improvements --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 361d237b3af8..b45dec0d7cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1502,9 +1502,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", From 589200ea5ed1d83d8680bc3db6dd6bc559a25539 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 1 May 2025 04:53:52 +0000 Subject: [PATCH 104/302] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 59d53891217d..66b4fe2bf3bf 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1b8ab72680f36e783af84c1a3c4f8508572bd9f9 +0c33fe2c3d3eecadd17a84b110bb067288a64f1c From 7adaa5044847517fa5a6552fa67e9161bcf300c9 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 1 May 2025 05:02:17 +0000 Subject: [PATCH 105/302] fmt --- src/tools/miri/src/machine.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 3ee53005a036..201b950e29ca 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1203,9 +1203,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &mut InterpCx<'tcx, Self>, val: ImmTy<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx>> { - crate::math::apply_random_float_error_to_imm( - ecx, val, 2 /* log2(4) */ - ) + crate::math::apply_random_float_error_to_imm(ecx, val, 2 /* log2(4) */) } #[inline(always)] From eec6cfb8dab2d20e58a44df0e1c52c5abf6b2d26 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Mon, 24 Mar 2025 00:23:46 +0000 Subject: [PATCH 106/302] rustc_target: RISC-V "Zfinx" is incompatible with {ILP32,LP64}[FD] ABIs Because RISC-V Calling Conventions note that: > This means code targeting the Zfinx extension always uses the ILP32, > ILP32E or LP64 integer calling-convention only ABIs as there is no > dedicated hardware floating-point register file. {ILP32,LP64}[FD] ABIs with hardware floating-point calling conventions are incompatible with the "Zfinx" extension. This commit adds "zfinx" to the incompatible feature list to those ABIs and tests whether trying to add "zdinx" (that is analogous to "zfinx" but in double-precision) on a LP64D ABI configuration results in an error (it also tests extension implication; "Zdinx" requires "Zfinx" extension). Link: RISC-V psABI specification version 1.0 --- compiler/rustc_target/src/target_features.rs | 8 ++++---- ...bidden-hardfloat-target-feature-attribute-e-d.rs} | 0 ...en-hardfloat-target-feature-attribute-e-d.stderr} | 2 +- ...den-hardfloat-target-feature-attribute-f-zfinx.rs | 12 ++++++++++++ ...hardfloat-target-feature-attribute-f-zfinx.stderr | 8 ++++++++ 5 files changed, 25 insertions(+), 5 deletions(-) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.rs => forbidden-hardfloat-target-feature-attribute-e-d.rs} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.stderr => forbidden-hardfloat-target-feature-attribute-e-d.stderr} (77%) create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..9c8c804e18cd 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -963,12 +963,12 @@ impl Target { // about what the intended ABI is. match &*self.llvm_abiname { "ilp32d" | "lp64d" => { - // Requires d (which implies f), incompatible with e. - FeatureConstraints { required: &["d"], incompatible: &["e"] } + // Requires d (which implies f), incompatible with e and zfinx. + FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] } } "ilp32f" | "lp64f" => { - // Requires f, incompatible with e. - FeatureConstraints { required: &["f"], incompatible: &["e"] } + // Requires f, incompatible with e and zfinx. + FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] } } "ilp32" | "lp64" => { // Requires nothing, incompatible with e. diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr similarity index 77% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr index bfe767e5ffb0..84d27463b38c 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr @@ -1,5 +1,5 @@ error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18 + --> $DIR/forbidden-hardfloat-target-feature-attribute-e-d.rs:10:18 | LL | #[target_feature(enable = "d")] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs new file mode 100644 index 000000000000..d74f4a1d4b17 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs @@ -0,0 +1,12 @@ +//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. +//@ compile-flags: --target=riscv64gc-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +#[target_feature(enable = "zdinx")] +//~^ERROR: cannot be enabled with +pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr new file mode 100644 index 000000000000..af0e53f34f23 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr @@ -0,0 +1,8 @@ +error: target feature `zfinx` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs:10:18 + | +LL | #[target_feature(enable = "zdinx")] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From a6b8abf341013a9f13423a0012ab0fa096a825c7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 1 May 2025 07:27:32 +0200 Subject: [PATCH 107/302] Bump salsa --- src/tools/rust-analyzer/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index a29717d67abe..dd39cf59bb44 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,8 +131,8 @@ process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" -salsa = { version = "0.21.0", default-features = false, features = ["rayon","salsa_unstable"] } -salsa-macros = "0.21.0" +salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] } +salsa-macros = "0.21.1" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } From 7cb357a36b96781f9ff85f8a4168382243352ba1 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 11 Apr 2025 02:52:17 -0700 Subject: [PATCH 108/302] Make internal `OsString::truncate` and `extend_from_slice` unsafe Communicate the safety invariants of these methods with `unsafe fn` rather than privacy. --- library/std/src/ffi/os_str.rs | 22 ++++++++++++++++------ library/std/src/path.rs | 3 ++- library/std/src/sys/os_str/bytes.rs | 23 +++++++++++++++-------- library/std/src/sys/os_str/wtf8.rs | 28 ++++++++++++++++++++-------- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ce01175309a7..72bdf03ee61a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -582,15 +582,25 @@ impl OsString { #[unstable(feature = "os_string_truncate", issue = "133262")] pub fn truncate(&mut self, len: usize) { self.as_os_str().inner.check_public_boundary(len); - self.inner.truncate(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`OsStr::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the encoding-dependent surrogate joining, so `self` must + /// not end with a leading surrogate half and `other` must not start with + /// with a trailing surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { - self.inner.extend_from_slice(other); + pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { + // SAFETY: Guaranteed by caller. + unsafe { self.inner.extend_from_slice_unchecked(other) }; } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 50f403ba411b..ae18891ad47d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2759,7 +2759,8 @@ impl Path { }; let mut new_path = PathBuf::with_capacity(new_capacity); - new_path.inner.extend_from_slice(slice_to_copy); + // SAFETY: The path is empty, so cannot have surrogate halves. + unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) }; new_path.set_extension(extension); new_path } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index dfff2d3e5d31..4a8808c92304 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -216,19 +216,26 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// This encoding has no safety requirements. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index a32f5d40f6a9..5174ea65d0cd 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -195,19 +195,31 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`Slice::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a + /// leading surrogate half and `other` must not start with with a trailing + /// surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } From 0f0c0d8b16b265ac57cac9fd50f1dcfe78719a6a Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 22 Apr 2025 03:31:45 -0700 Subject: [PATCH 109/302] Avoid redundant WTF-8 checks in `PathBuf` Eliminate checks for WTF-8 boundaries in `PathBuf::set_extension` and `add_extension`, where joining WTF-8 surrogate halves is impossible. Don't convert the `str` to `OsStr`, because `OsString::push` specializes to skip the joining when given strings. --- library/std/src/path.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index ae18891ad47d..32a86e9f7b40 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1526,11 +1526,13 @@ impl PathBuf { self.inner.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true @@ -1587,7 +1589,7 @@ impl PathBuf { Some(f) => f.as_encoded_bytes(), }; - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { // truncate until right after the file name // this is necessary for trimming the trailing slash @@ -1597,8 +1599,10 @@ impl PathBuf { // append the new extension self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true From 408232fb51b89cf543f1fe85c250b764656c8ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 1 May 2025 10:21:46 +0300 Subject: [PATCH 110/302] Update lockfile --- src/tools/rust-analyzer/Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index d257988a57a0..8d6c8284e44e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2039,9 +2039,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4deeb38b4c80ac90a8d4796f83da941b0d76c23783550d15d37eb43ccddcb5bc" +checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5" dependencies = [ "boxcar", "crossbeam-queue", @@ -2062,15 +2062,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e6166fa2802d86a77dbcae1bfe75f0ac46fdf952660c233ed64855a53dd603" +checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185" [[package]] name = "salsa-macros" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf358e645a835d9901ee4d812d9812266e046ee92a28d2e37a73b7169a6503b7" +checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50" dependencies = [ "heck", "proc-macro2", From b01b98f9f0b350badf8390e7950759d78484622d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 1 May 2025 10:21:52 +0300 Subject: [PATCH 111/302] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 09c127f6bcd8..90e4d65bf961 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -21079f53a359d9fc82668d4175d49dafdb600563 +6e23095adf9209614a45f7f75fea36dad7b92afb From 8a91bbfa91a5e2e269131f1da7b84d87cf2b4591 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 1 May 2025 09:50:54 +0200 Subject: [PATCH 112/302] Bump nightly version -> 2025-05-01 --- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index aceff14a1599..66192f866fa0 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-04-22 +nightly-2025-05-01 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d2f79da1a541..39c7f0e4ad5a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-04-22" +channel = "nightly-2025-05-01" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From d3ec14bbec7d3647a3c1a3bfdf2cafb0f72bf937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Apr 2025 21:27:53 +0200 Subject: [PATCH 113/302] Use thread local dep graph encoding --- compiler/rustc_data_structures/src/sync.rs | 2 +- .../src/sync/parallel.rs | 10 + .../rustc_incremental/src/persist/save.rs | 13 +- .../rustc_query_system/src/dep_graph/graph.rs | 76 ++-- .../rustc_query_system/src/dep_graph/mod.rs | 3 +- .../src/dep_graph/serialized.rs | 371 +++++++++++------- 6 files changed, 290 insertions(+), 185 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 80d49effbf8a..b28c333d860c 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,7 +43,7 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; pub use self::lock::{Lock, LockGuard, Mode}; pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; pub use self::parallel::{ - join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in, + broadcast, join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in, }; pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec}; pub use self::worker_local::{Registry, WorkerLocal}; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 64db39cc4c6e..ab65c7f3a6b5 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -237,3 +237,13 @@ pub fn par_map, R: DynSend, C: FromIterato } }) } + +pub fn broadcast(op: impl Fn(usize) -> R + DynSync) -> Vec { + if mode::is_dyn_thread_safe() { + let op = FromDyn::from(op); + let results = rayon_core::broadcast(|context| op.derive(op(context.index()))); + results.into_iter().map(|r| r.into_inner()).collect() + } else { + vec![op(0)] + } +} diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 94ce6d9fa81f..58fea3278a83 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -44,10 +44,6 @@ pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) { sess.time("assert_dep_graph", || assert_dep_graph(tcx)); sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)); - if sess.opts.unstable_opts.incremental_info { - tcx.dep_graph.print_incremental_info() - } - join( move || { sess.time("incr_comp_persist_dep_graph", || { @@ -172,12 +168,5 @@ pub(crate) fn build_dep_graph( // First encode the commandline arguments hash sess.opts.dep_tracking_hash(false).encode(&mut encoder); - Some(DepGraph::new( - sess, - prev_graph, - prev_work_products, - encoder, - sess.opts.unstable_opts.query_dep_graph, - sess.opts.unstable_opts.incremental_info, - )) + Some(DepGraph::new(sess, prev_graph, prev_work_products, encoder)) } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0d56db160996..180a2c9edf67 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -11,7 +11,7 @@ use rustc_data_structures::outline; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU64, Lock}; +use rustc_data_structures::sync::{AtomicU64, Lock, is_dyn_thread_safe}; use rustc_data_structures::unord::UnordMap; use rustc_errors::DiagInner; use rustc_index::IndexVec; @@ -124,19 +124,11 @@ impl DepGraph { prev_graph: Arc, prev_work_products: WorkProductMap, encoder: FileEncoder, - record_graph: bool, - record_stats: bool, ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); - let current = CurrentDepGraph::new( - session, - prev_graph_node_count, - encoder, - record_graph, - record_stats, - Arc::clone(&prev_graph), - ); + let current = + CurrentDepGraph::new(session, prev_graph_node_count, encoder, Arc::clone(&prev_graph)); let colors = DepNodeColorMap::new(prev_graph_node_count); @@ -1052,17 +1044,8 @@ impl DepGraph { } } - pub fn print_incremental_info(&self) { - if let Some(data) = &self.data { - data.current.encoder.print_incremental_info( - data.current.total_read_count.load(Ordering::Relaxed), - data.current.total_duplicate_read_count.load(Ordering::Relaxed), - ) - } - } - pub fn finish_encoding(&self) -> FileEncodeResult { - if let Some(data) = &self.data { data.current.encoder.finish() } else { Ok(0) } + if let Some(data) = &self.data { data.current.encoder.finish(&data.current) } else { Ok(0) } } pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { @@ -1179,8 +1162,8 @@ pub(super) struct CurrentDepGraph { /// These are simple counters that are for profiling and /// debugging and only active with `debug_assertions`. - total_read_count: AtomicU64, - total_duplicate_read_count: AtomicU64, + pub(super) total_read_count: AtomicU64, + pub(super) total_duplicate_read_count: AtomicU64, } impl CurrentDepGraph { @@ -1188,8 +1171,6 @@ impl CurrentDepGraph { session: &Session, prev_graph_node_count: usize, encoder: FileEncoder, - record_graph: bool, - record_stats: bool, previous: Arc, ) -> Self { let mut stable_hasher = StableHasher::new(); @@ -1211,14 +1192,7 @@ impl CurrentDepGraph { session.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions); CurrentDepGraph { - encoder: GraphEncoder::new( - encoder, - prev_graph_node_count, - record_graph, - record_stats, - &session.prof, - previous, - ), + encoder: GraphEncoder::new(session, encoder, prev_graph_node_count, previous), anon_node_to_index: ShardedHashMap::with_capacity( // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. new_node_count_estimate / sharded::shards(), @@ -1345,6 +1319,7 @@ impl Default for TaskDeps { // array, using one u32 per entry. pub(super) struct DepNodeColorMap { values: IndexVec, + sync: bool, } const COMPRESSED_NONE: u32 = u32::MAX; @@ -1353,7 +1328,10 @@ const COMPRESSED_RED: u32 = u32::MAX - 1; impl DepNodeColorMap { fn new(size: usize) -> DepNodeColorMap { debug_assert!(COMPRESSED_RED > DepNodeIndex::MAX_AS_U32); - DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } + DepNodeColorMap { + values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(), + sync: is_dyn_thread_safe(), + } } #[inline] @@ -1362,6 +1340,36 @@ impl DepNodeColorMap { if value <= DepNodeIndex::MAX_AS_U32 { Some(DepNodeIndex::from_u32(value)) } else { None } } + /// This tries to atomically mark a node green and assign `index` as the new + /// index. + #[inline] + pub(super) fn try_mark_green( + &self, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Result<(), DepNodeIndex> { + let value = &self.values[prev_index]; + if self.sync { + match value.compare_exchange( + COMPRESSED_NONE, + index.as_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ) { + Ok(_) => Ok(()), + Err(v) => Err(DepNodeIndex::from_u32(v)), + } + } else { + let v = value.load(Ordering::Relaxed); + if v == COMPRESSED_NONE { + value.store(index.as_u32(), Ordering::Relaxed); + Ok(()) + } else { + Err(DepNodeIndex::from_u32(v)) + } + } + } + #[inline] pub(super) fn get(&self, index: SerializedDepNodeIndex) -> Option { match self.values[index].load(Ordering::Acquire) { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 3a80835afad5..89d1db878095 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -12,6 +12,7 @@ pub(crate) use graph::DepGraphData; pub use graph::{DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result}; pub use query::DepGraphQuery; use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::DynSync; use rustc_session::Session; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use tracing::instrument; @@ -89,7 +90,7 @@ pub trait DepContext: Copy { } } -pub trait Deps { +pub trait Deps: DynSync { /// Execute the operation with provided dependencies. fn with_deps(deps: TaskDepsRef<'_>, op: OP) -> R where diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index d2bcde143835..e88d95b6b074 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -35,23 +35,27 @@ //! If the number of edges in this node does not fit in the bits available in the header, we //! store it directly after the header with leb128. -use std::iter; +use std::cell::RefCell; +use std::cmp::max; use std::marker::PhantomData; use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::{iter, mem, u64}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::outline; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{Lock, WorkerLocal, broadcast}; use rustc_data_structures::unhash::UnhashMap; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_serialize::opaque::mem_encoder::MemEncoder; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_session::Session; use tracing::{debug, instrument}; -use super::graph::{DepNodeColor, DepNodeColorMap}; +use super::graph::{CurrentDepGraph, DepNodeColor, DepNodeColorMap}; use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex, Deps}; use crate::dep_graph::edges::EdgesVec; @@ -76,6 +80,9 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; /// Data for use when recompiling the **current crate**. +/// +/// There may be unused indices with DEP_KIND_NULL in this graph due to batch allocation of +/// indices to threads. #[derive(Debug, Default)] pub struct SerializedDepGraph { /// The set of all DepNodes in the graph @@ -184,26 +191,30 @@ impl SerializedDepGraph { pub fn decode(d: &mut MemDecoder<'_>, deps: &D) -> Arc { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); - let (node_count, edge_count) = - d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| { + + // `node_max` is the number of indices including empty nodes while `node_count` + // is the number of actually encoded nodes. + let (node_max, node_count, edge_count) = + d.with_position(d.len() - 3 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| { debug!("position: {:?}", d.position()); + let node_max = IntEncodedWithFixedSize::decode(d).0 as usize; let node_count = IntEncodedWithFixedSize::decode(d).0 as usize; let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize; - (node_count, edge_count) + (node_max, node_count, edge_count) }); debug!("position: {:?}", d.position()); debug!(?node_count, ?edge_count); - let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); + let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); let mut nodes = IndexVec::from_elem_n( DepNode { kind: D::DEP_KIND_NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) }, - node_count, + node_max, ); - let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_count); + let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max); let mut edge_list_indices = - IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_count); + IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max); // This estimation assumes that all of the encoded bytes are for the edge lists or for the // fixed-size node headers. But that's not necessarily true; if any edge list has a length @@ -217,7 +228,7 @@ impl SerializedDepGraph { let mut edge_list_data = Vec::with_capacity(graph_bytes - node_count * size_of::>()); - for _index in 0..node_count { + for _ in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. let node_header = @@ -263,8 +274,8 @@ impl SerializedDepGraph { for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { - // Side effect nodes can have duplicates - if node.kind != D::DEP_KIND_SIDE_EFFECT { + // Empty nodes and side effect nodes can have duplicates + if node.kind != D::DEP_KIND_NULL && node.kind != D::DEP_KIND_SIDE_EFFECT { let name = deps.name(node.kind); panic!( "Error: A dep graph node ({name}) does not have an unique index. \ @@ -508,17 +519,32 @@ struct Stat { edge_counter: u64, } -struct EncoderState { - previous: Arc, - encoder: FileEncoder, - total_node_count: usize, - total_edge_count: usize, - stats: Option>, - - mem_encoder: MemEncoder, +struct LocalEncoderState { + next_node_index: u32, + remaining_node_index: u32, + encoder: MemEncoder, + node_count: usize, + edge_count: usize, /// Stores the number of times we've encoded each dep kind. kind_stats: Vec, +} + +struct LocalEncoderResult { + node_max: u32, + node_count: usize, + edge_count: usize, + + /// Stores the number of times we've encoded each dep kind. + kind_stats: Vec, +} + +struct EncoderState { + next_node_index: AtomicU64, + previous: Arc, + file: Lock>, + local: WorkerLocal>, + stats: Option>>, marker: PhantomData, } @@ -526,34 +552,58 @@ impl EncoderState { fn new(encoder: FileEncoder, record_stats: bool, previous: Arc) -> Self { Self { previous, - encoder, - total_edge_count: 0, - total_node_count: 0, - stats: record_stats.then(FxHashMap::default), - mem_encoder: MemEncoder::new(), - kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + next_node_index: AtomicU64::new(0), + stats: record_stats.then(|| Lock::new(FxHashMap::default())), + file: Lock::new(Some(encoder)), + local: WorkerLocal::new(|_| { + RefCell::new(LocalEncoderState { + next_node_index: 0, + remaining_node_index: 0, + edge_count: 0, + node_count: 0, + encoder: MemEncoder::new(), + kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + }) + }), marker: PhantomData, } } #[inline] - fn alloc_index(&mut self) -> DepNodeIndex { - let index = DepNodeIndex::new(self.total_node_count); - self.total_node_count += 1; - index + fn next_index(&self, local: &mut LocalEncoderState) -> DepNodeIndex { + if local.remaining_node_index == 0 { + let count = 256; + + // We assume that there won't be enough active threads to overflow u64 from u32::MAX here. + assert!(self.next_node_index.load(Ordering::Relaxed) <= u32::MAX as u64); + local.next_node_index = + self.next_node_index.fetch_add(count, Ordering::Relaxed).try_into().unwrap(); + + local.remaining_node_index = count as u32; + } + + DepNodeIndex::from_u32(local.next_node_index) + } + + #[inline] + fn bump_index(&self, local: &mut LocalEncoderState) { + local.remaining_node_index -= 1; + local.next_node_index += 1; + local.node_count += 1; } #[inline] fn record( - &mut self, + &self, node: DepNode, index: DepNodeIndex, edge_count: usize, - edges: impl FnOnce(&mut Self) -> Vec, + edges: impl FnOnce(&Self) -> Vec, record_graph: &Option>, - ) -> DepNodeIndex { - self.kind_stats[node.kind.as_usize()] += 1; - self.total_edge_count += edge_count; + local: &mut LocalEncoderState, + ) { + local.kind_stats[node.kind.as_usize()] += 1; + local.edge_count += edge_count; if let Some(record_graph) = &record_graph { // Call `edges` before the outlined code to allow the closure to be optimized out. @@ -568,40 +618,47 @@ impl EncoderState { }); } - if let Some(stats) = &mut self.stats { + if let Some(stats) = &self.stats { let kind = node.kind; // Outline the stats code as it's typically disabled and cold. outline(move || { + let mut stats = stats.lock(); let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); stat.node_counter += 1; stat.edge_counter += edge_count as u64; }); } - - index } #[inline] - fn flush_mem_encoder(&mut self) { - let data = &mut self.mem_encoder.data; + fn flush_mem_encoder(&self, local: &mut LocalEncoderState) { + let data = &mut local.encoder.data; if data.len() > 64 * 1024 { - self.encoder.emit_raw_bytes(&data[..]); + self.file.lock().as_mut().unwrap().emit_raw_bytes(&data[..]); data.clear(); } } /// Encodes a node to the current graph. fn encode_node( - &mut self, + &self, + index: DepNodeIndex, node: &NodeInfo, record_graph: &Option>, - ) -> DepNodeIndex { - let index = self.alloc_index(); - node.encode::(&mut self.mem_encoder, index); - self.flush_mem_encoder(); - self.record(node.node, index, node.edges.len(), |_| node.edges[..].to_vec(), record_graph) + local: &mut LocalEncoderState, + ) { + node.encode::(&mut local.encoder, index); + self.flush_mem_encoder(&mut *local); + self.record( + node.node, + index, + node.edges.len(), + |_| node.edges[..].to_vec(), + record_graph, + &mut *local, + ); } /// Encodes a node that was promoted from the previous graph. It reads the information directly from @@ -612,16 +669,17 @@ impl EncoderState { /// It expects all edges to already have a new dep node index assigned. #[inline] fn encode_promoted_node( - &mut self, + &self, + index: DepNodeIndex, prev_index: SerializedDepNodeIndex, record_graph: &Option>, colors: &DepNodeColorMap, - ) -> DepNodeIndex { - let index = self.alloc_index(); + local: &mut LocalEncoderState, + ) { let node = self.previous.index_to_node(prev_index); let fingerprint = self.previous.fingerprint_by_index(prev_index); let edge_count = NodeInfo::encode_promoted::( - &mut self.mem_encoder, + &mut local.encoder, node, index, fingerprint, @@ -629,7 +687,7 @@ impl EncoderState { colors, &self.previous, ); - self.flush_mem_encoder(); + self.flush_mem_encoder(&mut *local); self.record( node, index, @@ -641,38 +699,60 @@ impl EncoderState { .collect() }, record_graph, + &mut *local, ); - index } - fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { - let Self { - mut encoder, - mem_encoder, - total_node_count, - total_edge_count, - stats: _, - kind_stats, - marker: _, - previous, - } = self; + fn finish(&self, profiler: &SelfProfilerRef, current: &CurrentDepGraph) -> FileEncodeResult { + // Prevent more indices from being allocated. + self.next_node_index.store(u32::MAX as u64 + 1, Ordering::SeqCst); - encoder.emit_raw_bytes(&mem_encoder.data); + let results = broadcast(|_| { + let mut local = self.local.borrow_mut(); - let node_count = total_node_count.try_into().unwrap(); - let edge_count = total_edge_count.try_into().unwrap(); + // Prevent more indices from being allocated on this thread. + local.remaining_node_index = 0; + + let data = mem::replace(&mut local.encoder.data, Vec::new()); + self.file.lock().as_mut().unwrap().emit_raw_bytes(&data); + + LocalEncoderResult { + kind_stats: local.kind_stats.clone(), + node_max: local.next_node_index, + node_count: local.node_count, + edge_count: local.edge_count, + } + }); + + let mut encoder = self.file.lock().take().unwrap(); + + let mut kind_stats: Vec = iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(); + + let mut node_max = 0; + let mut node_count = 0; + let mut edge_count = 0; + + for result in results { + node_max = max(node_max, result.node_max); + node_count += result.node_count; + edge_count += result.edge_count; + for (i, stat) in result.kind_stats.iter().enumerate() { + kind_stats[i] += stat; + } + } // Encode the number of each dep kind encountered for count in kind_stats.iter() { count.encode(&mut encoder); } - previous.session_count.checked_add(1).unwrap().encode(&mut encoder); + self.previous.session_count.checked_add(1).unwrap().encode(&mut encoder); - debug!(?node_count, ?edge_count); + debug!(?node_max, ?node_count, ?edge_count); debug!("position: {:?}", encoder.position()); - IntEncodedWithFixedSize(node_count).encode(&mut encoder); - IntEncodedWithFixedSize(edge_count).encode(&mut encoder); + IntEncodedWithFixedSize(node_max.try_into().unwrap()).encode(&mut encoder); + IntEncodedWithFixedSize(node_count.try_into().unwrap()).encode(&mut encoder); + IntEncodedWithFixedSize(edge_count.try_into().unwrap()).encode(&mut encoder); debug!("position: {:?}", encoder.position()); // Drop the encoder so that nothing is written after the counts. let result = encoder.finish(); @@ -681,44 +761,20 @@ impl EncoderState { // don't need a dependency on rustc_incremental just for that. profiler.artifact_size("dep_graph", "dep-graph.bin", position as u64); } + + self.print_incremental_info(current, node_count, edge_count); + result } -} -pub(crate) struct GraphEncoder { - profiler: SelfProfilerRef, - status: Lock>>, - record_graph: Option>, -} - -impl GraphEncoder { - pub(crate) fn new( - encoder: FileEncoder, - prev_node_count: usize, - record_graph: bool, - record_stats: bool, - profiler: &SelfProfilerRef, - previous: Arc, - ) -> Self { - let record_graph = record_graph.then(|| Lock::new(DepGraphQuery::new(prev_node_count))); - let status = Lock::new(Some(EncoderState::new(encoder, record_stats, previous))); - GraphEncoder { status, record_graph, profiler: profiler.clone() } - } - - pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { - if let Some(record_graph) = &self.record_graph { - f(&record_graph.lock()) - } - } - - pub(crate) fn print_incremental_info( + fn print_incremental_info( &self, - total_read_count: u64, - total_duplicate_read_count: u64, + current: &CurrentDepGraph, + total_node_count: usize, + total_edge_count: usize, ) { - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); - if let Some(record_stats) = &status.stats { + if let Some(record_stats) = &self.stats { + let record_stats = record_stats.lock(); let mut stats: Vec<_> = record_stats.values().collect(); stats.sort_by_key(|s| -(s.node_counter as i64)); @@ -730,10 +786,13 @@ impl GraphEncoder { eprintln!("[incremental] DepGraph Statistics"); eprintln!("{SEPARATOR}"); eprintln!("[incremental]"); - eprintln!("[incremental] Total Node Count: {}", status.total_node_count); - eprintln!("[incremental] Total Edge Count: {}", status.total_edge_count); + eprintln!("[incremental] Total Node Count: {}", total_node_count); + eprintln!("[incremental] Total Edge Count: {}", total_edge_count); if cfg!(debug_assertions) { + let total_read_count = current.total_read_count.load(Ordering::Relaxed); + let total_duplicate_read_count = + current.total_duplicate_read_count.load(Ordering::Relaxed); eprintln!("[incremental] Total Edge Reads: {total_read_count}"); eprintln!("[incremental] Total Duplicate Edge Reads: {total_duplicate_read_count}"); } @@ -747,7 +806,7 @@ impl GraphEncoder { for stat in stats { let node_kind_ratio = - (100.0 * (stat.node_counter as f64)) / (status.total_node_count as f64); + (100.0 * (stat.node_counter as f64)) / (total_node_count as f64); let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64); eprintln!( @@ -763,6 +822,35 @@ impl GraphEncoder { eprintln!("[incremental]"); } } +} + +pub(crate) struct GraphEncoder { + profiler: SelfProfilerRef, + status: EncoderState, + record_graph: Option>, +} + +impl GraphEncoder { + pub(crate) fn new( + sess: &Session, + encoder: FileEncoder, + prev_node_count: usize, + previous: Arc, + ) -> Self { + let record_graph = sess + .opts + .unstable_opts + .query_dep_graph + .then(|| Lock::new(DepGraphQuery::new(prev_node_count))); + let status = EncoderState::new(encoder, sess.opts.unstable_opts.incremental_info, previous); + GraphEncoder { status, record_graph, profiler: sess.prof.clone() } + } + + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + if let Some(record_graph) = &self.record_graph { + f(&record_graph.lock()) + } + } /// Encodes a node that does not exists in the previous graph. pub(crate) fn send_new( @@ -773,7 +861,11 @@ impl GraphEncoder { ) -> DepNodeIndex { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; - self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph) + let mut local = self.status.local.borrow_mut(); + let index = self.status.next_index(&mut *local); + self.status.bump_index(&mut *local); + self.status.encode_node(index, &node, &self.record_graph, &mut *local); + index } /// Encodes a node that exists in the previous graph, but was re-executed. @@ -791,23 +883,24 @@ impl GraphEncoder { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); + let mut local = self.status.local.borrow_mut(); - // Check colors inside the lock to avoid racing when `send_promoted` is called concurrently - // on the same index. - match colors.get(prev_index) { - None => { - let dep_node_index = status.encode_node(&node, &self.record_graph); - colors.insert( - prev_index, - if is_green { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }, - ); - dep_node_index + let index = self.status.next_index(&mut *local); + + if is_green { + // Use `try_mark_green` to avoid racing when `send_promoted` is called concurrently + // on the same index. + match colors.try_mark_green(prev_index, index) { + Ok(()) => (), + Err(dep_node_index) => return dep_node_index, } - Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, - Some(DepNodeColor::Red) => panic!(), + } else { + colors.insert(prev_index, DepNodeColor::Red); } + + self.status.bump_index(&mut *local); + self.status.encode_node(index, &node, &self.record_graph, &mut *local); + index } /// Encodes a node that was promoted from the previous graph. It reads the information directly from @@ -822,26 +915,30 @@ impl GraphEncoder { ) -> DepNodeIndex { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); + let mut local = self.status.local.borrow_mut(); + let index = self.status.next_index(&mut *local); - // Check colors inside the lock to avoid racing when `send_promoted` or `send_and_color` + // Use `try_mark_green` to avoid racing when `send_promoted` or `send_and_color` // is called concurrently on the same index. - match colors.get(prev_index) { - None => { - let dep_node_index = - status.encode_promoted_node(prev_index, &self.record_graph, colors); - colors.insert(prev_index, DepNodeColor::Green(dep_node_index)); - dep_node_index + match colors.try_mark_green(prev_index, index) { + Ok(()) => { + self.status.bump_index(&mut *local); + self.status.encode_promoted_node( + index, + prev_index, + &self.record_graph, + colors, + &mut *local, + ); + index } - Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, - Some(DepNodeColor::Red) => panic!(), + Err(dep_node_index) => dep_node_index, } } - pub(crate) fn finish(&self) -> FileEncodeResult { + pub(crate) fn finish(&self, current: &CurrentDepGraph) -> FileEncodeResult { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph_finish"); - self.status.lock().take().unwrap().finish(&self.profiler) + self.status.finish(&self.profiler, current) } } From c43a6f05d6cedbb6a191e0c307cd257665a342e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 22 Apr 2025 04:36:58 +0200 Subject: [PATCH 114/302] Add some comments --- compiler/rustc_query_system/src/dep_graph/graph.rs | 3 ++- compiler/rustc_query_system/src/dep_graph/serialized.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 180a2c9edf67..3ae56cef2c42 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1341,7 +1341,8 @@ impl DepNodeColorMap { } /// This tries to atomically mark a node green and assign `index` as the new - /// index. + /// index. This returns `Ok` if `index` gets assigned, otherwise it returns + /// the alreadly allocated index in `Err`. #[inline] pub(super) fn try_mark_green( &self, diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index e88d95b6b074..648823edb189 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -585,6 +585,7 @@ impl EncoderState { DepNodeIndex::from_u32(local.next_node_index) } + /// Marks the index previously returned by `next_index` as used. #[inline] fn bump_index(&self, local: &mut LocalEncoderState) { local.remaining_node_index -= 1; From 8cc866d25e9f1209de04640b7063fad74c0ec813 Mon Sep 17 00:00:00 2001 From: Xinglu Chen Date: Mon, 7 Apr 2025 13:05:59 +0200 Subject: [PATCH 115/302] Add `Cell` state to Tree Borrows --- .../src/borrow_tracker/tree_borrows/mod.rs | 37 +++--- .../src/borrow_tracker/tree_borrows/perms.rs | 111 +++++++++++++----- .../src/borrow_tracker/tree_borrows/tree.rs | 10 +- .../reserved/cell-protected-write.rs | 10 +- .../reserved/cell-protected-write.stderr | 2 +- .../tree_borrows/cell-alternate-writes.rs | 8 +- .../tree_borrows/cell-alternate-writes.stderr | 8 +- .../pass/tree_borrows/interior_mutability.rs | 9 +- .../miri/tests/pass/tree_borrows/reserved.rs | 18 +-- 9 files changed, 141 insertions(+), 72 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f39a606513d5..ff09821394ab 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -123,6 +123,10 @@ struct NewPermission { /// Whether this pointer is part of the arguments of a function call. /// `protector` is `Some(_)` for all pointers marked `noalias`. protector: Option, + /// Whether a read should be performed on a retag. This should be `false` + /// for `Cell` because this could cause data races when using thread-safe + /// data types like `Mutex`. + initial_read: bool, } impl<'tcx> NewPermission { @@ -141,18 +145,19 @@ impl<'tcx> NewPermission { // To eliminate the case of Protected Reserved IM we override interior mutability // in the case of a protected reference: protected references are always considered // "freeze" in their reservation phase. - let initial_state = match mutability { - Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze, is_protected), - Mutability::Not if ty_is_freeze => Permission::new_frozen(), + let (initial_state, initial_read) = match mutability { + Mutability::Mut if ty_is_unpin => + (Permission::new_reserved(ty_is_freeze, is_protected), true), + Mutability::Not if ty_is_freeze => (Permission::new_frozen(), true), + Mutability::Not if !ty_is_freeze => (Permission::new_cell(), false), // Raw pointers never enter this function so they are not handled. // However raw pointers are not the only pointers that take the parent - // tag, this also happens for `!Unpin` `&mut`s and interior mutable - // `&`s, which are excluded above. + // tag, this also happens for `!Unpin` `&mut`s, which are excluded above. _ => return None, }; let protector = is_protected.then_some(ProtectorKind::StrongProtector); - Some(Self { zero_size: false, initial_state, protector }) + Some(Self { zero_size: false, initial_state, protector, initial_read }) } /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled). @@ -175,6 +180,7 @@ impl<'tcx> NewPermission { zero_size, initial_state, protector: protected.then_some(ProtectorKind::WeakProtector), + initial_read: true, } }) } @@ -289,13 +295,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); // All reborrows incur a (possibly zero-sized) read access to the parent - tree_borrows.perform_access( - orig_tag, - Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)), - this.machine.borrow_tracker.as_ref().unwrap(), - alloc_id, - this.machine.current_span(), - )?; + if new_perm.initial_read { + tree_borrows.perform_access( + orig_tag, + Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)), + this.machine.borrow_tracker.as_ref().unwrap(), + alloc_id, + this.machine.current_span(), + )?; + } // Record the parent-child pair in the tree. tree_borrows.new_child( orig_tag, @@ -308,7 +316,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { drop(tree_borrows); // Also inform the data race model (but only if any bytes are actually affected). - if range.size.bytes() > 0 { + if range.size.bytes() > 0 && new_perm.initial_read { if let Some(data_race) = alloc_extra.data_race.as_ref() { data_race.read( alloc_id, @@ -535,6 +543,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), zero_size: false, protector: Some(ProtectorKind::StrongProtector), + initial_read: true, }; this.tb_retag_place(place, new_perm) } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 5c12ce39d10d..087f6fc3f24b 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -8,6 +8,10 @@ use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; /// The activation states of a pointer. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum PermissionPriv { + /// represents: a shared reference to interior mutable data. + /// allows: all foreign and child accesses; + /// rejects: nothing + Cell, /// represents: a local mutable reference that has not yet been written to; /// allows: child reads, foreign reads; /// affected by: child writes (becomes Active), @@ -60,6 +64,14 @@ impl PartialOrd for PermissionPriv { use Ordering::*; Some(match (self, other) { (a, b) if a == b => Equal, + // Versions of `Reserved` with different interior mutability are incomparable with each + // other. + (ReservedIM, ReservedFrz { .. }) + | (ReservedFrz { .. }, ReservedIM) + // `Cell` is not comparable with any other permission + // since it never transitions to any other state and we + // can never get to `Cell` from another state. + | (Cell, _) | (_, Cell) => return None, (Disabled, _) => Greater, (_, Disabled) => Less, (Frozen, _) => Greater, @@ -71,9 +83,6 @@ impl PartialOrd for PermissionPriv { // `bool` is ordered such that `false <= true`, so this works as intended. c1.cmp(c2) } - // Versions of `Reserved` with different interior mutability are incomparable with each - // other. - (ReservedIM, ReservedFrz { .. }) | (ReservedFrz { .. }, ReservedIM) => return None, }) } } @@ -81,17 +90,22 @@ impl PartialOrd for PermissionPriv { impl PermissionPriv { /// Check if `self` can be the initial state of a pointer. fn is_initial(&self) -> bool { - matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM) + matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell) } /// Reject `ReservedIM` that cannot exist in the presence of a protector. fn compatible_with_protector(&self) -> bool { - !matches!(self, ReservedIM) + // FIXME(TB-Cell): It is unclear what to do here. + // `Cell` will occur with a protector but won't provide the guarantees + // of noalias (it will fail the `protected_enforces_noalias` test). + !matches!(self, ReservedIM | Cell) } /// See `foreign_access_skipping.rs`. Computes the SIFA of a permission. fn strongest_idempotent_foreign_access(&self, prot: bool) -> IdempotentForeignAccess { match self { + // Cell survives any foreign access + Cell => IdempotentForeignAccess::Write, // A protected non-conflicted Reserved will become conflicted under a foreign read, // and is hence not idempotent under it. ReservedFrz { conflicted } if prot && !conflicted => IdempotentForeignAccess::None, @@ -124,7 +138,7 @@ mod transition { Disabled => return None, // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read // accesses, since the data is not being mutated. Hence the `{ .. }`. - readable @ (ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable, + readable @ (Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable, }) } @@ -132,6 +146,8 @@ mod transition { /// is protected; invalidate `Active`. fn foreign_read(state: PermissionPriv, protected: bool) -> Option { Some(match state { + // Cell ignores foreign reads. + Cell => Cell, // Non-writeable states just ignore foreign reads. non_writeable @ (Frozen | Disabled) => non_writeable, // Writeable states are more tricky, and depend on whether things are protected. @@ -167,6 +183,8 @@ mod transition { /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB. fn child_write(state: PermissionPriv, protected: bool) -> Option { Some(match state { + // Cell ignores child writes. + Cell => Cell, // If the `conflicted` flag is set, then there was a foreign read during // the function call that is still ongoing (still `protected`), // this is UB (`noalias` violation). @@ -185,6 +203,8 @@ mod transition { // types receive a `ReservedFrz` instead of `ReservedIM` when retagged under a protector, // so the result of this function does indirectly depend on (past) protector status. Some(match state { + // Cell ignores foreign writes. + Cell => Cell, res @ ReservedIM => { // We can never create a `ReservedIM` under a protector, only `ReservedFrz`. assert!(!protected); @@ -242,6 +262,11 @@ impl Permission { self.inner == Frozen } + /// Check if `self` is the shared-reference-to-interior-mutable-data state of a pointer. + pub fn is_cell(&self) -> bool { + self.inner == Cell + } + /// Default initial permission of the root of a new tree at inbounds positions. /// Must *only* be used for the root, this is not in general an "initial" permission! pub fn new_active() -> Self { @@ -278,11 +303,27 @@ impl Permission { Self { inner: Disabled } } + /// Default initial permission of a shared reference to interior mutable data. + pub fn new_cell() -> Self { + Self { inner: Cell } + } + /// Reject `ReservedIM` that cannot exist in the presence of a protector. pub fn compatible_with_protector(&self) -> bool { self.inner.compatible_with_protector() } + /// What kind of access to perform before releasing the protector. + pub fn protector_end_access(&self) -> Option { + match self.inner { + // Do not do perform access if it is a `Cell`, as this + // can cause data races when using thread-safe data types. + Cell => None, + Active => Some(AccessKind::Write), + _ => Some(AccessKind::Read), + } + } + /// Apply the transition to the inner PermissionPriv. pub fn perform_access( kind: AccessKind, @@ -306,30 +347,32 @@ impl Permission { /// remove protected parents. pub fn can_be_replaced_by_child(self, child: Self) -> bool { match (self.inner, child.inner) { - // ReservedIM can be replaced by anything, as it allows all - // transitions. + // Cell allows all transitions. + (Cell, _) => true, + // Cell is the most permissive, nothing can be replaced by Cell. + // (ReservedIM, Cell) => true, + (_, Cell) => false, + // ReservedIM can be replaced by anything besides Cell. + // ReservedIM allows all transitions, but unlike Cell, a local write + // to ReservedIM transitions to Active, while it is a no-op for Cell. (ReservedIM, _) => true, + (_, ReservedIM) => false, // Reserved (as parent, where conflictedness does not matter) - // can be replaced by all but ReservedIM, - // since ReservedIM alone would survive foreign writes - (ReservedFrz { .. }, ReservedIM) => false, + // can be replaced by all but ReservedIM and Cell, + // since ReservedIM and Cell alone would survive foreign writes (ReservedFrz { .. }, _) => true, + (_, ReservedFrz { .. }) => false, // Active can not be replaced by something surviving - // foreign reads and then remaining writable. - (Active, ReservedIM) => false, - (Active, ReservedFrz { .. }) => false, + // foreign reads and then remaining writable (i.e., Reserved*). // Replacing a state by itself is always okay, even if the child state is protected. - (Active, Active) => true, // Active can be replaced by Frozen, since it is not protected. - (Active, Frozen) => true, - (Active, Disabled) => true, + (Active, Active | Frozen | Disabled) => true, + (_, Active) => false, // Frozen can only be replaced by Disabled (and itself). - (Frozen, Frozen) => true, - (Frozen, Disabled) => true, - (Frozen, _) => false, + (Frozen, Frozen | Disabled) => true, + (_, Frozen) => false, // Disabled can not be replaced by anything else. (Disabled, Disabled) => true, - (Disabled, _) => false, } } @@ -383,6 +426,7 @@ pub mod diagnostics { f, "{}", match self { + Cell => "Cell", ReservedFrz { conflicted: false } => "Reserved", ReservedFrz { conflicted: true } => "Reserved (conflicted)", ReservedIM => "Reserved (interior mutable)", @@ -413,6 +457,7 @@ pub mod diagnostics { // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise // alignment will be incorrect. match self.inner { + Cell => "Cel ", ReservedFrz { conflicted: false } => "Res ", ReservedFrz { conflicted: true } => "ResC", ReservedIM => "ReIM", @@ -459,7 +504,7 @@ pub mod diagnostics { /// (Reserved < Active < Frozen < Disabled); /// - between `self` and `err` the permission should also be increasing, /// so all permissions inside `err` should be greater than `self.1`; - /// - `Active` and `Reserved(conflicted=false)` cannot cause an error + /// - `Active`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error /// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)` /// of either of them; /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected @@ -492,13 +537,14 @@ pub mod diagnostics { (ReservedFrz { conflicted: true } | Active | Frozen, Disabled) => false, (ReservedFrz { conflicted: true }, Frozen) => false, - // `Active` and `Reserved` have all permissions, so a + // `Active`, `Reserved`, and `Cell` have all permissions, so a // `ChildAccessForbidden(Reserved | Active)` can never exist. - (_, Active) | (_, ReservedFrz { conflicted: false }) => + (_, Active) | (_, ReservedFrz { conflicted: false }) | (_, Cell) => unreachable!("this permission cannot cause an error"), // No transition has `Reserved { conflicted: false }` or `ReservedIM` - // as its `.to` unless it's a noop. - (ReservedFrz { conflicted: false } | ReservedIM, _) => + // as its `.to` unless it's a noop. `Cell` cannot be in its `.to` + // because all child accesses are a noop. + (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), // All transitions produced in normal executions (using `apply_access`) // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`. @@ -544,16 +590,17 @@ pub mod diagnostics { "permission that results in Disabled should not itself be Disabled in the first place" ), // No transition has `Reserved { conflicted: false }` or `ReservedIM` as its `.to` - // unless it's a noop. - (ReservedFrz { conflicted: false } | ReservedIM, _) => + // unless it's a noop. `Cell` cannot be in its `.to` because all child + // accesses are a noop. + (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`, // so permissions found must be increasing in the order // `self.from < self.to <= forbidden.from < forbidden.to`. - (Disabled, ReservedFrz { .. } | ReservedIM | Active | Frozen) - | (Frozen, ReservedFrz { .. } | ReservedIM | Active) - | (Active, ReservedFrz { .. } | ReservedIM) => + (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) + | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Active) + | (Active, Cell | ReservedFrz { .. } | ReservedIM) => unreachable!("permissions between self and err must be increasing"), } } @@ -590,7 +637,7 @@ mod propagation_optimization_checks { impl Exhaustive for PermissionPriv { fn exhaustive() -> Box> { Box::new( - vec![Active, Frozen, Disabled, ReservedIM] + vec![Active, Frozen, Disabled, ReservedIM, Cell] .into_iter() .chain(::exhaustive().map(|conflicted| ReservedFrz { conflicted })), ) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 3389b1c602c3..47ccaadbb9e3 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -721,9 +721,14 @@ impl<'tcx> Tree { // visit all children, skipping none |_| ContinueTraversal::Recurse, |args: NodeAppArgs<'_>| -> Result<(), TransitionError> { - let NodeAppArgs { node, .. } = args; + let NodeAppArgs { node, perm, .. } = args; + let perm = + perm.get().copied().unwrap_or_else(|| node.default_location_state()); if global.borrow().protected_tags.get(&node.tag) == Some(&ProtectorKind::StrongProtector) + // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). + // Related to https://github.com/rust-lang/rust/issues/55005. + && !perm.permission().is_cell() { Err(TransitionError::ProtectedDealloc) } else { @@ -865,10 +870,9 @@ impl<'tcx> Tree { let idx = self.tag_mapping.get(&tag).unwrap(); // Only visit initialized permissions if let Some(p) = perms.get(idx) + && let Some(access_kind) = p.permission.protector_end_access() && p.initialized { - let access_kind = - if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read }; let access_cause = diagnostics::AccessCause::FnExit(access_kind); TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } .traverse_nonchildren( diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs index 7af1a7636fad..bf963f6a8f77 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs @@ -12,16 +12,16 @@ use std::cell::UnsafeCell; fn main() { unsafe { let n = &mut UnsafeCell::new(0u8); - name!(n.get(), "base"); + name!(n as *mut _, "base"); let x = &mut *(n as *mut UnsafeCell<_>); - name!(x.get(), "x"); - let y = (&mut *n).get(); + name!(x as *mut _, "x"); + let y = (&mut *n) as *mut UnsafeCell<_> as *mut _; name!(y); write_second(x, y); unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { let alloc_id = alloc_id!(x.get()); - name!(x.get(), "callee:x"); - name!(x.get()=>1, "caller:x"); + name!(x as *mut _, "callee:x"); + name!((x as *mut _)=>1, "caller:x"); name!(y, "callee:y"); name!(y, "caller:y"); print_state!(alloc_id); diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 03f79fe0a5d7..10414df6a6a2 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -21,7 +21,7 @@ LL | *y = 1; help: the accessed tag was created here --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | -LL | let y = (&mut *n).get(); +LL | let y = (&mut *n) as *mut UnsafeCell<_> as *mut _; | ^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs index 3269acb51193..019ea369811d 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs @@ -6,16 +6,16 @@ mod utils; use std::cell::UnsafeCell; -// UnsafeCells use the parent tag, so it is possible to use them with +// UnsafeCells use the `Cell` state, so it is possible to use them with // few restrictions when only among themselves. fn main() { unsafe { let data = &mut UnsafeCell::new(0u8); - name!(data.get(), "data"); + name!(data as *mut _, "data"); let x = &*data; - name!(x.get(), "x"); + name!(x as *const _, "x"); let y = &*data; - name!(y.get(), "y"); + name!(y as *const _, "y"); let alloc_id = alloc_id!(data.get()); print_state!(alloc_id); // y and x tolerate alternating Writes diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr index d13e9ad0215b..75a30c9a0837 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr +++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr @@ -2,11 +2,15 @@ Warning: this tree is indicative only. Some tags may have been hidden. 0.. 1 | Act | └─┬── -| ReIM| └──── +| ReIM| └─┬── +| Cel | ├──── +| Cel | └──── ────────────────────────────────────────────────── ────────────────────────────────────────────────── Warning: this tree is indicative only. Some tags may have been hidden. 0.. 1 | Act | └─┬── -| Act | └──── +| Act | └─┬── +| Cel | ├──── +| Cel | └──── ────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs index 752ae4b20c5d..58dab1ec5e52 100644 --- a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs @@ -102,7 +102,12 @@ fn unsafe_cell_invalidate() { let raw1 = &mut x as *mut _; let ref1 = unsafe { &mut *raw1 }; let raw2 = ref1 as *mut _; - // Now the borrow stack is: raw1, ref2, raw2. + // Now the borrow tree is: + // + // Act x + // Res `- raw1 + // Res `- ref1, raw2 + // // So using raw1 invalidates raw2. f(unsafe { mem::transmute(raw2) }, raw1); } @@ -139,7 +144,7 @@ fn refcell_basic() { } } -// Adding a Stacked Borrows protector for `Ref` would break this +// Adding a protector for `Ref` would break this fn ref_protector() { fn break_it(rc: &RefCell, r: Ref<'_, i32>) { // `r` has a shared reference, it is passed in as argument and hence diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs index f93cac8361e3..c57cd7fcf0ab 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs @@ -43,11 +43,11 @@ unsafe fn read_second(x: &mut T, y: *mut u8) { unsafe fn cell_protected_read() { print("[interior mut + protected] Foreign Read: Re* -> Frz"); let base = &mut UnsafeCell::new(0u8); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u8; name!(y); read_second(x, y); // Foreign Read for callee:x print_state!(alloc_id); @@ -57,11 +57,11 @@ unsafe fn cell_protected_read() { unsafe fn cell_unprotected_read() { print("[interior mut] Foreign Read: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell<_>); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); let _val = *y; // Foreign Read for x print_state!(alloc_id); @@ -72,11 +72,11 @@ unsafe fn cell_unprotected_read() { unsafe fn cell_unprotected_write() { print("[interior mut] Foreign Write: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); *y = 1; // Foreign Write for x print_state!(alloc_id); From 3e196c00c2374263d943b5e2226164d4c5f122db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 1 May 2025 11:41:42 +0200 Subject: [PATCH 116/302] remove a couple of clones --- .../hir-def/src/expr_store/lower/generics.rs | 2 +- .../crates/hir-expand/src/attrs.rs | 2 +- .../crates/hir-ty/src/dyn_compatibility.rs | 2 +- .../crates/hir-ty/src/infer/closure.rs | 2 +- .../crates/hir-ty/src/infer/expr.rs | 4 +-- .../crates/hir-ty/src/infer/pat.rs | 4 +-- .../crates/hir-ty/src/infer/unify.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 26 +++++--------- .../rust-analyzer/crates/hir/src/semantics.rs | 20 +++++------ .../crates/hir/src/semantics/source_to_def.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 2 +- .../src/handlers/convert_bool_then.rs | 2 +- .../src/handlers/convert_from_to_tryfrom.rs | 2 +- .../src/handlers/generate_function.rs | 6 ++-- .../src/handlers/wrap_unwrap_cfg_attr.rs | 6 ++-- .../ide-completion/src/context/analysis.rs | 6 +--- .../crates/ide-db/src/items_locator.rs | 4 +-- .../src/handlers/type_mismatch.rs | 2 +- .../rust-analyzer/crates/intern/src/symbol.rs | 34 +++++++++---------- .../crates/load-cargo/src/lib.rs | 2 +- .../crates/project-model/src/env.rs | 2 +- .../crates/project-model/src/workspace.rs | 2 +- .../crates/query-group-macro/src/lib.rs | 2 +- .../src/cli/unresolved_references.rs | 2 +- .../crates/rust-analyzer/src/config.rs | 2 +- .../crates/rust-analyzer/src/global_state.rs | 2 +- .../src/handlers/notification.rs | 2 +- .../rust-analyzer/src/handlers/request.rs | 2 +- .../rust-analyzer/tests/slow-tests/ratoml.rs | 7 ++-- .../rust-analyzer/tests/slow-tests/support.rs | 2 +- .../syntax/src/syntax_editor/edit_algo.rs | 2 +- .../crates/test-fixture/src/lib.rs | 2 +- 32 files changed, 71 insertions(+), 90 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index 42c85571f646..02a1d274fb5e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -270,7 +270,7 @@ impl GenericParamsCollector { let self_ = Name::new_symbol_root(sym::Self_); let idx = self.type_or_consts.alloc( TypeParamData { - name: Some(self_.clone()), + name: Some(self_), default: None, provenance: TypeParamProvenance::TraitSelf, } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 107316239809..bb17eb062760 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -320,7 +320,7 @@ impl Attr { ) -> impl IntoIterator { let is_cfg_attr = self.path.as_ident().is_some_and(|name| *name == sym::cfg_attr); if !is_cfg_attr { - return smallvec![self.clone()]; + return smallvec![self]; } let subtree = match self.token_tree_value() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index fecaafb4c2e8..106b996b13ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -515,7 +515,7 @@ fn receiver_is_dispatchable( trait_id: to_chalk_trait_id(trait_), substitution: Substitution::from_iter( Interner, - std::iter::once(unsized_self_ty.clone().cast(Interner)) + std::iter::once(unsized_self_ty.cast(Interner)) .chain(placeholder_subst.iter(Interner).skip(1).cloned()), ), }); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index cf3b15d2a679..800897c6fc3a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -127,7 +127,7 @@ impl InferenceContext<'_> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_closure = mem::replace(&mut self.current_closure, id); let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty.clone()); - let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty.clone())); + let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty)); let prev_resume_yield_tys = mem::replace(&mut self.resume_yield_tys, resume_yield_tys); self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 5468254ab910..8084b394d044 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -827,9 +827,9 @@ impl InferenceContext<'_> { } let assoc = self.resolve_ops_index_output(); self.resolve_associated_type_with_params( - self_ty.clone(), + self_ty, assoc, - &[index_ty.clone().cast(Interner)], + &[index_ty.cast(Interner)], ) } else { self.err_ty() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index dc1de3b9e851..a9a3265858e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -435,7 +435,7 @@ impl InferenceContext<'_> { decl: Option, ) -> Ty { let (expectation_type, expectation_lt) = match expected.as_reference() { - Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime.clone()), + Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime), None => { let inner_ty = self.table.new_type_var(); let inner_lt = self.table.new_lifetime_var(); @@ -597,7 +597,7 @@ impl InferenceContext<'_> { let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db)); let elem_ty = self.table.new_type_var(); - let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner); + let array_ty = TyKind::Array(elem_ty, size).intern(Interner); Some(array_ty) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index d921afeb9879..631b571465fe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -1029,7 +1029,7 @@ impl<'a> InferenceTable<'a> { }; let sized_pred = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(sized), - substitution: Substitution::from1(Interner, ty.clone()), + substitution: Substitution::from1(Interner, ty), }); let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); matches!(self.try_obligation(goal), Some(Solution::Unique(_))) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index d7754bf2e233..3f1d5bb01f2a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -3685,24 +3685,16 @@ impl GenericDef { } let source_map = match def { - GenericDefId::AdtId(AdtId::EnumId(it)) => { - db.enum_signature_with_source_map(it).1.clone() - } - GenericDefId::AdtId(AdtId::StructId(it)) => { - db.struct_signature_with_source_map(it).1.clone() - } - GenericDefId::AdtId(AdtId::UnionId(it)) => { - db.union_signature_with_source_map(it).1.clone() - } + GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::StructId(it)) => db.struct_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::UnionId(it)) => db.union_signature_with_source_map(it).1, GenericDefId::ConstId(_) => return, - GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1.clone(), - GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1.clone(), + GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1, + GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1, GenericDefId::StaticId(_) => return, - GenericDefId::TraitAliasId(it) => { - db.trait_alias_signature_with_source_map(it).1.clone() - } - GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1.clone(), - GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1.clone(), + GenericDefId::TraitAliasId(it) => db.trait_alias_signature_with_source_map(it).1, + GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1, + GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1, }; expr_store_diagnostics(db, acc, &source_map); @@ -3802,7 +3794,7 @@ impl GenericSubstitution { container_params .chain(self_params) .filter_map(|(ty, name)| { - Some((name?.symbol().clone(), Type { ty: ty.clone(), env: self.env.clone() })) + Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) }) .collect() } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 2e693559e292..4d092c1f0bb0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -926,7 +926,7 @@ impl<'db> SemanticsImpl<'db> { token: InRealFile, mut cb: impl FnMut(InFile, SyntaxContext) -> ControlFlow, ) -> Option { - self.descend_into_macros_impl(token.clone(), &mut cb) + self.descend_into_macros_impl(token, &mut cb) } /// Descends the token into expansions, returning the tokens that matches the input @@ -958,17 +958,13 @@ impl<'db> SemanticsImpl<'db> { let text = token.text(); let kind = token.kind(); if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_breakable( - token.clone(), - |InFile { value, file_id: _ }, _ctx| { - let mapped_kind = value.kind(); - let any_ident_match = - || kind.is_any_identifier() && value.kind().is_any_identifier(); - let matches = - (kind == mapped_kind || any_ident_match()) && text == value.text(); - if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } - }, - ) + self.descend_into_macros_breakable(token, |InFile { value, file_id: _ }, _ctx| { + let mapped_kind = value.kind(); + let any_ident_match = + || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); + if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } + }) } else { None } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 466bf7f6c826..587c51d8cc99 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -559,7 +559,7 @@ impl SourceToDefCtx<'_, '_> { let item = match ast::Item::cast(value.clone()) { Some(it) => it, None => { - let variant = ast::Variant::cast(value.clone())?; + let variant = ast::Variant::cast(value)?; return this .enum_variant_to_def(InFile::new(file_id, &variant)) .map(Into::into); diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 7d447116e088..c1a75ce7e574 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1431,7 +1431,7 @@ impl SourceAnalyzer { } fn ty_of_expr(&self, expr: ast::Expr) -> Option<&Ty> { - self.infer()?.type_of_expr_or_pat(self.expr_id(expr.clone())?) + self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?) } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index cd23ad223729..bcd06c1ef725 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -196,7 +196,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> // Wrap all tails in `Some(...)` let none_path = mapless_make.expr_path(mapless_make.ident_path("None")); let some_path = mapless_make.expr_path(mapless_make.ident_path("Some")); - for_each_tail_expr(&ast::Expr::BlockExpr(closure_body.clone()), &mut |e| { + for_each_tail_expr(&ast::Expr::BlockExpr(closure_body), &mut |e| { let e = match e { ast::Expr::BreakExpr(e) => e.expr(), ast::Expr::ReturnExpr(e) => e.expr(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 24cc32d10d88..db41927f1df2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -80,7 +80,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> let from_fn_name = builder.make_mut(from_fn_name); let tail_expr = builder.make_mut(tail_expr); let return_exprs = return_exprs.map(|r| builder.make_mut(r)).collect_vec(); - let associated_items = builder.make_mut(associated_items).clone(); + let associated_items = builder.make_mut(associated_items); ted::replace( trait_ty.syntax(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index ba2b84a42c75..aac145a72150 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -392,14 +392,14 @@ impl FunctionBuilder { // Focus the return type if there is one match ret_type { Some(ret_type) => { - edit.add_placeholder_snippet(cap, ret_type.clone()); + edit.add_placeholder_snippet(cap, ret_type); } None => { - edit.add_placeholder_snippet(cap, tail_expr.clone()); + edit.add_placeholder_snippet(cap, tail_expr); } } } else { - edit.add_placeholder_snippet(cap, tail_expr.clone()); + edit.add_placeholder_snippet(cap, tail_expr); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs index 1068d5d4cd57..e1b94673e775 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs @@ -116,7 +116,7 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - (Some(attr), Some(ident)) if attr.simple_name().map(|v| v.eq("derive")).unwrap_or_default() => { - Some(attempt_get_derive(attr.clone(), ident)) + Some(attempt_get_derive(attr, ident)) } (Some(attr), _) => Some(WrapUnwrapOption::WrapAttr(attr)), @@ -128,7 +128,7 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - NodeOrToken::Node(node) => ast::Attr::cast(node).map(WrapUnwrapOption::WrapAttr), NodeOrToken::Token(ident) if ident.kind() == syntax::T![ident] => { let attr = ident.parent_ancestors().find_map(ast::Attr::cast)?; - Some(attempt_get_derive(attr.clone(), ident)) + Some(attempt_get_derive(attr, ident)) } _ => None, } @@ -233,7 +233,7 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) -> if let Some(meta) = attr.meta() { if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) { raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" "))); - raw_tokens.push(NodeOrToken::Token(eq.clone())); + raw_tokens.push(NodeOrToken::Token(eq)); raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" "))); expr.syntax().descendants_with_tokens().for_each(|it| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 822dae2578e7..391e2379dcd5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -387,11 +387,7 @@ fn expand( match ( sema.expand_macro_call(&actual_macro_call), - sema.speculative_expand_macro_call( - &actual_macro_call, - &speculative_args, - fake_ident_token.clone(), - ), + sema.speculative_expand_macro_call(&actual_macro_call, &speculative_args, fake_ident_token), ) { // successful expansions (Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs index e9385253250a..4b0a84a559e2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs @@ -86,7 +86,7 @@ pub fn items_with_name_in_module( let local_query = match name { NameToImport::Prefix(exact_name, case_sensitive) | NameToImport::Exact(exact_name, case_sensitive) => { - let mut local_query = symbol_index::Query::new(exact_name.clone()); + let mut local_query = symbol_index::Query::new(exact_name); local_query.assoc_search_mode(assoc_item_search); if prefix { local_query.prefix(); @@ -99,7 +99,7 @@ pub fn items_with_name_in_module( local_query } NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => { - let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); + let mut local_query = symbol_index::Query::new(fuzzy_search_string); local_query.fuzzy(); local_query.assoc_search_mode(assoc_item_search); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 8f6ed1a7bdbd..1db9b6d04944 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -195,7 +195,7 @@ fn remove_unnecessary_wrapper( let db = ctx.sema.db; let root = db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); - let expr = ctx.sema.original_ast_node(expr.clone())?; + let expr = ctx.sema.original_ast_node(expr)?; let Expr::CallExpr(call_expr) = expr else { return None; diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 89c3be96fcb9..8b2d6e8717d2 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -163,28 +163,28 @@ impl Symbol { pub fn integer(i: usize) -> Self { match i { - 0 => symbols::INTEGER_0.clone(), - 1 => symbols::INTEGER_1.clone(), - 2 => symbols::INTEGER_2.clone(), - 3 => symbols::INTEGER_3.clone(), - 4 => symbols::INTEGER_4.clone(), - 5 => symbols::INTEGER_5.clone(), - 6 => symbols::INTEGER_6.clone(), - 7 => symbols::INTEGER_7.clone(), - 8 => symbols::INTEGER_8.clone(), - 9 => symbols::INTEGER_9.clone(), - 10 => symbols::INTEGER_10.clone(), - 11 => symbols::INTEGER_11.clone(), - 12 => symbols::INTEGER_12.clone(), - 13 => symbols::INTEGER_13.clone(), - 14 => symbols::INTEGER_14.clone(), - 15 => symbols::INTEGER_15.clone(), + 0 => symbols::INTEGER_0, + 1 => symbols::INTEGER_1, + 2 => symbols::INTEGER_2, + 3 => symbols::INTEGER_3, + 4 => symbols::INTEGER_4, + 5 => symbols::INTEGER_5, + 6 => symbols::INTEGER_6, + 7 => symbols::INTEGER_7, + 8 => symbols::INTEGER_8, + 9 => symbols::INTEGER_9, + 10 => symbols::INTEGER_10, + 11 => symbols::INTEGER_11, + 12 => symbols::INTEGER_12, + 13 => symbols::INTEGER_13, + 14 => symbols::INTEGER_14, + 15 => symbols::INTEGER_15, i => Symbol::intern(&format!("{i}")), } } pub fn empty() -> Self { - symbols::__empty.clone() + symbols::__empty } #[inline] diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 3e52dbaea654..2686a75c7c86 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -292,7 +292,7 @@ impl ProjectFolders { }; let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())]; - let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]); + let entry = vfs::loader::Entry::Files(vec![ratoml_path]); res.watch.push(res.load.len()); res.load.push(entry); diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs index f2e5df171ae3..e7293b0b2ef6 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/env.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs @@ -25,7 +25,7 @@ pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) { env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string()); env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string()); - env.set("CARGO_PKG_AUTHORS", package.authors.join(":").clone()); + env.set("CARGO_PKG_AUTHORS", package.authors.join(":")); env.set("CARGO_PKG_NAME", package.name.clone()); env.set("CARGO_PKG_DESCRIPTION", package.description.as_deref().unwrap_or_default()); diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index c6e0cf36aff2..eec0077ea6e2 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -1370,7 +1370,7 @@ fn detached_file_to_crate_graph( Edition::CURRENT, display_name.clone(), None, - cfg_options.clone(), + cfg_options, None, Env::default(), CrateOrigin::Local { diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index 357e56ddfaa0..ec4b6b2a4ac3 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -210,7 +210,7 @@ pub(crate) fn query_group_impl( .into_iter() .filter(|fn_arg| matches!(fn_arg, FnArg::Typed(_))) .map(|fn_arg| match fn_arg { - FnArg::Typed(pat_type) => pat_type.clone(), + FnArg::Typed(pat_type) => pat_type, FnArg::Receiver(_) => unreachable!("this should have been filtered out"), }) .collect::>(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs index 1d4fbb942235..0362e13b88b7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -30,7 +30,7 @@ impl flags::UnresolvedReferences { let root = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize(); let config = crate::config::Config::new( - root.clone(), + root, lsp_types::ClientCapabilities::default(), vec![], None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 9acbcc08a9dd..03e5b1f6f4b6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1183,7 +1183,7 @@ impl ConfigChange { source_root_map: Arc>, ) { assert!(self.source_map_change.is_none()); - self.source_map_change = Some(source_root_map.clone()); + self.source_map_change = Some(source_root_map); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 820276e8aea2..3b3b9c879754 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -511,7 +511,7 @@ impl GlobalState { self.fetch_workspaces_queue.request_op( format!("workspace vfs file change: {path}"), - FetchWorkspaceRequest { path: Some(path.to_owned()), force_crate_graph_reload }, + FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload }, ); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index a30e5d8ce268..b7373f274f05 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -309,7 +309,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let task = move || -> std::result::Result<(), Cancelled> { if invocation_strategy_once { let saved_file = vfs_path.as_path().map(|p| p.to_owned()); - world.flycheck[0].restart_workspace(saved_file.clone()); + world.flycheck[0].restart_workspace(saved_file); } let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index e08dd80973a7..69983a676261 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -2210,7 +2210,7 @@ fn runnable_action_links( let label = update_test.label(); if let Some(r) = to_proto::make_update_runnable(&r, update_test) { let update_command = to_proto::command::run_single(&r, label.unwrap().as_str()); - group.commands.push(to_command_link(update_command, r.label.clone())); + group.commands.push(to_command_link(update_command, r.label)); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs index 3f313b7e57fe..485f32281dde 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs @@ -82,11 +82,8 @@ impl RatomlTest { } Url::parse( - format!( - "file://{}", - path.into_string().to_owned().replace("C:\\", "/c:/").replace('\\', "/") - ) - .as_str(), + format!("file://{}", path.into_string().replace("C:\\", "/c:/").replace('\\', "/")) + .as_str(), ) .unwrap() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 7b5a53311217..2bebb0c1b970 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -202,7 +202,7 @@ impl Project<'_> { } let mut config = Config::new( - tmp_dir_path.clone(), + tmp_dir_path, lsp_types::ClientCapabilities { workspace: Some(lsp_types::WorkspaceClientCapabilities { did_change_watched_files: Some( diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index 6a9c88b55d7e..01c1f0d49bfd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -391,7 +391,7 @@ fn report_intersecting_changes( fn to_owning_node(element: &SyntaxElement) -> SyntaxNode { match element { SyntaxElement::Node(node) => node.clone(), - SyntaxElement::Token(token) => token.parent().unwrap().clone(), + SyntaxElement::Token(token) => token.parent().unwrap(), } } diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 2f379d419e8f..f6ca5ab6c8c5 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -353,7 +353,7 @@ impl ChangeFixture { )]), CrateOrigin::Local { repo: None, name: None }, true, - proc_macro_cwd.clone(), + proc_macro_cwd, crate_ws_data, ); proc_macros.insert(proc_macros_crate, Ok(proc_macro)); From 3e969d433d5c4f7001e14dba1c9a00a591937a4f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 May 2025 11:53:24 +0200 Subject: [PATCH 117/302] Move core::fmt::Arguments::new_v1* to rt.rs. --- library/core/src/fmt/mod.rs | 35 ----------------------------- library/core/src/fmt/rt.rs | 45 ++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 580f95eddce7..4f7f8a5b84dd 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -622,44 +622,9 @@ pub struct Arguments<'a> { args: &'a [rt::Argument<'a>], } -/// Used by the format_args!() macro to create a fmt::Arguments object. #[doc(hidden)] #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { - #[inline] - pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { - const { assert!(N <= 1) }; - Arguments { pieces, fmt: None, args: &[] } - } - - /// When using the format_args!() macro, this function is used to generate the - /// Arguments structure. - #[inline] - pub const fn new_v1( - pieces: &'a [&'static str; P], - args: &'a [rt::Argument<'a>; A], - ) -> Arguments<'a> { - const { assert!(P >= A && P <= A + 1, "invalid args") } - Arguments { pieces, fmt: None, args } - } - - /// Specifies nonstandard formatting parameters. - /// - /// An `rt::UnsafeArg` is required because the following invariants must be held - /// in order for this function to be safe: - /// 1. The `pieces` slice must be at least as long as `fmt`. - /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. - /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. - #[inline] - pub const fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - /// Estimates the length of the formatted text. /// /// This is intended to be used for setting initial `String` capacity diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index e409771362e4..ec5015e06d2c 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -1,7 +1,10 @@ #![allow(missing_debug_implementations)] #![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -//! These are the lang items used by format_args!(). +//! All types and methods in this file are used by the compiler in +//! the expansion/lowering of format_args!(). +//! +//! Do not modify them without understanding the consequences for the format_args!() macro. use super::*; use crate::hint::unreachable_unchecked; @@ -229,3 +232,43 @@ impl UnsafeArg { Self { _private: () } } } + +/// Used by the format_args!() macro to create a fmt::Arguments object. +#[doc(hidden)] +#[unstable(feature = "fmt_internals", issue = "none")] +#[rustc_diagnostic_item = "FmtArgumentsNew"] +impl<'a> Arguments<'a> { + #[inline] + pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { + const { assert!(N <= 1) }; + Arguments { pieces, fmt: None, args: &[] } + } + + /// When using the format_args!() macro, this function is used to generate the + /// Arguments structure. + #[inline] + pub const fn new_v1( + pieces: &'a [&'static str; P], + args: &'a [rt::Argument<'a>; A], + ) -> Arguments<'a> { + const { assert!(P >= A && P <= A + 1, "invalid args") } + Arguments { pieces, fmt: None, args } + } + + /// Specifies nonstandard formatting parameters. + /// + /// An `rt::UnsafeArg` is required because the following invariants must be held + /// in order for this function to be safe: + /// 1. The `pieces` slice must be at least as long as `fmt`. + /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. + /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. + #[inline] + pub const fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + _unsafe_arg: rt::UnsafeArg, + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } +} From 36c6633b0fb422e35f78de6fb9f0df77d1f4ba23 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 May 2025 11:53:51 +0200 Subject: [PATCH 118/302] Clean up "const" situation in format_args!(). Rather than marking the Argument::new_display etc. functions as non-const, this marks the Arguments::new_v1 functions as non-const. --- .../rustc_const_eval/src/check_consts/ops.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/fmt/rt.rs | 48 +++++++++++-------- tests/ui/consts/const-eval/format.stderr | 8 ++-- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 7756e51c4c5f..1e5b98675c4f 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -352,7 +352,7 @@ fn build_error_for_const_call<'tcx>( ); err } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { + _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => { ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ba3e6d7ca826..7a1fb36324bf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -174,7 +174,6 @@ symbols! { Arc, ArcWeak, Argument, - ArgumentMethods, ArrayIntoIter, AsMut, AsRef, @@ -249,6 +248,7 @@ symbols! { Error, File, FileType, + FmtArgumentsNew, Fn, FnMut, FnOnce, diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index ec5015e06d2c..c2a8a39bcac8 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -113,46 +113,45 @@ macro_rules! argument_new { }; } -#[rustc_diagnostic_item = "ArgumentMethods"] impl Argument<'_> { #[inline] - pub fn new_display(x: &T) -> Argument<'_> { + pub const fn new_display(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_debug(x: &T) -> Argument<'_> { + pub const fn new_debug(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_debug_noop(x: &T) -> Argument<'_> { + pub const fn new_debug_noop(x: &T) -> Argument<'_> { argument_new!(T, x, |_: &T, _| Ok(())) } #[inline] - pub fn new_octal(x: &T) -> Argument<'_> { + pub const fn new_octal(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_lower_hex(x: &T) -> Argument<'_> { + pub const fn new_lower_hex(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_upper_hex(x: &T) -> Argument<'_> { + pub const fn new_upper_hex(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_pointer(x: &T) -> Argument<'_> { + pub const fn new_pointer(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_binary(x: &T) -> Argument<'_> { + pub const fn new_binary(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_lower_exp(x: &T) -> Argument<'_> { + pub const fn new_lower_exp(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_upper_exp(x: &T) -> Argument<'_> { + pub const fn new_upper_exp(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] @@ -203,15 +202,8 @@ impl Argument<'_> { /// let f = format_args!("{}", "a"); /// println!("{f}"); /// ``` - /// - /// This function should _not_ be const, to make sure we don't accept - /// format_args!() and panic!() with arguments in const, even when not evaluated: - /// - /// ```compile_fail,E0015 - /// const _: () = if false { panic!("a {}", "a") }; - /// ``` #[inline] - pub fn none() -> [Self; 0] { + pub const fn none() -> [Self; 0] { [] } } @@ -246,8 +238,15 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. + /// + /// This function should _not_ be const, to make sure we don't accept + /// format_args!() and panic!() with arguments in const, even when not evaluated: + /// + /// ```compile_fail,E0015 + /// const _: () = if false { panic!("a {}", "a") }; + /// ``` #[inline] - pub const fn new_v1( + pub fn new_v1( pieces: &'a [&'static str; P], args: &'a [rt::Argument<'a>; A], ) -> Arguments<'a> { @@ -262,8 +261,15 @@ impl<'a> Arguments<'a> { /// 1. The `pieces` slice must be at least as long as `fmt`. /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. + /// + /// This function should _not_ be const, to make sure we don't accept + /// format_args!() and panic!() with arguments in const, even when not evaluated: + /// + /// ```compile_fail,E0015 + /// const _: () = if false { panic!("a {:1}", "a") }; + /// ``` #[inline] - pub const fn new_v1_formatted( + pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], fmt: &'a [rt::Placeholder], diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 4c4cbb372a7f..2f202705b7f9 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -1,16 +1,16 @@ error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:2:13 + --> $DIR/format.rs:2:5 | LL | panic!("{:?}", 0); - | ^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:7:15 + --> $DIR/format.rs:7:5 | LL | println!("{:?}", 0); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) From 714ea10ea41e97310a1b3d90fed4cfb3e2dd6b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 29 Apr 2025 02:11:41 +0200 Subject: [PATCH 119/302] rustdoc: Fix doctest heuristic for main fn wrapping --- src/librustdoc/doctest/make.rs | 67 ++++++++----------- tests/rustdoc-ui/doctest/auxiliary/items.rs | 1 + .../doctest/auxiliary/macro-after-main.rs | 1 - tests/rustdoc-ui/doctest/macro-after-main.rs | 16 ----- .../doctest/macro-after-main.stdout | 6 -- .../main-alongside-macro-calls.fail.stdout | 60 +++++++++++++++++ .../main-alongside-macro-calls.pass.stdout | 9 +++ .../doctest/main-alongside-macro-calls.rs | 44 ++++++++++++ .../doctest/main-alongside-stmts.rs | 33 +++++++++ .../doctest/main-alongside-stmts.stdout | 7 ++ .../doctest/test-main-alongside-exprs.rs | 22 ------ .../doctest/test-main-alongside-exprs.stdout | 6 -- 12 files changed, 183 insertions(+), 89 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/auxiliary/items.rs delete mode 100644 tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs delete mode 100644 tests/rustdoc-ui/doctest/macro-after-main.rs delete mode 100644 tests/rustdoc-ui/doctest/macro-after-main.stdout create mode 100644 tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout create mode 100644 tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout create mode 100644 tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs create mode 100644 tests/rustdoc-ui/doctest/main-alongside-stmts.rs create mode 100644 tests/rustdoc-ui/doctest/main-alongside-stmts.stdout delete mode 100644 tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs delete mode 100644 tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 4194abc8d574..d4fbfb12582e 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -301,8 +301,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result) -> Result) -> bool { let mut is_extern_crate = false; if !info.has_global_allocator @@ -351,8 +347,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - // We only push if it's the top item because otherwise, we would duplicate - // its content since the top-level item was already added. if fn_item.ident.name == sym::main { info.has_main_fn = true; } @@ -412,7 +406,32 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - is_extern_crate = check_item(&item, &mut info, crate_name); + is_extern_crate = check_item(item, &mut info, crate_name); + } + // We assume that the macro calls will expand to item(s) even though they could + // expand to statements and expressions. + StmtKind::MacCall(ref mac_call) => { + if !info.has_main_fn { + // For backward compatibility, we look for the token sequence `fn main(…)` + // in the macro input (!) to crudely detect main functions "masked by a + // wrapper macro". For the record, this is a horrible heuristic! + // See . + let mut iter = mac_call.mac.args.tokens.iter(); + while let Some(token) = iter.next() { + if let TokenTree::Token(token, _) = token + && let TokenKind::Ident(kw::Fn, _) = token.kind + && let Some(TokenTree::Token(ident, _)) = iter.peek() + && let TokenKind::Ident(sym::main, _) = ident.kind + && let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, _)) = { + iter.next(); + iter.peek() + } + { + info.has_main_fn = true; + break; + } + } + } } StmtKind::Expr(ref expr) => { if matches!(expr.kind, ast::ExprKind::Err(_)) { @@ -421,35 +440,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - if info.has_main_fn { - continue; - } - let mut iter = mac_call.mac.args.tokens.iter(); - - while let Some(token) = iter.next() { - if let TokenTree::Token(token, _) = token - && let TokenKind::Ident(name, _) = token.kind - && name == kw::Fn - && let Some(TokenTree::Token(fn_token, _)) = iter.peek() - && let TokenKind::Ident(fn_name, _) = fn_token.kind - && fn_name == sym::main - && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = { - iter.next(); - iter.peek() - } - { - info.has_main_fn = true; - break; - } - } - } - _ => { - has_non_items = true; - } + StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty => has_non_items = true, } // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to diff --git a/tests/rustdoc-ui/doctest/auxiliary/items.rs b/tests/rustdoc-ui/doctest/auxiliary/items.rs new file mode 100644 index 000000000000..40d4eb261e5a --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/items.rs @@ -0,0 +1 @@ +fn item() {} diff --git a/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs b/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs deleted file mode 100644 index ed7584b74253..000000000000 --- a/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs +++ /dev/null @@ -1 +0,0 @@ -use std::string::String; diff --git a/tests/rustdoc-ui/doctest/macro-after-main.rs b/tests/rustdoc-ui/doctest/macro-after-main.rs deleted file mode 100644 index 0a42343f1c27..000000000000 --- a/tests/rustdoc-ui/doctest/macro-after-main.rs +++ /dev/null @@ -1,16 +0,0 @@ -// This test checks a corner case where the macro calls used to be skipped, -// making them considered as statement, and therefore some cases where -// `include!` macro was then put into a function body, making the doctest -// compilation fail. - -//@ compile-flags:--test -//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" -//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ check-pass - -//! ``` -//! include!("./auxiliary/macro-after-main.rs"); -//! -//! fn main() {} -//! eprintln!(); -//! ``` diff --git a/tests/rustdoc-ui/doctest/macro-after-main.stdout b/tests/rustdoc-ui/doctest/macro-after-main.stdout deleted file mode 100644 index 72ffe2b5a27c..000000000000 --- a/tests/rustdoc-ui/doctest/macro-after-main.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/macro-after-main.rs - (line 11) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout new file mode 100644 index 000000000000..65989a8ef47c --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout @@ -0,0 +1,60 @@ + +running 4 tests +test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 28) ... FAILED +test $DIR/main-alongside-macro-calls.rs - (line 33) ... FAILED + +failures: + +---- $DIR/main-alongside-macro-calls.rs - (line 28) stdout ---- +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/main-alongside-macro-calls.rs:30:1 + | +LL | println!(); + | ^^^^^^^^^^ + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: macro expansion ignores `{` and any tokens following + --> $SRC_DIR/std/src/macros.rs:LL:COL + | + ::: $DIR/main-alongside-macro-calls.rs:30:1 + | +LL | println!(); + | ---------- caused by the macro expansion here + | + = note: the usage of `print!` is likely invalid in item context + +error: aborting due to 2 previous errors + +Couldn't compile the test. +---- $DIR/main-alongside-macro-calls.rs - (line 33) stdout ---- +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/main-alongside-macro-calls.rs:34:1 + | +LL | println!(); + | ^^^^^^^^^^ + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: macro expansion ignores `{` and any tokens following + --> $SRC_DIR/std/src/macros.rs:LL:COL + | + ::: $DIR/main-alongside-macro-calls.rs:34:1 + | +LL | println!(); + | ---------- caused by the macro expansion here + | + = note: the usage of `print!` is likely invalid in item context + +error: aborting due to 2 previous errors + +Couldn't compile the test. + +failures: + $DIR/main-alongside-macro-calls.rs - (line 28) + $DIR/main-alongside-macro-calls.rs - (line 33) + +test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout new file mode 100644 index 000000000000..93a4bbd87368 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout @@ -0,0 +1,9 @@ + +running 4 tests +test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 28) - compile fail ... ok +test $DIR/main-alongside-macro-calls.rs - (line 33) - compile fail ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs new file mode 100644 index 000000000000..b455d8b0cc35 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs @@ -0,0 +1,44 @@ +// This test ensures that if there is are any macro calls alongside a `main` function, +// it will indeed consider the `main` function as the program entry point and *won't* +// generate its own `main` function to wrap everything even though macro calls are +// valid in statement contexts, too, and could just as well expand to statements or +// expressions (we don't perform any macro expansion to find `main`, see also +// ). +// +// See <./main-alongside-stmts.rs> for comparison. +// +//@ compile-flags:--test --test-args --test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ revisions: pass fail +//@[pass] check-pass +//@[fail] failure-status: 101 + +// Regression test for : + +//! ``` +//! fn main() {} +//! include!("./auxiliary/items.rs"); +//! ``` +//! +//! ``` +//! include!("./auxiliary/items.rs"); +//! fn main() {} +//! ``` + +// Regression test for : +// We test the "same" thing twice: Once via `compile_fail` to more closely mirror the reported +// regression and once without it to make sure that it leads to the expected rustc errors, +// namely `println!(…)` not being valid in item contexts. + +#![cfg_attr(pass, doc = " ```compile_fail")] +#![cfg_attr(fail, doc = " ```")] +//! fn main() {} +//! println!(); +//! ``` +//! +#![cfg_attr(pass, doc = " ```compile_fail")] +#![cfg_attr(fail, doc = " ```")] +//! println!(); +//! fn main() {} +//! ``` diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.rs b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs new file mode 100644 index 000000000000..5965f928cdd1 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs @@ -0,0 +1,33 @@ +// This test ensures that if there is are any statements alongside a `main` function, +// it will not consider the `main` function as the program entry point but instead +// will generate its own `main` function to wrap everything as it needs to reside in a +// module where only *items* are permitted syntactically. +// +// See <./main-alongside-macro-calls.rs> for comparison. +// +// This is a regression test for: +// * +// * +// +//@ compile-flags:--test --test-args --test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +//! ``` +//! # if cfg!(miri) { return; } +//! use std::ops::Deref; +//! +//! fn main() { +//! assert!(false); +//! } +//! ``` +//! +//! ``` +//! let x = 2; +//! assert_eq!(x, 2); +//! +//! fn main() { +//! assert!(false); +//! } +//! ``` diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout new file mode 100644 index 000000000000..9b9a3fe8a68f --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/main-alongside-stmts.rs - (line 17) ... ok +test $DIR/main-alongside-stmts.rs - (line 26) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs deleted file mode 100644 index ee2299c0fd87..000000000000 --- a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs +++ /dev/null @@ -1,22 +0,0 @@ -// This test ensures that if there is an expression alongside a `main` -// function, it will not consider the entire code to be part of the `main` -// function and will generate its own function to wrap everything. -// -// This is a regression test for: -// * -// * -//@ compile-flags:--test -//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" -//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ check-pass - -#![crate_name = "foo"] - -//! ``` -//! # if cfg!(miri) { return; } -//! use std::ops::Deref; -//! -//! fn main() { -//! println!("Hi!"); -//! } -//! ``` diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout deleted file mode 100644 index 90d7c3546bf1..000000000000 --- a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/test-main-alongside-exprs.rs - (line 15) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - From ce50b4fd9d3b75976520486e4ff6888c22ba89d7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 May 2025 12:29:43 +0200 Subject: [PATCH 120/302] Bless mir opt tests. --- .../sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index a1df868cde05..33f1ad9bef4e 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -121,7 +121,7 @@ StorageDead(_18); _16 = &_17; _15 = &(*_16); - _11 = Arguments::<'_>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; + _11 = core::fmt::rt::>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; } bb5: { From 86c6e7911d2ccf69f8306f5bfb10233025dc8e22 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 May 2025 12:31:44 +0200 Subject: [PATCH 121/302] Bless pretty tests. --- tests/pretty/issue-4264.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 3cff6ca33dab..eb808f7122a9 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -34,7 +34,7 @@ fn bar() ({ ((::alloc::fmt::format as for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const as - fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test" + fn(&[&'static str; 1]) -> Arguments<'_> {core::fmt::rt::>::new_const::<1>})((&([("test" as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>)) as String) } as String)) as String); From 60218be5e997a9d6ced4857cc13cd9441d5c3e40 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Thu, 1 May 2025 07:40:43 -0400 Subject: [PATCH 122/302] Remove backtrace dep from anyhow in features status dump tool According to `anyhow`'s Cargo.toml: > On compilers older than 1.65, features=["backtrace"] may be used to enable > backtraces via the `backtrace` crate. This feature has no effect on 1.65+ > besides bringing in an unused dependency, as `std::backtrace` is always > preferred. So this is just bringing in an unused dependency. --- Cargo.lock | 3 --- src/tools/features-status-dump/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60daa453c60d..b06119bc0920 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,9 +161,6 @@ name = "anyhow" version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -dependencies = [ - "backtrace", -] [[package]] name = "ar_archive_writer" diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml index 35be71a46e55..b2976f14a01a 100644 --- a/src/tools/features-status-dump/Cargo.toml +++ b/src/tools/features-status-dump/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -anyhow = { version = "1", features = ["backtrace"] } +anyhow = { version = "1" } clap = { version = "4", features = ["derive"] } serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" From bfe3d54d817cd66e4ab85d94409db8a572fdadd7 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 13:11:53 +0100 Subject: [PATCH 123/302] User type annotations for free consts in pattern position --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 3 +-- .../user_type_annotations_pattern.rs | 14 ++++++++++++++ .../user_type_annotations_pattern.stderr | 11 +++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/ui/generic-const-items/user_type_annotations_pattern.rs create mode 100644 tests/ui/generic-const-items/user_type_annotations_pattern.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8e69ff568b92..4f00a85004d0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -553,8 +553,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let res = self.typeck_results.qpath_res(qpath, id); let (def_id, user_ty) = match res { - Res::Def(DefKind::Const, def_id) => (def_id, None), - Res::Def(DefKind::AssocConst, def_id) => { + Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { (def_id, self.typeck_results.user_provided_types().get(id)) } diff --git a/tests/ui/generic-const-items/user_type_annotations_pattern.rs b/tests/ui/generic-const-items/user_type_annotations_pattern.rs new file mode 100644 index 000000000000..aa3846df2bca --- /dev/null +++ b/tests/ui/generic-const-items/user_type_annotations_pattern.rs @@ -0,0 +1,14 @@ +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +const FOO<'a: 'static>: usize = 10; + +fn bar<'a>() { + match 10_usize { + FOO::<'a> => todo!(), + //~^ ERROR: lifetime may not live long enough + _ => todo!(), + } +} + +fn main() {} diff --git a/tests/ui/generic-const-items/user_type_annotations_pattern.stderr b/tests/ui/generic-const-items/user_type_annotations_pattern.stderr new file mode 100644 index 000000000000..e15be275d297 --- /dev/null +++ b/tests/ui/generic-const-items/user_type_annotations_pattern.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/user_type_annotations_pattern.rs:8:9 + | +LL | fn bar<'a>() { + | -- lifetime `'a` defined here +LL | match 10_usize { +LL | FOO::<'a> => todo!(), + | ^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + From 72b110ada38d0ebf9faf2538b9069f3b878e5625 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 1 May 2025 13:48:11 +0100 Subject: [PATCH 124/302] Stabilize `select_unpredictable` FCP completed in tracking issue #133962. --- library/core/src/hint.rs | 4 +--- library/coretests/tests/lib.rs | 1 - tests/codegen/intrinsics/select_unpredictable.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 1ca23ab6eea6..394a3ea67783 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -763,8 +763,6 @@ pub const fn cold_path() { /// /// Distribute values evenly between two buckets: /// ``` -/// #![feature(select_unpredictable)] -/// /// use std::hash::BuildHasher; /// use std::hint; /// @@ -780,7 +778,7 @@ pub const fn cold_path() { /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); /// ``` #[inline(always)] -#[unstable(feature = "select_unpredictable", issue = "133962")] +#[stable(feature = "select_unpredictable", since = "CURRENT_RUSTC_VERSION")] pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): // Change this to use ManuallyDrop instead. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ef548971aafa..f52e338a0850 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -68,7 +68,6 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] -#![feature(select_unpredictable)] #![feature(slice_from_ptr_range)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs index 2db4ae174b33..ad7120c6fb8b 100644 --- a/tests/codegen/intrinsics/select_unpredictable.rs +++ b/tests/codegen/intrinsics/select_unpredictable.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled #![feature(core_intrinsics)] -#![feature(select_unpredictable)] #![crate_type = "lib"] /* Test the intrinsic */ From 53e3907bcb5a4519a6558051476c3198aba2a12c Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 14:29:10 +0100 Subject: [PATCH 125/302] No-op split into sub functions --- .../src/traits/normalize.rs | 326 +++++++++--------- 1 file changed, 162 insertions(+), 164 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 5f0acd46f86a..e08428f925c9 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -10,8 +10,8 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, - TypingMode, + self, AliasTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, + TypeVisitableExt, TypingMode, }; use tracing::{debug, instrument}; @@ -178,6 +178,163 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) } } + + fn normalize_trait_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { + if !data.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + let data = data.fold_with(self); + let normalized_ty = project::normalize_projection_ty( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty.expect_type() + } else { + // If there are escaping bound vars, we temporarily replace the + // bound vars with placeholders. Note though, that in the case + // that we still can't project for whatever reason (e.g. self + // type isn't known enough), we *can't* register an obligation + // and return an inference variable (since then that obligation + // would have bound vars and that's a can of worms). Instead, + // we just give up and fall back to pretending like we never tried! + // + // Note: this isn't necessarily the final approach here; we may + // want to figure out how to register obligations with escaping vars + // or handle this some other way. + + let infcx = self.selcx.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let normalized_ty = project::opt_normalize_projection_term( + self.selcx, + self.param_env, + data.into(), + self.cause.clone(), + self.depth, + self.obligations, + ) + .ok() + .flatten() + .map(|term| term.expect_type()) + .map(|normalized_ty| { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_ty, + ) + }) + .unwrap_or_else(|| ty.super_fold_with(self)); + + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty + } + } + + fn normalize_inherent_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { + if !data.has_escaping_bound_vars() { + // This branch is *mostly* just an optimization: when we don't + // have escaping bound vars, we don't need to replace them with + // placeholders (see branch below). *Also*, we know that we can + // register an obligation to *later* project, since we know + // there won't be bound vars there. + + let data = data.fold_with(self); + + project::normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ) + } else { + let infcx = self.selcx.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let ty = project::normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + ty, + ) + } + } + + fn normalize_free_alias(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { + let recursion_limit = self.cx().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.selcx.infcx.err_ctxt().report_overflow_error( + OverflowCause::DeeplyNormalize(data.into()), + self.cause.span, + false, + |diag| { + diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); + }, + ); + } + + let infcx = self.selcx.infcx; + self.obligations.extend( + infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( + |(mut predicate, span)| { + if data.has_escaping_bound_vars() { + (predicate, ..) = BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + predicate, + ); + } + let mut cause = self.cause.clone(); + cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, data.def_id)); + Obligation::new(infcx.tcx, cause, self.param_env, predicate) + }, + ), + ); + self.depth += 1; + let res = infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self); + self.depth -= 1; + res + } } impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -258,168 +415,9 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } } } - - ty::Projection if !data.has_escaping_bound_vars() => { - // When we don't have escaping bound vars we can normalize ambig aliases - // to inference variables (done in `normalize_projection_ty`). This would - // be wrong if there were escaping bound vars as even if we instantiated - // the bound vars with placeholders, we wouldn't be able to map them back - // after normalization succeeded. - // - // Also, as an optimization: when we don't have escaping bound vars, we don't - // need to replace them with placeholders (see branch below). - let data = data.fold_with(self); - let normalized_ty = project::normalize_projection_ty( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty.expect_type() - } - - ty::Projection => { - // If there are escaping bound vars, we temporarily replace the - // bound vars with placeholders. Note though, that in the case - // that we still can't project for whatever reason (e.g. self - // type isn't known enough), we *can't* register an obligation - // and return an inference variable (since then that obligation - // would have bound vars and that's a can of worms). Instead, - // we just give up and fall back to pretending like we never tried! - // - // Note: this isn't necessarily the final approach here; we may - // want to figure out how to register obligations with escaping vars - // or handle this some other way. - - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let normalized_ty = project::opt_normalize_projection_term( - self.selcx, - self.param_env, - data.into(), - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .map(|term| term.expect_type()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); - - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty - } - ty::Free => { - let recursion_limit = self.cx().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.selcx.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), - self.cause.span, - false, - |diag| { - diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); - }, - ); - } - - let infcx = self.selcx.infcx; - self.obligations.extend( - infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( - |(mut predicate, span)| { - if data.has_escaping_bound_vars() { - (predicate, ..) = BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - predicate, - ); - } - let mut cause = self.cause.clone(); - cause.map_code(|code| { - ObligationCauseCode::TypeAlias(code, span, data.def_id) - }); - Obligation::new(infcx.tcx, cause, self.param_env, predicate) - }, - ), - ); - self.depth += 1; - let res = infcx - .tcx - .type_of(data.def_id) - .instantiate(infcx.tcx, data.args) - .fold_with(self); - self.depth -= 1; - res - } - - ty::Inherent if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - - let data = data.fold_with(self); - - project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } - - ty::Inherent => { - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let ty = project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - ty, - ) - } + ty::Projection => self.normalize_trait_projection(data), + ty::Free => self.normalize_free_alias(data), + ty::Inherent => self.normalize_inherent_projection(data), } } From 5d308148aa06f011f062488e81a10aeeb338ba35 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 1 May 2025 16:19:24 +0200 Subject: [PATCH 126/302] allow `#[rustc_std_internal_symbol]` in combination with `#[naked]` --- compiler/rustc_passes/src/check_attr.rs | 1 + tests/ui/asm/naked-functions.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a61d446a3a93..f04b167889f1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -625,6 +625,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::naked, sym::instruction_set, sym::repr, + sym::rustc_std_internal_symbol, // code generation sym::cold, // documentation diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 1eeb716e98a1..cb5fde9a80b8 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -2,7 +2,7 @@ //@ ignore-nvptx64 //@ ignore-spirv -#![feature(asm_unwind, linkage)] +#![feature(asm_unwind, linkage, rustc_attrs)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; @@ -225,3 +225,9 @@ pub extern "C" fn compatible_doc_attributes() { pub extern "C" fn compatible_linkage() { naked_asm!("", options(raw)); } + +#[rustc_std_internal_symbol] +#[unsafe(naked)] +pub extern "C" fn rustc_std_internal_symbol() { + naked_asm!("", options(raw)); +} From 7443d039a5bd9724165e616e5e545e947d85c018 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 29 Apr 2025 20:11:34 +0530 Subject: [PATCH 127/302] Update stdarch --- library/core/Cargo.toml | 1 - library/coretests/benches/ascii.rs | 2 +- library/std/Cargo.toml | 1 - library/stdarch | 2 +- library/sysroot/Cargo.toml | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index fe61f552a49d..99e52d0ada0a 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -31,7 +31,6 @@ level = "warn" check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', - 'cfg(stdarch_intel_sde)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/coretests/benches/ascii.rs b/library/coretests/benches/ascii.rs index 3fe45aa360bf..64bdc7fed118 100644 --- a/library/coretests/benches/ascii.rs +++ b/library/coretests/benches/ascii.rs @@ -354,7 +354,7 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ ]; const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; -const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; #[bench] fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 940b671c5146..d7bd28b5279d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -121,7 +121,6 @@ debug_typeid = ["core/debug_typeid"] # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std_detect/std_detect_env_override"] # Enable using raw-dylib for Windows imports. # This will eventually be the default. diff --git a/library/stdarch b/library/stdarch index 1245618ccf5b..f1c1839c0deb 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 1245618ccf5b2df7ab1ebb0279b9f3f726670161 +Subproject commit f1c1839c0deb985a9f98cbd6b38a6d43f2df6157 diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index ec6ae31507e0..c149d513c32b 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -31,5 +31,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std/std_detect_env_override"] windows_raw_dylib = ["std/windows_raw_dylib"] From c1f2ad2d16cdedd6cf82fe551fb2e8c05def36e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 15 Apr 2025 22:46:29 +0200 Subject: [PATCH 128/302] crashes: more tests --- tests/crashes/138156.rs | 42 +++++++++++++++++++++++++++++++++++++++++ tests/crashes/138240.rs | 9 +++++++++ tests/crashes/138265.rs | 12 ++++++++++++ tests/crashes/138266.rs | 7 +++++++ tests/crashes/138359.rs | 8 ++++++++ tests/crashes/138361.rs | 6 ++++++ tests/crashes/138510.rs | 7 +++++++ tests/crashes/138534.rs | 6 ++++++ tests/crashes/138564.rs | 26 +++++++++++++++++++++++++ tests/crashes/138707.rs | 37 ++++++++++++++++++++++++++++++++++++ tests/crashes/138738.rs | 7 +++++++ tests/crashes/139089.rs | 2 ++ tests/crashes/139120.rs | 29 ++++++++++++++++++++++++++++ tests/crashes/139381.rs | 13 +++++++++++++ tests/crashes/139387.rs | 15 +++++++++++++++ tests/crashes/139409.rs | 12 ++++++++++++ tests/crashes/139462.rs | 8 ++++++++ tests/crashes/139556.rs | 13 +++++++++++++ tests/crashes/139570.rs | 4 ++++ tests/crashes/139596.rs | 10 ++++++++++ tests/crashes/139659.rs | 29 ++++++++++++++++++++++++++++ tests/crashes/139738.rs | 3 +++ tests/crashes/139815.rs | 14 ++++++++++++++ tests/crashes/139817.rs | 8 ++++++++ tests/crashes/139825.rs | 5 +++++ 25 files changed, 332 insertions(+) create mode 100644 tests/crashes/138156.rs create mode 100644 tests/crashes/138240.rs create mode 100644 tests/crashes/138265.rs create mode 100644 tests/crashes/138266.rs create mode 100644 tests/crashes/138359.rs create mode 100644 tests/crashes/138361.rs create mode 100644 tests/crashes/138510.rs create mode 100644 tests/crashes/138534.rs create mode 100644 tests/crashes/138564.rs create mode 100644 tests/crashes/138707.rs create mode 100644 tests/crashes/138738.rs create mode 100644 tests/crashes/139089.rs create mode 100644 tests/crashes/139120.rs create mode 100644 tests/crashes/139381.rs create mode 100644 tests/crashes/139387.rs create mode 100644 tests/crashes/139409.rs create mode 100644 tests/crashes/139462.rs create mode 100644 tests/crashes/139556.rs create mode 100644 tests/crashes/139570.rs create mode 100644 tests/crashes/139596.rs create mode 100644 tests/crashes/139659.rs create mode 100644 tests/crashes/139738.rs create mode 100644 tests/crashes/139815.rs create mode 100644 tests/crashes/139817.rs create mode 100644 tests/crashes/139825.rs diff --git a/tests/crashes/138156.rs b/tests/crashes/138156.rs new file mode 100644 index 000000000000..48c6455627f0 --- /dev/null +++ b/tests/crashes/138156.rs @@ -0,0 +1,42 @@ +//@ known-bug: #138156 + +#![feature(generic_const_exprs)] + +#[derive(Default)] +pub struct GenId; + +pub trait IndexTrait: Default { + const IDX: usize; +} +pub trait ToplogyIndex { + type Idx: IndexTrait; +} + +#[derive(Default)] +pub struct Expression { + pub data: T, +} + +fn i(s: Expression) -> + Expression> +where + GenId<{ IDX0 | IDX1 }>: ToplogyIndex, +{ + Expression::default() +} + +pub fn sum(s: Expression) -> Expression +where + [(); In::Idx::IDX]:, +{ + s +} + +fn param_position(s: Expression) +where + GenId<{ 1 | 2 }>: ToplogyIndex, +{ + sum(i::<_, 1, 2>(s)); +} + +fn main() {} diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs new file mode 100644 index 000000000000..6ffb7868bd5d --- /dev/null +++ b/tests/crashes/138240.rs @@ -0,0 +1,9 @@ +//@ known-bug: #138240 +//@edition:2024 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +async fn _CF() -> Box<[u8; Box::b]> { + Box::new(true) +} + +fn main() {} diff --git a/tests/crashes/138265.rs b/tests/crashes/138265.rs new file mode 100644 index 000000000000..f6c8ea748895 --- /dev/null +++ b/tests/crashes/138265.rs @@ -0,0 +1,12 @@ +//@ known-bug: #138265 + +#![feature(coerce_unsized)] +#![crate_type = "lib"] +impl std::ops::CoerceUnsized for A {} +pub fn f() { + [0; { + let mut c = &0; + c = &0; + 0 + }] +} diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs new file mode 100644 index 000000000000..9a4de9abcff5 --- /dev/null +++ b/tests/crashes/138266.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138266 +//@compile-flags: --crate-type=lib +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +pub fn f(mut x: [u8; Box::b]) { + x[72] = 1; +} diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs new file mode 100644 index 000000000000..d4376d536eec --- /dev/null +++ b/tests/crashes/138359.rs @@ -0,0 +1,8 @@ +//@ known-bug: #138359 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct a(Box<[u8; Box::b]>); +impl a { + fn c(self) { self.0.da } +} +fn main() {} diff --git a/tests/crashes/138361.rs b/tests/crashes/138361.rs new file mode 100644 index 000000000000..8661ed374744 --- /dev/null +++ b/tests/crashes/138361.rs @@ -0,0 +1,6 @@ +//@ known-bug: #138361 + +fn main() { + [0; loop{}]; + std::mem::transmute(4) +} diff --git a/tests/crashes/138510.rs b/tests/crashes/138510.rs new file mode 100644 index 000000000000..f429e8bb33b5 --- /dev/null +++ b/tests/crashes/138510.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138510 +fn main() +where + #[repr()] + _: Sized, +{ +} diff --git a/tests/crashes/138534.rs b/tests/crashes/138534.rs new file mode 100644 index 000000000000..80f9cd225183 --- /dev/null +++ b/tests/crashes/138534.rs @@ -0,0 +1,6 @@ +//@ known-bug: #138534 +//@compile-flags: -Zunpretty=expanded +#[repr(bool)] +pub enum TopFg { + Bar, +} diff --git a/tests/crashes/138564.rs b/tests/crashes/138564.rs new file mode 100644 index 000000000000..b10f75f8cdd0 --- /dev/null +++ b/tests/crashes/138564.rs @@ -0,0 +1,26 @@ +//@ known-bug: #138564 +//@compile-flags: -Copt-level=0 -Cdebuginfo=2 --crate-type lib +#![feature(unsize, dispatch_from_dyn, arbitrary_self_types)] + +use std::marker::Unsize; +use std::ops::{Deref, DispatchFromDyn}; + +#[repr(align(16))] +pub struct MyPointer(*const T); + +impl, U: ?Sized> DispatchFromDyn> for MyPointer {} +impl Deref for MyPointer { + type Target = T; + fn deref(&self) -> &T { + unimplemented!() + } +} + +pub trait Trait { + fn foo(self: MyPointer) {} +} + +// make sure some usage of `::foo` makes it to codegen +pub fn user() -> *const () { + ::foo as *const () +} diff --git a/tests/crashes/138707.rs b/tests/crashes/138707.rs new file mode 100644 index 000000000000..4d9a82500ec4 --- /dev/null +++ b/tests/crashes/138707.rs @@ -0,0 +1,37 @@ +//@ known-bug: #138707 +//@edition:2024 +//@compile-flags: --crate-type lib +use core::marker::PhantomData; + +struct LeftReflector { + _phantom: PhantomData, +} + +struct DefaultAllocator {} + +trait Allocator { + type Buffer; +} + +struct U2 {} + +impl Allocator for DefaultAllocator { + type Buffer = [u8; 2]; +} + +impl From for LeftReflector<>::Buffer> +where + DefaultAllocator: Allocator, +{ + fn from(_: R) -> Self { + todo!() + } +} + +fn ice(a: U2) +where + DefaultAllocator: Allocator, +{ + // ICE + let _ = LeftReflector::from(a); +} diff --git a/tests/crashes/138738.rs b/tests/crashes/138738.rs new file mode 100644 index 000000000000..74e5effa56f5 --- /dev/null +++ b/tests/crashes/138738.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138738 +//@ only-x86_64 + +#![feature(abi_ptx)] +fn main() { + let a = unsafe { core::mem::transmute::(4) }(2); +} diff --git a/tests/crashes/139089.rs b/tests/crashes/139089.rs new file mode 100644 index 000000000000..3326aa6ad984 --- /dev/null +++ b/tests/crashes/139089.rs @@ -0,0 +1,2 @@ +//@ known-bug: #139089 +pub fn foo3(x: &Vec) { x.push(0); } diff --git a/tests/crashes/139120.rs b/tests/crashes/139120.rs new file mode 100644 index 000000000000..f946f010c44e --- /dev/null +++ b/tests/crashes/139120.rs @@ -0,0 +1,29 @@ +//@ known-bug: #139120 + + + +pub trait Foo { + type Bar<'a>; +} + +pub struct FooImpl {} + +impl Foo for FooImpl { + type Bar<'a> = (); +} + +pub trait FooFn { + fn bar(&self); +} + +impl FooFn for fn(T, T::Bar<'_>) { + fn bar(&self) {} +} + +fn foo(f: fn(T, T::Bar<'_>)) { + let _: &dyn FooFn = &f; +} + +fn main() { + foo(|_: FooImpl, _| {}); +} diff --git a/tests/crashes/139381.rs b/tests/crashes/139381.rs new file mode 100644 index 000000000000..6757b584e82a --- /dev/null +++ b/tests/crashes/139381.rs @@ -0,0 +1,13 @@ +//@ known-bug: #139381 +//@ needs-rustc-debug-assertions +trait A<'a> { + type Assoc: ?Sized; +} + +impl<'a> A<'a> for () { + type Assoc = &'a (); +} + +fn hello() -> impl for<'a> A<'a, Assoc: Into + 'static + Copy> { + () +} diff --git a/tests/crashes/139387.rs b/tests/crashes/139387.rs new file mode 100644 index 000000000000..133643ad084b --- /dev/null +++ b/tests/crashes/139387.rs @@ -0,0 +1,15 @@ +//@ known-bug: #139387 +//@ needs-rustc-debug-assertions + +trait A { + fn method() -> impl Sized; +} +trait B { + fn method(Hash: Wrap Epsilon<'_, SI1: Eta>>>) -> impl Sized; +} + +fn ambiguous() +where + T::method(..): Send, +{ +} diff --git a/tests/crashes/139409.rs b/tests/crashes/139409.rs new file mode 100644 index 000000000000..68cbfa153deb --- /dev/null +++ b/tests/crashes/139409.rs @@ -0,0 +1,12 @@ +//@ known-bug: #139409 +//@ compile-flags: -Znext-solver=globally + +fn main() { + trait B {} + impl B for () {} + trait D: B + B { + fn f(&self) {} + } + impl D for () {} + (&() as &dyn D<&(), &()>).f() +} diff --git a/tests/crashes/139462.rs b/tests/crashes/139462.rs new file mode 100644 index 000000000000..05bb246d7be0 --- /dev/null +++ b/tests/crashes/139462.rs @@ -0,0 +1,8 @@ +//@ known-bug: #139462 +//@ compile-flags: -Cdebuginfo=2 +#![feature(unsafe_binders)] +use std::unsafe_binder::wrap_binder; +fn main() { + let foo = 0; + let foo: unsafe<'a> &'a u32 = unsafe { wrap_binder!(&foo) }; +} diff --git a/tests/crashes/139556.rs b/tests/crashes/139556.rs new file mode 100644 index 000000000000..60dc8d7c3afc --- /dev/null +++ b/tests/crashes/139556.rs @@ -0,0 +1,13 @@ +//@ known-bug: #139556 + +trait T {} + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S {} + +#[define_opaque(Alias)] +fn with_positive(fun: impl Fn(Alias<'_>)) { + with_positive(|&n| ()); +} diff --git a/tests/crashes/139570.rs b/tests/crashes/139570.rs new file mode 100644 index 000000000000..9c001aaf848a --- /dev/null +++ b/tests/crashes/139570.rs @@ -0,0 +1,4 @@ +//@ known-bug: #139570 +fn main() { + |(1, 42), ()| yield; +} diff --git a/tests/crashes/139596.rs b/tests/crashes/139596.rs new file mode 100644 index 000000000000..590cfddf83e2 --- /dev/null +++ b/tests/crashes/139596.rs @@ -0,0 +1,10 @@ +//@ known-bug: #139596 + +#![feature(min_generic_const_args)] +struct Colour; + +struct Led; + +fn main() { + Led::<{ Colour}>; +} diff --git a/tests/crashes/139659.rs b/tests/crashes/139659.rs new file mode 100644 index 000000000000..7fc33f7e6a7c --- /dev/null +++ b/tests/crashes/139659.rs @@ -0,0 +1,29 @@ +//@ known-bug: #139659 +//@compile-flags: -Cdebuginfo=2 -Copt-level=0 --crate-type lib +trait Trait { + type Output; +} + +impl O> Trait for F { + type Output = O; +} + +struct Wrap

(P); +struct WrapOutput(O); + +impl Trait for Wrap

{ + type Output = WrapOutput; +} + +fn wrap(x: P) -> impl Trait { + Wrap(x) +} + +fn consume(_: P) -> P::Output { + unimplemented!() +} + +pub fn recurse() -> impl Sized { + consume(wrap(recurse)) +} +pub fn main() {} diff --git a/tests/crashes/139738.rs b/tests/crashes/139738.rs new file mode 100644 index 000000000000..c0e7307de6c3 --- /dev/null +++ b/tests/crashes/139738.rs @@ -0,0 +1,3 @@ +//@ known-bug: #139738 +#![feature(generic_const_exprs)] +fn b<'a>() -> impl IntoIterator<[(); (|_: &'a u8| 0, 0).1]> {} diff --git a/tests/crashes/139815.rs b/tests/crashes/139815.rs new file mode 100644 index 000000000000..9094acdc94b2 --- /dev/null +++ b/tests/crashes/139815.rs @@ -0,0 +1,14 @@ +//@ known-bug: #139815 + +#![feature(generic_const_exprs)] +fn is_123( + x: [u32; { + N + 1; + 5 + }], +) -> bool { + match x { + [1, 2] => true, + _ => false, + } +} diff --git a/tests/crashes/139817.rs b/tests/crashes/139817.rs new file mode 100644 index 000000000000..d439ed4cacbd --- /dev/null +++ b/tests/crashes/139817.rs @@ -0,0 +1,8 @@ +//@ known-bug: #139817 +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((42, std::marker::PhantomData::)); + let x = move || match foo { + None => (), + }; +} diff --git a/tests/crashes/139825.rs b/tests/crashes/139825.rs new file mode 100644 index 000000000000..8c5b6b80f0ba --- /dev/null +++ b/tests/crashes/139825.rs @@ -0,0 +1,5 @@ +//@ known-bug: #139825 +//@compile-flags: --check-cfg=cfg(docsrs,test) --crate-type lib +struct a +where + for<#[cfg(b)] c> u8:; From bc68d3a14467ef6fcebb003f79c2f4c5ef5dd08e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 May 2025 17:42:13 +0200 Subject: [PATCH 129/302] Improve error output in case `nodejs` or `npm` is not installed for rustdoc-gui test suite --- src/tools/rustdoc-gui-test/src/config.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs index 950e2fa478dc..b9d08a0a2950 100644 --- a/src/tools/rustdoc-gui-test/src/config.rs +++ b/src/tools/rustdoc-gui-test/src/config.rs @@ -20,8 +20,8 @@ pub(crate) struct Config { impl Config { pub(crate) fn from_args(args: Vec) -> Self { let mut opts = Options::new(); - opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH") - .reqopt("", "npm", "absolute path of npm", "PATH") + opts.optopt("", "nodejs", "absolute path of nodejs", "PATH") + .optopt("", "npm", "absolute path of npm", "PATH") .reqopt("", "out-dir", "output path of doc compilation", "PATH") .reqopt("", "rust-src", "root source of the rust source", "PATH") .reqopt( @@ -47,9 +47,18 @@ impl Config { Err(f) => panic!("{:?}", f), }; + let Some(nodejs) = matches.opt_str("nodejs").map(PathBuf::from) else { + eprintln!("`nodejs` was not provided. If not available, please install it"); + std::process::exit(1); + }; + let Some(npm) = matches.opt_str("npm").map(PathBuf::from) else { + eprintln!("`npm` was not provided. If not available, please install it"); + std::process::exit(1); + }; + Self { - nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"), - npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"), + nodejs, + npm, rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(), out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(), initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(), From 951412e2f3cf2b27f9a22076b5cb77fb8ff5f259 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 1 May 2025 00:37:37 +0000 Subject: [PATCH 130/302] PassWrapper: adapt for llvm/llvm-project@f137c3d592e96330e450a8fd63ef7e8877fc1908 In LLVM 21 PR https://github.com/llvm/llvm-project/pull/130940 `TargetRegistry::createTargetMachine` was changed to take a `const Triple&` and has deprecated the old `StringRef` method. @rustbot label llvm-main --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ebe8eb57f2cd..d4a05fbbbc5d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -512,8 +512,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( #endif } +#if LLVM_VERSION_GE(21, 0) + TargetMachine *TM = TheTarget->createTargetMachine(Trip, CPU, Feature, + Options, RM, CM, OptLevel); +#else TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); +#endif return wrap(TM); } From 238d113b0726b9734ec42737cbc461d08520bf35 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 13:26:23 +0100 Subject: [PATCH 131/302] Set groundwork for proper const normalization --- compiler/rustc_infer/src/infer/projection.rs | 25 ++- compiler/rustc_middle/src/ty/context.rs | 12 +- compiler/rustc_middle/src/ty/print/pretty.rs | 5 +- compiler/rustc_middle/src/ty/util.rs | 2 + .../rustc_mir_build/src/thir/pattern/mod.rs | 2 + .../src/solve/normalizes_to/free_alias.rs | 16 +- .../src/solve/normalizes_to/inherent.rs | 13 +- .../src/solve/normalizes_to/mod.rs | 10 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/normalize.rs | 194 ++++++++++-------- .../src/traits/project.rs | 166 +++++++++------ .../src/traits/select/confirmation.rs | 1 - .../rustc_trait_selection/src/traits/wf.rs | 20 +- .../src/normalize_projection_ty.rs | 14 +- compiler/rustc_type_ir/src/predicate.rs | 70 ++++++- compiler/rustc_type_ir/src/relate.rs | 2 + compiler/rustc_type_ir/src/ty_kind.rs | 22 -- .../cross_crate_predicate.stderr | 15 +- 18 files changed, 366 insertions(+), 225 deletions(-) diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 1bee9632110b..2a4f9db8963c 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -1,7 +1,8 @@ use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use super::InferCtxt; +use crate::infer::Term; use crate::traits::{Obligation, PredicateObligations}; impl<'tcx> InferCtxt<'tcx> { @@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> { /// of the given projection. This allows us to proceed with projections /// while they cannot be resolved yet due to missing information or /// simply due to the lack of access to the trait resolution machinery. - pub fn projection_ty_to_infer( + pub fn projection_term_to_infer( &self, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, obligations: &mut PredicateObligations<'tcx>, - ) -> Ty<'tcx> { + ) -> Term<'tcx> { debug_assert!(!self.next_trait_solver()); - let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id)); + + let span = self.tcx.def_span(alias_term.def_id); + let infer_var = if alias_term.kind(self.tcx).is_type() { + self.next_ty_var(span).into() + } else { + self.next_const_var(span).into() + }; + let projection = ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_term: projection_ty.into(), - term: ty_var.into(), + projection_term: alias_term, + term: infer_var, })); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); obligations.push(obligation); - ty_var + + infer_var } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3ea285d3d8eb..0f7f8527088c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -243,10 +243,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ty::AliasTermKind::ProjectionTy } } + DefKind::AssocConst => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentConst + } else { + ty::AliasTermKind::ProjectionConst + } + } DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::FreeTy, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => { + DefKind::Const => ty::AliasTermKind::FreeConst, + DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => { ty::AliasTermKind::UnevaluatedConst } kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ad8677f7c7da..af90c2fb95da 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3195,7 +3195,7 @@ define_print! { ty::AliasTerm<'tcx> { match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)), ty::AliasTermKind::ProjectionTy => { if !(cx.should_print_verbose() || with_reduced_queries()) && cx.tcx().is_impl_trait_in_trait(self.def_id) @@ -3205,7 +3205,8 @@ define_print! { p!(print_def_path(self.def_id, self.args)); } } - | ty::AliasTermKind::FreeTy + ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f5158edffcff..6fe5927c29fc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -966,7 +966,9 @@ impl<'tcx> TyCtxt<'tcx> { } ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => None, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8e69ff568b92..4a7e98f24ae3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -568,6 +568,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Lower the named constant to a THIR pattern. let args = self.typeck_results.node_args(id); + // FIXME(mgca): we will need to special case IACs here to have type system compatible + // generic args, instead of how we represent them in body expressions. let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let mut pattern = self.const_to_pat(c, ty, id, span); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index d077f8a9be8a..8aa6e4a3d711 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -19,19 +19,25 @@ where goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let free_ty = goal.predicate.alias; + let free_alias = goal.predicate.alias; // Check where clauses self.add_goals( GoalSource::Misc, - cx.predicates_of(free_ty.def_id) - .iter_instantiated(cx, free_ty.args) + cx.predicates_of(free_alias.def_id) + .iter_instantiated(cx, free_alias.args) .map(|pred| goal.with(cx, pred)), ); - let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args); - self.instantiate_normalizes_to_term(goal, actual.into()); + let actual = if free_alias.kind(cx).is_type() { + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. + panic!("normalizing free const aliases in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 1d1ff09ee410..2640238f5a90 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -15,12 +15,12 @@ where D: SolverDelegate, I: Interner, { - pub(super) fn normalize_inherent_associated_type( + pub(super) fn normalize_inherent_associated_term( &mut self, goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let inherent = goal.predicate.alias.expect_ty(cx); + let inherent = goal.predicate.alias; let impl_def_id = cx.parent(inherent.def_id); let impl_args = self.fresh_args_for_item(impl_def_id); @@ -48,8 +48,13 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args); - self.instantiate_normalizes_to_term(goal, normalized.into()); + let normalized = if inherent.kind(cx).is_type() { + cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() + } else { + // FIXME(mgca): Properly handle IACs in the type system + panic!("normalizing inherent associated consts in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index b030af483817..400b4ce1200c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -48,9 +48,13 @@ where }) }) } - ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + self.normalize_inherent_associated_term(goal) + } ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), - ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal), + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + self.normalize_free_alias(goal) + } ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal), } } @@ -333,6 +337,8 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. if cx.features().associated_const_equality() { panic!("associated const projection is not supported yet") } else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0987c5b42d88..5b938456e03b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -51,7 +51,7 @@ pub use self::dyn_compatibility::{ pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; -pub use self::project::{normalize_inherent_projection, normalize_projection_ty}; +pub use self::project::{normalize_inherent_projection, normalize_projection_term}; pub use self::select::{ EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache, SelectionContext, diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index e08428f925c9..88a0c402702e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,6 +1,7 @@ //! Deeply normalize types using the old trait solver. use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def::DefKind; use rustc_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ @@ -10,15 +11,12 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, AliasTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, + self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingMode, }; use tracing::{debug, instrument}; -use super::{ - BoundVarReplacer, PlaceholderReplacer, SelectionContext, project, - with_replaced_escaping_bound_vars, -}; +use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project}; use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::traits::OverflowCause; use crate::solve::NextSolverError; @@ -179,8 +177,10 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) } } - fn normalize_trait_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { - if !data.has_escaping_bound_vars() { + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> { + if !proj.has_escaping_bound_vars() { // When we don't have escaping bound vars we can normalize ambig aliases // to inference variables (done in `normalize_projection_ty`). This would // be wrong if there were escaping bound vars as even if we instantiated @@ -189,23 +189,15 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { // // Also, as an optimization: when we don't have escaping bound vars, we don't // need to replace them with placeholders (see branch below). - let data = data.fold_with(self); - let normalized_ty = project::normalize_projection_ty( + let proj = proj.fold_with(self); + project::normalize_projection_term( self.selcx, self.param_env, - data, + proj, self.cause.clone(), self.depth, self.obligations, - ); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty.expect_type() + ) } else { // If there are escaping bound vars, we temporarily replace the // bound vars with placeholders. Note though, that in the case @@ -218,72 +210,64 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { // Note: this isn't necessarily the final approach here; we may // want to figure out how to register obligations with escaping vars // or handle this some other way. - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let normalized_ty = project::opt_normalize_projection_term( + let (proj, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj); + let proj = proj.fold_with(self); + let normalized_term = project::opt_normalize_projection_term( self.selcx, self.param_env, - data.into(), + proj, self.cause.clone(), self.depth, self.obligations, ) .ok() .flatten() - .map(|term| term.expect_type()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); + .unwrap_or(proj.to_term(infcx.tcx)); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_term, + ) } } - fn normalize_inherent_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { - if !data.has_escaping_bound_vars() { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - - let data = data.fold_with(self); + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> { + if !inherent.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + let inherent = inherent.fold_with(self); project::normalize_inherent_projection( self.selcx, self.param_env, - data, + inherent, self.cause.clone(), self.depth, self.obligations, ) } else { let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let ty = project::normalize_inherent_projection( + let (inherent, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent); + let inherent = inherent.fold_with(self); + let inherent = project::normalize_inherent_projection( self.selcx, self.param_env, - data, + inherent, self.cause.clone(), self.depth, self.obligations, @@ -295,16 +279,18 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { mapped_types, mapped_consts, &self.universes, - ty, + inherent, ) } } - fn normalize_free_alias(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> { + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> { let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), + OverflowCause::DeeplyNormalize(free.into()), self.cause.span, false, |diag| { @@ -315,9 +301,13 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { let infcx = self.selcx.infcx; self.obligations.extend( - infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( + // FIXME(BoxyUwU): + // FIXME(lazy_type_alias): + // It seems suspicious to instantiate the predicates with arguments that might be bound vars, + // we might wind up instantiating one of these bound vars underneath a hrtb. + infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map( |(mut predicate, span)| { - if data.has_escaping_bound_vars() { + if free.has_escaping_bound_vars() { (predicate, ..) = BoundVarReplacer::replace_bound_vars( infcx, &mut self.universes, @@ -325,13 +315,21 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ); } let mut cause = self.cause.clone(); - cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, data.def_id)); + cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id)); Obligation::new(infcx.tcx, cause, self.param_env, predicate) }, ), ); self.depth += 1; - let res = infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self); + let res = if free.kind(infcx.tcx).is_type() { + infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead use that rather than evaluating. + super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) + .super_fold_with(self) + .into() + }; self.depth -= 1; res } @@ -415,28 +413,64 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } } } - ty::Projection => self.normalize_trait_projection(data), - ty::Free => self.normalize_free_alias(data), - ty::Inherent => self.normalize_inherent_projection(data), + + ty::Projection => self.normalize_trait_projection(data.into()).expect_type(), + ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(), + ty::Free => self.normalize_free_alias(data.into()).expect_type(), } } #[instrument(skip(self), level = "debug")] - fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant) - { - constant + if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) { + return ct; + } + + // Doing "proper" normalization of const aliases is inherently cyclic until const items + // are real aliases instead of having bodies. We gate proper const alias handling behind + // mgca to avoid breaking stable code, though this should become the "main" codepath long + // before mgca is stabilized. + // + // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items + // are represented. + if tcx.features().min_generic_const_args() { + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; + + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()) + } + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; + + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.expect_const().super_fold_with(self) } else { - let constant = constant.super_fold_with(self); - debug!(?constant, ?self.param_env); - with_replaced_escaping_bound_vars( + let ct = ct.super_fold_with(self); + return super::with_replaced_escaping_bound_vars( self.selcx.infcx, &mut self.universes, - constant, - |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env), + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), ) - .super_fold_with(self) + .super_fold_with(self); + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dd868c9d40ea..ca58da5ca6d5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -5,7 +5,6 @@ use std::ops::ControlFlow; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::resolve::OpportunisticRegionResolver; @@ -172,6 +171,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// ``` /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -201,6 +201,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_term] for an explanation of the return value. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] fn project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -258,34 +259,28 @@ fn project_and_unify_term<'cx, 'tcx>( /// there are unresolved type variables in the projection, we will /// instantiate it with a fresh type variable `$X` and generate a new /// obligation `::Item == $X` for later. -pub fn normalize_projection_ty<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> Term<'tcx> { - opt_normalize_projection_term( - selcx, - param_env, - projection_ty.into(), - cause.clone(), - depth, - obligations, - ) - .ok() - .flatten() - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. + opt_normalize_projection_term(selcx, param_env, alias_term, cause.clone(), depth, obligations) + .ok() + .flatten() + .unwrap_or_else(move || { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. - selcx - .infcx - .projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations) - .into() - }) + selcx + .infcx + .projection_term_to_infer(param_env, alias_term, cause, depth + 1, obligations) + .into() + }) } /// The guts of `normalize`: normalize a specific projection like `( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, @@ -456,6 +452,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for /// one case where this arose.) +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn normalize_to_error<'a, 'tcx>( selcx: &SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -469,9 +466,10 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::InherentTy | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - selcx.infcx.next_const_var(cause.span).into() - } + ty::AliasTermKind::FreeConst + | ty::AliasTermKind::InherentConst + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(), }; let mut obligations = PredicateObligations::new(); obligations.push(Obligation { @@ -484,36 +482,37 @@ fn normalize_to_error<'a, 'tcx>( } /// Confirm and normalize the given inherent projection. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_inherent_projection<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, -) -> Ty<'tcx> { +) -> ty::Term<'tcx> { let tcx = selcx.tcx(); if !tcx.recursion_limit().value_within_limit(depth) { // Halt compilation because it is important that overflows never be masked. tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow { span: cause.span, - ty: alias_ty.to_string(), + ty: alias_term.to_string(), }); } - let args = compute_inherent_assoc_ty_args( + let args = compute_inherent_assoc_term_args( selcx, param_env, - alias_ty, + alias_term, cause.clone(), depth, obligations, ); // Register the obligations arising from the impl and from the associated type itself. - let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args); + let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args); for (predicate, span) in predicates { let predicate = normalize_with_depth_to( selcx, @@ -531,7 +530,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. // Consider creating separate cause codes for this specific situation. - ObligationCauseCode::WhereClause(alias_ty.def_id, span), + ObligationCauseCode::WhereClause(alias_term.def_id, span), ); obligations.push(Obligation::with_depth( @@ -543,27 +542,33 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( )); } - let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args); + let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { + tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() + } else { + get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + }; - let mut ty = selcx.infcx.resolve_vars_if_possible(ty); - if ty.has_aliases() { - ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations); + let mut term = selcx.infcx.resolve_vars_if_possible(term); + if term.has_aliases() { + term = + normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations); } - ty + term } -pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> ty::GenericArgsRef<'tcx> { let tcx = selcx.tcx(); - let impl_def_id = tcx.parent(alias_ty.def_id); + let impl_def_id = tcx.parent(alias_term.def_id); let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id); let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); @@ -580,7 +585,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. - let mut self_ty = alias_ty.self_ty(); + let mut self_ty = alias_term.self_ty(); if !selcx.infcx.next_trait_solver() { self_ty = normalize_with_depth_to( selcx, @@ -602,7 +607,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( } } - alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx) + alias_term.rebase_inherent_args_onto_impl(impl_args, tcx) } enum Projected<'tcx> { @@ -630,6 +635,7 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "info", skip(selcx))] fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -896,7 +902,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the + // codegen (i.e., `TypingMode` is not `PostAnalysis`), and the // impl's type is declared as default, then we disable // projection (even if the trait ref is fully // monomorphic). In the case where trait ref is not @@ -1189,6 +1195,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }); } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1222,6 +1229,7 @@ fn confirm_candidate<'cx, 'tcx>( result } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1873,6 +1881,7 @@ fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( .with_addl_obligations(nested) } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1926,9 +1935,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); - assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); - // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take - // a term instead. + assoc_term_own_obligations(selcx, obligation, &mut nested_obligations); Progress { term: cache_entry.term, obligations: nested_obligations } } Err(e) => { @@ -1942,6 +1949,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( } } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1955,8 +1963,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { - Ok(assoc_ty) => assoc_ty, + let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { + Ok(assoc_term) => assoc_term, Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), }; @@ -1965,10 +1973,10 @@ fn confirm_impl_candidate<'cx, 'tcx>( // has impossible-to-satisfy predicates (since those were // allowed in ), // or because the impl is literally missing the definition. - if !assoc_ty.item.defaultness(tcx).has_value() { + if !assoc_term.item.defaultness(tcx).has_value() { debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name(), + assoc_term.item.name(), obligation.predicate ); if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { @@ -1979,7 +1987,11 @@ fn confirm_impl_candidate<'cx, 'tcx>( return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx))); } else { return Ok(Projected::Progress(Progress { - term: Ty::new_misc_error(tcx).into(), + term: if obligation.predicate.kind(tcx).is_type() { + Ty::new_misc_error(tcx).into() + } else { + ty::Const::new_misc_error(tcx).into() + }, obligations: nested, })); } @@ -1992,27 +2004,32 @@ fn confirm_impl_candidate<'cx, 'tcx>( // * `args` is `[u32]` // * `args` ends up as `[u32, S]` let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); - let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); - let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); + let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node); - let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { - let did = assoc_ty.item.def_id; - let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); - let uv = ty::UnevaluatedConst::new(did, identity_args); - ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into()) + let term = if obligation.predicate.kind(tcx).is_type() { + tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) + ty::EarlyBinder::bind( + get_associated_const_value( + selcx, + obligation.predicate.to_term(tcx).expect_const(), + param_env, + ) + .into(), + ) }; - let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { - let err = Ty::new_error_with_message( - tcx, - obligation.cause.span, - "impl item and trait item have different parameters", - ); - Progress { term: err.into(), obligations: nested } + let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { + let msg = "impl item and trait item have different parameters"; + let span = obligation.cause.span; + let err = if obligation.predicate.kind(tcx).is_type() { + Ty::new_error_with_message(tcx, span, msg).into() + } else { + ty::Const::new_error_with_message(tcx, span, msg).into() + }; + Progress { term: err, obligations: nested } } else { - assoc_ty_own_obligations(selcx, obligation, &mut nested); + assoc_term_own_obligations(selcx, obligation, &mut nested); Progress { term: term.instantiate(tcx, args), obligations: nested } }; Ok(Projected::Progress(progress)) @@ -2020,7 +2037,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. -fn assoc_ty_own_obligations<'cx, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +fn assoc_term_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, nested: &mut PredicateObligations<'tcx>, @@ -2090,3 +2108,15 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } + +fn get_associated_const_value<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + alias_ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> ty::Const<'tcx> { + // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type + // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the + // constant is "close enough" to getting the actual rhs of the const item for now even if it might + // lead to some cycles + super::evaluate_const(selcx.infcx, alias_ct, param_env) +} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8008c7e4d342..94190cd3ae33 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -406,7 +406,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let mut assume = predicate.trait_ref.args.const_at(2); - // FIXME(mgca): We should shallowly normalize this. if self.tcx().features().generic_const_exprs() { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 2e32cda7602e..08d3b92e9b5e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -6,6 +6,7 @@ use std::iter; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::bug; @@ -486,7 +487,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes the obligations required for an inherent alias to be WF /// into `self.out`. // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`. - fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { + fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) { // An inherent projection is well-formed if // // (a) its predicates hold (*) @@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !data.self_ty().has_escaping_bound_vars() { // FIXME(inherent_associated_types): Should this happen inside of a snapshot? // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! - let args = traits::project::compute_inherent_assoc_ty_args( + let args = traits::project::compute_inherent_assoc_term_args( &mut traits::SelectionContext::new(self.infcx), self.param_env, data, @@ -776,7 +777,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.out.extend(obligations); } ty::Alias(ty::Inherent, data) => { - self.add_wf_preds_for_inherent_projection(data); + self.add_wf_preds_for_inherent_projection(data.into()); return; // Subtree handled by compute_inherent_projection. } @@ -961,9 +962,6 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def, uv.args); - self.out.extend(obligations); - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); @@ -975,6 +973,16 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.param_env, predicate, )); + + if tcx.def_kind(uv.def) == DefKind::AssocConst + && tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false }) + { + self.add_wf_preds_for_inherent_projection(uv.into()); + return; // Subtree is handled by above function + } else { + let obligations = self.nominal_obligations(uv.def, uv.args); + self.out.extend(obligations); + } } } ty::ConstKind::Infer(_) => { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 14a92ebb9f96..e52898cc6e24 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -32,8 +32,14 @@ fn normalize_canonicalized_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = - traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations); + let answer = traits::normalize_projection_term( + selcx, + param_env, + goal.into(), + cause, + 0, + &mut obligations, + ); ocx.register_obligations(obligations); // #112047: With projections and opaques, we are able to create opaques that // are recursive (given some generic parameters of the opaque's type variables). @@ -104,14 +110,14 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( let answer = traits::normalize_inherent_projection( selcx, param_env, - goal, + goal.into(), cause, 0, &mut obligations, ); ocx.register_obligations(obligations); - Ok(NormalizationResult { normalized_ty: answer }) + Ok(NormalizationResult { normalized_ty: answer.expect_type() }) }, ) } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 0411c5c2325e..b59495b93c83 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -474,10 +474,15 @@ pub enum AliasTermKind { /// Currently only used if the type alias references opaque types. /// Can always be normalized away. FreeTy, - /// An unevaluated const coming from a generic const expression. + + /// An unevaluated anonymous constants. UnevaluatedConst, /// An unevaluated const coming from an associated const. ProjectionConst, + /// A top level const item not part of a trait or impl. + FreeConst, + /// An associated const in an inherent `impl` + InherentConst, } impl AliasTermKind { @@ -486,11 +491,27 @@ impl AliasTermKind { AliasTermKind::ProjectionTy => "associated type", AliasTermKind::ProjectionConst => "associated const", AliasTermKind::InherentTy => "inherent associated type", + AliasTermKind::InherentConst => "inherent associated const", AliasTermKind::OpaqueTy => "opaque type", AliasTermKind::FreeTy => "type alias", + AliasTermKind::FreeConst => "unevaluated constant", AliasTermKind::UnevaluatedConst => "unevaluated constant", } } + + pub fn is_type(self) -> bool { + match self { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::FreeTy => true, + + AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst + | AliasTermKind::InherentConst + | AliasTermKind::FreeConst => false, + } + } } impl From for AliasTermKind { @@ -566,7 +587,10 @@ impl AliasTerm { | AliasTermKind::InherentTy | AliasTermKind::OpaqueTy | AliasTermKind::FreeTy => {} - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + AliasTermKind::InherentConst + | AliasTermKind::FreeConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => { panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") } } @@ -603,18 +627,19 @@ impl AliasTerm { ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { - I::Const::new_unevaluated( - interner, - ty::UnevaluatedConst::new(self.def_id, self.args), - ) - .into() - } + AliasTermKind::FreeConst + | AliasTermKind::InherentConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => I::Const::new_unevaluated( + interner, + ty::UnevaluatedConst::new(self.def_id, self.args), + ) + .into(), } } } -/// The following methods work only with (trait) associated type projections. +/// The following methods work only with (trait) associated term projections. impl AliasTerm { pub fn self_ty(self) -> I::Ty { self.args.type_at(0) @@ -659,6 +684,31 @@ impl AliasTerm { } } +/// The following methods work only with inherent associated term projections. +impl AliasTerm { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert!(matches!( + self.kind(interner), + AliasTermKind::InherentTy | AliasTermKind::InherentConst + )); + interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) + } +} + impl From> for AliasTerm { fn from(ty: ty::AliasTy) -> Self { AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index c80a567117c6..e3c4a793b37f 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -273,8 +273,10 @@ impl Relate for ty::AliasTerm { false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::FreeTy | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { relate_args_invariantly(relation, a.args, b.args)? diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 21adbffc0274..cf2e4284d10d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -514,28 +514,6 @@ impl AliasTy { } } -/// The following methods work only with inherent associated type projections. -impl AliasTy { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: I::GenericArgs, - interner: I, - ) -> I::GenericArgs { - debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); - interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr( feature = "nightly", diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index a05aaf2af649..1aac357d60e4 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -39,14 +39,6 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 - | -LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ----- required by a bound in this function -LL | where -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: { @@ -59,10 +51,13 @@ LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:3:27 + --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` + | ----- required by a bound in this function +LL | where +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: { From 9ec8373ab6beaf06425c5caa0fb783e767cdc6ad Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 17:12:40 +0100 Subject: [PATCH 132/302] Crashes tests --- tests/crashes/127643.rs | 22 +++++++++++----------- tests/crashes/133066.rs | 12 ------------ 2 files changed, 11 insertions(+), 23 deletions(-) delete mode 100644 tests/crashes/133066.rs diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs index a4db9397bdef..b5ec58b70e93 100644 --- a/tests/crashes/127643.rs +++ b/tests/crashes/127643.rs @@ -1,18 +1,18 @@ //@ known-bug: #127643 -#![feature(associated_const_equality)] +#![feature(generic_const_items, associated_const_equality)] +#![expect(incomplete_features)] -fn user() -> impl Owner {} - -trait Owner { - const C: K; -} -impl Owner for () { - const C: K = K::DEFAULT; +trait Foo { + const ASSOC: u32; } -trait ConstDefault { - const DEFAULT: Self; +impl Foo for () { + const ASSOC: u32 = N; } -fn main() {} +fn bar = { N }>>() {} + +fn main() { + bar::<10_u64, ()>(); +} diff --git a/tests/crashes/133066.rs b/tests/crashes/133066.rs deleted file mode 100644 index 732ebb7079fd..000000000000 --- a/tests/crashes/133066.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133066 -trait Owner { - const C: u32; -} - -impl Owner for () {;} - -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::(()); -} From 175f71750f149643cff56f88b6f7e63c88843dea Mon Sep 17 00:00:00 2001 From: Artur Roos Date: Thu, 1 May 2025 22:09:07 +0300 Subject: [PATCH 133/302] Simplify docs for breaking out of a named code block --- library/std/src/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b0e55c787250..71b68233f788 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -91,7 +91,7 @@ mod as_keyword {} /// /// When associated with `loop`, a break expression may be used to return a value from that loop. /// This is only valid with `loop` and not with any other type of loop. -/// If no value is specified, `break;` returns `()`. +/// If no value is specified for `break;` it returns `()`. /// Every `break` within a loop must return the same type. /// /// ```rust @@ -110,7 +110,7 @@ mod as_keyword {} /// ``` /// /// It is also possible to exit from any *labelled* block returning the value early. -/// If no value specified `break;` returns `()`. +/// If no value is specified for `break;` it returns `()`. /// /// ```rust /// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; From 17d74d63208c9ac1dbbe2462edad667fbeb9469a Mon Sep 17 00:00:00 2001 From: Eyal Kalderon Date: Thu, 1 May 2025 15:13:43 -0400 Subject: [PATCH 134/302] Use present indicative tense in std::io::pipe() API docs The inline documentation for all other free functions in the `std::io` module use the phrase "creates a" instead of "create a", except for the currently nightly-only `std::io::pipe()` function. This commit updates the text to align with the predominant wording in the `std::io` module. I recognize this PR is quite a minuscule nitpick, so feel free to ignore and close if you disagree and/or there are bigger fish to fry. :smile: --- library/std/src/io/pipe.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index c6b7b49a351e..47243806cd2d 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -2,7 +2,7 @@ use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::sys_common::{FromInner, IntoInner}; -/// Create an anonymous pipe. +/// Creates an anonymous pipe. /// /// # Behavior /// @@ -108,7 +108,7 @@ impl IntoInner for PipeWriter { } impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// Creates a new [`PipeReader`] instance that shares the same underlying file description. /// /// # Examples /// @@ -167,7 +167,7 @@ impl PipeReader { } impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// Creates a new [`PipeWriter`] instance that shares the same underlying file description. /// /// # Examples /// From 7b25d4a99edc12909dc73c31cb6a44238c4b9bf9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 1 May 2025 19:17:56 +0000 Subject: [PATCH 135/302] extend the list of registered dylibs on `test::prepare_cargo_test` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index d4fccc535a6b..a7a3b5a878c3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2556,9 +2556,9 @@ fn prepare_cargo_test( // We skip everything on Miri as then this overwrites the libdir set up // by `Cargo::new` and that actually makes things go wrong. if builder.kind != Kind::Miri { - let mut dylib_path = dylib_path(); - dylib_path.insert(0, PathBuf::from(&*builder.sysroot_target_libdir(compiler, target))); - cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + let mut dylib_paths = builder.rustc_lib_paths(compiler); + dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, target))); + helpers::add_dylib_path(dylib_paths, &mut cargo); } if builder.remote_tested(target) { From b2bf951dd60a57b423ab0a3f6b544ff580a08cd1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 28 Mar 2025 16:44:39 +1100 Subject: [PATCH 136/302] Augment `impl-trait-missing-lifetime-gated.rs`. We have coverage for `Foo` and `Foo` but not for `Foo<>`. This commit adds it. Note that the output has bogus syntax: `impl Foo'a, >` --- .../impl-trait-missing-lifetime-gated.rs | 11 ++++ .../impl-trait-missing-lifetime-gated.stderr | 59 +++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index 443a7e3835e3..f5c3da847c72 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -49,6 +49,17 @@ mod alone_in_path { //~| ERROR missing lifetime specifier } +mod alone_in_path2 { + trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; } + + fn f(_: impl Foo<>) {} + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + + fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + //~| ERROR missing lifetime specifier +} + mod in_path { trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 24013c85c875..e7dbb06987a9 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -108,7 +108,28 @@ LL + fn g(mut x: impl Foo) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41 + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:39 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn g(mut x: impl Foo<>) -> Option<&'static ()> { x.next() } + | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo<>) -> Option<&'a ()> { x.next() } + | ++++ ++ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Foo<>) -> Option<()> { x.next() } + | + +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:41 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -129,7 +150,7 @@ LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } | warning: elided lifetime has a name - --> $DIR/impl-trait-missing-lifetime-gated.rs:64:57 + --> $DIR/impl-trait-missing-lifetime-gated.rs:75:57 | LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` @@ -217,7 +238,35 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 + --> $DIR/impl-trait-missing-lifetime-gated.rs:55:21 + | +LL | fn f(_: impl Foo<>) {} + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL - fn f(_: impl Foo<>) {} +LL + fn f<'a>(_: impl Foo'a, >) {} + | + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:25 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } +LL + fn g<'a>(mut x: impl Foo'a, >) -> Option<&()> { x.next() } + | + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:66:22 | LL | fn f(_: impl Foo<()>) {} | ^ expected named lifetime parameter @@ -230,7 +279,7 @@ LL | fn f<'a>(_: impl Foo<'a, ()>) {} | ++++ +++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:26 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -242,7 +291,7 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 17 previous errors; 1 warning emitted Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. From 28deaa6e0e7993f963b3bb44bb235c7682ce0cf3 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 06:18:53 -0700 Subject: [PATCH 137/302] Delegate to inner `vec::IntoIter` from `env::ArgsOs` Delegate from `std::env::ArgsOs` to the methods of the inner platform-specific iterators, when it would be more efficient than just using the default methods of its own impl. Most platforms use `vec::IntoIter` as the inner type, so prioritize delegating to the methods it provides. `std::env::Args` is implemented atop `std::env::ArgsOs` and performs UTF-8 validation with a panic for invalid data. This is a visible effect which users certainly rely on, so we can't skip any arguments. Any further iterator methods would skip some elements, so no change is needed for that type. Add `#[inline]` for any methods which simply wrap the inner iterator. --- library/std/src/env.rs | 73 +++++++++++++++++++++++- library/std/src/lib.rs | 3 + library/std/src/sys/args/common.rs | 66 +++++++++++++++++++-- library/std/src/sys/args/sgx.rs | 76 ++++++++++++++++++++----- library/std/src/sys/args/unsupported.rs | 18 ++++-- 5 files changed, 211 insertions(+), 25 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 1593969e114a..ce2dc7952207 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -12,9 +12,11 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::ops::Try; use crate::path::{Path, PathBuf}; use crate::sys::{env as env_imp, os as os_imp}; -use crate::{fmt, io, sys}; +use crate::{array, fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. /// @@ -872,19 +874,36 @@ impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; + fn next(&mut self) -> Option { self.inner.next().map(|s| s.into_string().unwrap()) } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + // Methods which skip args cannot simply delegate to the inner iterator, + // because `env::args` states that we will "panic during iteration if any + // argument to the process is not valid Unicode". + // + // This offers two possible interpretations: + // - a skipped argument is never encountered "during iteration" + // - even a skipped argument is encountered "during iteration" + // + // As a panic can be observed, we err towards validating even skipped + // arguments for now, though this is not explicitly promised by the API. } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for Args { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -914,19 +933,65 @@ impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.inner.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn count(self) -> usize { + self.inner.len() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.inner.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for ArgsOs { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -934,9 +999,15 @@ impl ExactSizeIterator for ArgsOs { #[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for ArgsOs { + #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_back_by(n) + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ba57ad9bae32..c011f9661ae7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -301,6 +301,8 @@ #![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(let_chains)] #![feature(link_cfg)] @@ -321,6 +323,7 @@ #![feature(strict_provenance_lints)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] // tidy-alphabetical-end // diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index 43ac5e959234..303b373ccf90 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -1,5 +1,7 @@ use crate::ffi::OsString; -use crate::{fmt, vec}; +use crate::num::NonZero; +use crate::ops::Try; +use crate::{array, fmt, vec}; pub struct Args { iter: vec::IntoIter, @@ -9,6 +11,7 @@ impl !Send for Args {} impl !Sync for Args {} impl Args { + #[inline] pub(super) fn new(args: Vec) -> Self { Args { iter: args.into_iter() } } @@ -22,22 +25,77 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.iter.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.iter.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { + #[inline] + fn count(self) -> usize { self.iter.len() } + + #[inline] + fn last(mut self) -> Option { + self.iter.next_back() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 2a4bc76aefb9..f800500c22a8 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,6 +1,8 @@ #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers use crate::ffi::OsString; +use crate::num::NonZero; +use crate::ops::Try; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::os_str::Buf; use crate::sys::pal::abi::usercalls::alloc; @@ -28,35 +30,81 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; - if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) } + let slice = args.map(|args| args.as_slice()).unwrap_or(&[]); + Args { iter: slice.iter() } } -pub struct Args(slice::Iter<'static, OsString>); +pub struct Args { + iter: slice::Iter<'static, OsString>, +} impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.as_slice().fmt(f) + self.iter.as_slice().fmt(f) } } impl Iterator for Args { type Item = OsString; - fn next(&mut self) -> Option { - self.0.next().cloned() - } - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.0.len() + fn next(&mut self) -> Option { + self.iter.next().cloned() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option { + self.iter.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.by_ref().cloned().try_fold(init, f) + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.cloned().fold(init, f) } } impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option { - self.0.next_back().cloned() + self.iter.next_back().cloned() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() } } diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index a2d75a619763..ecffc6d26414 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -15,22 +15,28 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { None } + + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(0)) } } -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { None } } + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + 0 + } +} From d42edee451b87ce3d7b9de82f43c142592e1e661 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 28 Apr 2025 19:24:45 +1000 Subject: [PATCH 138/302] Handle `Path<>` better in error messages. `Path<>` needs to be distinguished from `Path`. This commit does that, improving some error messages. --- compiler/rustc_ast_lowering/src/lib.rs | 10 +++---- compiler/rustc_ast_lowering/src/path.rs | 30 +++++++++++-------- compiler/rustc_hir/src/hir.rs | 29 ++++++++++++------ .../impl-trait-missing-lifetime-gated.stderr | 18 +++++------ 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e14b4d6723f..1844cb2de6c4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, - LifetimeSyntax, ParamName, TraitCandidate, + self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, + LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1081,7 +1081,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( lt, - LifetimeSource::Path { with_angle_brackets: true }, + LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full }, lt.ident.into(), )), ast::GenericArg::Type(ty) => { @@ -1773,13 +1773,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, id: NodeId, span: Span, - with_angle_brackets: bool, + angle_brackets: AngleBrackets, ) -> &'hir hir::Lifetime { self.new_named_lifetime( id, id, Ident::new(kw::UnderscoreLifetime, span), - LifetimeSource::Path { with_angle_brackets }, + LifetimeSource::Path { angle_brackets }, LifetimeSyntax::Hidden, ) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index fabe40a9d041..5cda64ce7b4b 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -432,27 +432,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { - // If there are no brackets, use the identifier span. + let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() { + // No brackets, e.g. `Path`: use an empty span just past the end of the identifier. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) - } else if generic_args.is_empty() { - // If there are brackets, but not generic arguments, then use the opening bracket - (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) + ( + segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), + hir::AngleBrackets::Missing, + ) } else { - // Else use an empty span right after the opening bracket. - (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) + // Brackets, e.g. `Path<>` or `Path`: use an empty span just after the `<`. + ( + generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), + if generic_args.is_empty() { + hir::AngleBrackets::Empty + } else { + hir::AngleBrackets::Full + }, + ) }; generic_args.args.insert_many( 0, (start..end).map(|id| { - let l = self.lower_lifetime_hidden_in_path( - id, - elided_lifetime_span, - with_angle_brackets, - ); + let l = + self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af587ee5bdcd..58b776bdc6ae 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -35,18 +35,24 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum AngleBrackets { + /// E.g. `Path`. + Missing, + /// E.g. `Path<>`. + Empty, + /// E.g. `Path`. + Full, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum LifetimeSource { /// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type` Reference, - /// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>` - Path { - /// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`, - /// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>` - /// - false for `ContainsLifetime` - with_angle_brackets: bool, - }, + /// E.g. `ContainsLifetime`, `ContainsLifetime<>`, `ContainsLifetime<'_>`, + /// `ContainsLifetime<'a>` + Path { angle_brackets: AngleBrackets }, /// E.g. `impl Trait + '_`, `impl Trait + 'a` OutlivesBound, @@ -304,12 +310,17 @@ impl Lifetime { (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), // The user wrote `Path`, and omitted the `'_,`. - (Hidden, Path { with_angle_brackets: true }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Full }) => { (self.ident.span, format!("{new_lifetime}, ")) } + // The user wrote `Path<>`, and omitted the `'_`.. + (Hidden, Path { angle_brackets: AngleBrackets::Empty }) => { + (self.ident.span, format!("{new_lifetime}")) + } + // The user wrote `Path` and omitted the `<'_>`. - (Hidden, Path { with_angle_brackets: false }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Missing }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index e7dbb06987a9..92996ca84678 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -238,32 +238,30 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:55:21 + --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 | LL | fn f(_: impl Foo<>) {} - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date help: consider introducing a named lifetime parameter | -LL - fn f(_: impl Foo<>) {} -LL + fn f<'a>(_: impl Foo'a, >) {} - | +LL | fn f<'a>(_: impl Foo<'a>) {} + | ++++ ++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:25 + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 | LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date help: consider introducing a named lifetime parameter | -LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } -LL + fn g<'a>(mut x: impl Foo'a, >) -> Option<&()> { x.next() } - | +LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } + | ++++ ++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:66:22 From 3f842e51a6e97dad23f9717ae27db2960dde1c34 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 15:24:54 +1000 Subject: [PATCH 139/302] Improve coverage of HIR pretty printing. By taking the existing `expanded-exhaustive.rs` test and running it with both `Zunpretty=expanded` *and* `Zunpretty=hir`. Also rename some files, and split the asm parts out so they only run on x86-64. --- .../unpretty/exhaustive-asm.expanded.stdout | 33 + tests/ui/unpretty/exhaustive-asm.hir.stdout | 31 + tests/ui/unpretty/exhaustive-asm.rs | 31 + ...tive.stdout => exhaustive.expanded.stdout} | 87 +-- tests/ui/unpretty/exhaustive.hir.stderr | 172 +++++ tests/ui/unpretty/exhaustive.hir.stdout | 700 ++++++++++++++++++ .../{expanded-exhaustive.rs => exhaustive.rs} | 64 +- ...rpolation.rs => interpolation-expanded.rs} | 0 ...n.stdout => interpolation-expanded.stdout} | 0 9 files changed, 1014 insertions(+), 104 deletions(-) create mode 100644 tests/ui/unpretty/exhaustive-asm.expanded.stdout create mode 100644 tests/ui/unpretty/exhaustive-asm.hir.stdout create mode 100644 tests/ui/unpretty/exhaustive-asm.rs rename tests/ui/unpretty/{expanded-exhaustive.stdout => exhaustive.expanded.stdout} (96%) create mode 100644 tests/ui/unpretty/exhaustive.hir.stderr create mode 100644 tests/ui/unpretty/exhaustive.hir.stdout rename tests/ui/unpretty/{expanded-exhaustive.rs => exhaustive.rs} (90%) rename tests/ui/unpretty/{expanded-interpolation.rs => interpolation-expanded.rs} (100%) rename tests/ui/unpretty/{expanded-interpolation.stdout => interpolation-expanded.stdout} (100%) diff --git a/tests/ui/unpretty/exhaustive-asm.expanded.stdout b/tests/ui/unpretty/exhaustive-asm.expanded.stdout new file mode 100644 index 000000000000..92829b0ab15b --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.expanded.stdout @@ -0,0 +1,33 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + global_asm! (".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout new file mode 100644 index 000000000000..5a642dff6f2e --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -0,0 +1,31 @@ +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm {/// ItemKind::GlobalAsm + global_asm! (".globl my_asm_func") } + } diff --git a/tests/ui/unpretty/exhaustive-asm.rs b/tests/ui/unpretty/exhaustive-asm.rs new file mode 100644 index 000000000000..74a45447a20f --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.rs @@ -0,0 +1,31 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + core::arch::asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + core::arch::global_asm!(".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout similarity index 96% rename from tests/ui/unpretty/expanded-exhaustive.stdout rename to tests/ui/unpretty/exhaustive.expanded.stdout index c6ffbb0d316b..9712ba58e627 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -1,7 +1,13 @@ #![feature(prelude_import)] -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -211,7 +217,10 @@ mod expressions { } /// ExprKind::Await - fn expr_await() { let fut; fut.await; } + fn expr_await() { + let fut; + fut.await; + } /// ExprKind::TryBlock fn expr_try_block() { try {} try { return; } } @@ -242,7 +251,9 @@ mod expressions { } /// ExprKind::Underscore - fn expr_underscore() { _; } + fn expr_underscore() { + _; + } /// ExprKind::Path fn expr_path() { @@ -275,16 +286,8 @@ mod expressions { /// ExprKind::Ret fn expr_ret() { return; return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", - inout(reg) - x, - out(reg) - _); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -300,65 +303,12 @@ mod expressions { - - - - - - // ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // concat_idents is deprecated @@ -450,10 +400,7 @@ mod items { unsafe extern "C++" {} unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - global_asm! (".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { pub type Type<'a> where T: 'a = T; diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr new file mode 100644 index 000000000000..58f7ff0f5981 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -0,0 +1,172 @@ +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:211:9 + | +LL | static || value; + | ^^^^^^^^^ + +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:212:9 + | +LL | static move || value; + | ^^^^^^^^^^^^^^ + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/exhaustive.rs:241:13 + | +LL | fn expr_await() { + | --------------- this is not `async` +LL | let fut; +LL | fut.await; + | ^^^^^ only allowed inside `async` functions and blocks + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/exhaustive.rs:290:9 + | +LL | _; + | ^ `_` not allowed here + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:300:9 + | +LL | x::(); + | ^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:301:9 + | +LL | x::(T, T) -> T; + | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + | +help: use angle brackets instead + | +LL - x::(T, T) -> T; +LL + x:: -> T; + | + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:302:9 + | +LL | crate::() -> ()::expressions::() -> ()::expr_path; + | ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:302:26 + | +LL | crate::() -> ()::expressions::() -> ()::expr_path; + | ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:305:9 + | +LL | core::()::marker::()::PhantomData; + | ^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:305:19 + | +LL | core::()::marker::()::PhantomData; + | ^^^^^^^^^^ only `Fn` traits may use parentheses + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/exhaustive.rs:392:9 + | +LL | yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn expr_yield() { + | ++++++++++++ + +error[E0703]: invalid ABI: found `C++` + --> $DIR/exhaustive.rs:472:23 + | +LL | unsafe extern "C++" {} + | ^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error: `..` patterns are not allowed here + --> $DIR/exhaustive.rs:679:13 + | +LL | let ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:794:16 + | +LL | let _: T() -> !; + | ^^^^^^^^ only `Fn` traits may use parentheses + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:809:16 + | +LL | let _: impl Send; + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:810:16 + | +LL | let _: impl Send + 'static; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:811:16 + | +LL | let _: impl 'static + Send; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:812:16 + | +LL | let _: impl ?Sized; + | ^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:813:16 + | +LL | let _: impl ~const Clone; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:814:16 + | +LL | let _: impl for<'a> Send; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0214, E0562, E0697, E0703, E0728. +For more information about an error, try `rustc --explain E0214`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout new file mode 100644 index 000000000000..d2c379d43662 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -0,0 +1,700 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail +//@ edition:2024 + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. + +#![feature(auto_traits)]#![feature(box_patterns)]#![feature(builtin_syntax)]#![feature(concat_idents)]#![feature(const_trait_impl)]#![feature(decl_macro)]#![feature(deref_patterns)]#![feature(dyn_star)]#![feature(explicit_tail_calls)]#![feature(gen_blocks)]#![feature(more_qualified_paths)]#![feature(never_patterns)]#![feature(never_type)]#![feature(pattern_types)]#![feature(pattern_type_macro)]#![feature(prelude_import)]#![feature(specialization)]#![feature(trace_macros)]#![feature(trait_alias)]#![feature(try_blocks)]#![feature(yeet_expr)]#![allow(incomplete_features)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; + +#[prelude_import] +use self::prelude::*; + +mod prelude { + use std::prelude::rust_2024::*; + + type T = _; + + trait Trait { + const + CONST: + (); + } +} + +//! inner single-line doc comment +/*! + * inner multi-line doc comment + */ +#[doc = "inner doc attribute"]#[allow(dead_code, unused_variables)]#[no_std] +mod attributes {//! inner single-line doc comment + /*! + * inner multi-line doc comment + */ + #![doc = + "inner doc attribute"]#![allow(dead_code, unused_variables)]#![no_std] + + /// outer single-line doc comment + /** + * outer multi-line doc comment + */ + #[doc = + "outer doc attribute"]#[doc = "macro"]#[allow()]#[attr = Repr([ReprC])] + struct Struct; +} + +mod expressions { + /// ExprKind::Array + fn expr_array() { + []; + [true]; + [true]; + [true, true]; + ["long........................................................................"]; + ["long............................................................", + true]; + } + + /// ExprKind::ConstBlock + fn expr_const_block() { + const { }; + const { 1 }; + const + { + struct S; + }; + } + + /// ExprKind::Call + fn expr_call() { + let f; + f(); + f::(); + f::<1>(); + f::<'static, u8, 1>(); + f(true); + f(true); + ()(); + } + + /// ExprKind::MethodCall + fn expr_method_call() { + let x; + x.f(); + x.f::(); + x.collect::>(); + } + + /// ExprKind::Tup + fn expr_tup() { (); (true,); (true, false); (true, false); } + + /// ExprKind::Binary + fn expr_binary() { + let (a, b, c, d, x, y); + true || false; + true || false && false; + a < 1 && 2 < b && c > 3 && 4 > d; + a & b & !c; + a + b * c - d + -1 * -2 - -3; + x = !y; + } + + /// ExprKind::Unary + fn expr_unary() { let expr; *expr; !expr; -expr; } + + /// ExprKind::Lit + fn expr_lit() { 'x'; 1000i8; 1.00000000000000000000001; } + + /// ExprKind::Cast + fn expr_cast() { let expr; expr as T; expr as T; } + + /// ExprKind::Type + fn expr_type() { let expr; type_ascribe!(expr, T); } + + /// ExprKind::Let + fn expr_let() { + let b; + if let Some(a) = b { } + if let _ = true && false { } + if let _ = (true && false) { } + } + + /// ExprKind::If + fn expr_if() { + if true { } + if !true { } + if let true = true { } else { } + if true { } else if false { } + if true { } else if false { } else { } + if true { return; } else if false { 0 } else { 0 } + } + + /// ExprKind::While + fn expr_while() { + loop { if false { } else { break; } } + 'a: loop { if false { } else { break; } } + loop { if let true = true { } else { break; } } + } + + /// ExprKind::ForLoop + fn expr_for_loop() { + let x; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + }; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + 'a: + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + } + } + + /// ExprKind::Loop + fn expr_loop() { loop { } 'a: loop { } } + + /// ExprKind::Match + fn expr_match() { + let value; + match value { } + match value { ok => 1, } + match value { ok => 1, err => 0, } + } + + /// ExprKind::Closure + fn expr_closure() { + let value; + || { }; + |x| { }; + |x: u8| { }; + || (); + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || value; + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || -> u8 { value }; + 1 + (|| { }); + } + + /// ExprKind::Block + fn expr_block() { + { } + unsafe { } + 'a: { } + #[allow()] + { } + #[allow()] + { } + } + + /// ExprKind::Gen + fn expr_gen() { + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + || { }; + move || { }; + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + } + + /// ExprKind::Await + fn expr_await() { + let fut; + { + fut; + (/*ERROR*/) + }; + } + + /// ExprKind::TryBlock + fn expr_try_block() { + { #[lang = "from_output"](()) } + { return; #[lang = "from_output"](()) } + } + + /// ExprKind::Assign + fn expr_assign() { let expr; expr = true; } + + /// ExprKind::AssignOp + fn expr_assign_op() { let expr; expr += true; } + + /// ExprKind::Field + fn expr_field() { let expr; expr.field; expr.0; } + + /// ExprKind::Index + fn expr_index() { let expr; expr[true]; } + + /// ExprKind::Range + fn expr_range() { + let (lo, hi); + #[lang = "RangeFull"] { }; + #[lang = "RangeTo"] { end: hi }; + #[lang = "RangeFrom"] { start: lo }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "RangeToInclusive"] { end: hi }; + #[lang = "range_inclusive_new"](lo, hi); + #[lang = "range_inclusive_new"](-2, -1); + } + + /// ExprKind::Underscore + fn expr_underscore() { + (/*ERROR*/); + } + + /// ExprKind::Path + fn expr_path() { + let x; + crate::expressions::expr_path; + crate::expressions::expr_path::<'static>; + ::default; + ::default; + x; + x::; + crate::expressions::expr_path; + core::marker::PhantomData; + } + + /// ExprKind::AddrOf + fn expr_addr_of() { + let expr; + &expr; + &mut expr; + &raw const expr; + &raw mut expr; + } + + /// ExprKind::Break + fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } } + + /// ExprKind::Continue + fn expr_continue() { 'a: { continue; continue 'a; } } + + /// ExprKind::Ret + fn expr_ret() { return; return true; } + + + /// ExprKind::InlineAsm: see exhaustive-asm.rs + /// ExprKind::OffsetOf + fn expr_offset_of() { + + + + + + + + + + + + + + // ... + + + + + + // concat_idents is deprecated + + + + + { offset_of!(T, field) }; + } + /// ExprKind::MacCall + fn expr_mac_call() { "..."; "..."; "..."; } + /// ExprKind::Struct + fn expr_struct() { + struct Struct { + } + let (x, base); + Struct { }; + ::Owned { }; + Struct { .. }; + Struct { ..base }; + Struct { x }; + Struct { x, ..base }; + Struct { x: true }; + Struct { x: true, .. }; + Struct { x: true, ..base }; + Struct { 0: true, ..base }; + } + /// ExprKind::Repeat + fn expr_repeat() { [(); 0]; } + /// ExprKind::Paren + fn expr_paren() { let expr; expr; } + /// ExprKind::Try + fn expr_try() { + let expr; + match #[lang = "branch"](expr) { + #[lang = "Break"] { 0: residual } => + #[allow(unreachable_code)] + return #[lang = "from_residual"](residual), + #[lang = "Continue"] { 0: val } => #[allow(unreachable_code)] + val, + }; + } + /// ExprKind::Yield + fn expr_yield() { yield (); yield true; } + /// ExprKind::Yeet + fn expr_yeet() { + return #[lang = "from_yeet"](()); + return #[lang = "from_yeet"](0); + } + /// ExprKind::Become + fn expr_become() { become true; } + /// ExprKind::IncludedBytes + fn expr_include_bytes() { + b"data for include_bytes in ../expanded-exhaustive.rs\n"; + } + /// ExprKind::FormatArgs + fn expr_format_args() { + let expr; + format_arguments::new_const(&[]); + format_arguments::new_v1(&[""], + &[format_argument::new_display(&expr)]); + } +} +mod items { + /// ItemKind::ExternCrate + mod item_extern_crate {/// ItemKind::ExternCrate + extern crate core; + extern crate self as unpretty; + extern crate core as _; + } + /// ItemKind::Use + mod item_use {/// ItemKind::Use + use ::{}; + use crate::expressions; + use crate::items::item_use; + use core::*; + } + /// ItemKind::Static + mod item_static {/// ItemKind::Static + static A: () = { }; + static mut B: () = { }; + } + /// ItemKind::Const + mod item_const {/// ItemKind::Const + const A: () = { }; + trait TraitItems { + const + B: + (); + const + C: + () + = + { }; + } + } + /// ItemKind::Fn + mod item_fn {/// ItemKind::Fn + const unsafe extern "C" fn f() { } + async unsafe extern "C" fn g() + -> + /*impl Trait*/ |mut _task_context: ResumeTy| + { { let _t = { }; _t } } + fn h<'a, T>() where T: 'a { } + trait TraitItems { + unsafe extern "C" fn f(); + } + impl TraitItems for _ { + unsafe extern "C" fn f() { } + } + } + /// ItemKind::Mod + mod item_mod {/// ItemKind::Mod + } + /// ItemKind::ForeignMod + mod item_foreign_mod {/// ItemKind::ForeignMod + extern "Rust" { } + extern "C" { } + } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + mod item_ty_alias {/// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + type Type<'a> where T: 'a = T; + } + /// ItemKind::Enum + mod item_enum {/// ItemKind::Enum + enum Void { } + enum Empty { + Unit, + Tuple(), + Struct { + }, + } + enum Generic<'a, T> where T: 'a { + Tuple(T), + Struct { + t: T, + }, + } + } + /// ItemKind::Struct + mod item_struct {/// ItemKind::Struct + struct Unit; + struct Tuple(); + struct Newtype(Unit); + struct Struct { + } + struct Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Union + mod item_union {/// ItemKind::Union + union Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Trait + mod item_trait {/// ItemKind::Trait + auto unsafe trait Send { } + trait Trait<'a>: Sized where Self: 'a { } + } + /// ItemKind::TraitAlias + mod item_trait_alias {/// ItemKind::TraitAlias + trait Trait = Sized where for<'a> T: 'a; + } + /// ItemKind::Impl + mod item_impl {/// ItemKind::Impl + impl () { } + impl () { } + impl Default for () { } + impl const Default for () { } + } + /// ItemKind::MacCall + mod item_mac_call {/// ItemKind::MacCall + } + /// ItemKind::MacroDef + mod item_macro_def {/// ItemKind::MacroDef + macro_rules! mac { () => {...}; } + macro stringify { () => {} } + } + /// ItemKind::Delegation + /*! FIXME: todo */ + mod item_delegation {/// ItemKind::Delegation + /*! FIXME: todo */ + } + /// ItemKind::DelegationMac + /*! FIXME: todo */ + mod item_delegation_mac {/// ItemKind::DelegationMac + /*! FIXME: todo */ + } +} +mod patterns { + /// PatKind::Missing + fn pat_missing() { let _: for fn(u32, T, &'_ str); } + /// PatKind::Wild + fn pat_wild() { let _; } + /// PatKind::Ident + fn pat_ident() { + let x; + let ref x; + let mut x; + let ref mut x; + let ref mut x@_; + } + /// PatKind::Struct + fn pat_struct() { + let T {}; + let T:: {}; + let T::<'static> {}; + let T { x }; + let T { x: _x }; + let T { .. }; + let T { x, .. }; + let T { x: _x, .. }; + let T { 0: _x, .. }; + let ::Owned {}; + } + /// PatKind::TupleStruct + fn pat_tuple_struct() { + struct Tuple(); + let Tuple(); + let Tuple::(); + let Tuple::<'static>(); + let Tuple(x); + let Tuple(..); + let Tuple(x, ..); + } + /// PatKind::Or + fn pat_or() { let true | false; let true; let true | false; } + /// PatKind::Path + fn pat_path() { + let core::marker::PhantomData; + let core::marker::PhantomData::; + let core::marker::PhantomData::<'static>; + let ::CONST; + } + /// PatKind::Tuple + fn pat_tuple() { let (); let (true,); let (true, false); } + /// PatKind::Box + fn pat_box() { let box pat; } + /// PatKind::Deref + fn pat_deref() { let deref!(pat); } + /// PatKind::Ref + fn pat_ref() { let &pat; let &mut pat; } + /// PatKind::Expr + fn pat_expr() { let 1000i8; let -""; } + /// PatKind::Range + fn pat_range() { let ..1; let 0...; let 0..1; let 0...1; let -2...-1; } + /// PatKind::Slice + fn pat_slice() { let []; let [true]; let [true]; let [true, false]; } + /// PatKind::Rest + fn pat_rest() { let _; } + /// PatKind::Never + fn pat_never() { let !; let Some(!); } + /// PatKind::Paren + fn pat_paren() { let pat; } + /// PatKind::MacCall + fn pat_mac_call() { let ""; let ""; let ""; } +} +mod statements { + /// StmtKind::Let + fn stmt_let() { + let _; + let _ = true; + let _: T = true; + let _ = true else { return; }; + } + /// StmtKind::Item + fn stmt_item() { + struct Struct { + } + struct Unit; + } + /// StmtKind::Expr + fn stmt_expr() { () } + /// StmtKind::Semi + fn stmt_semi() { 1 + 1; } + /// StmtKind::Empty + fn stmt_empty() { } + /// StmtKind::MacCall + fn stmt_mac_call() { "..."; "..."; "..."; } +} +mod types { + /// TyKind::Slice + fn ty_slice() { let _: [T]; } + /// TyKind::Array + fn ty_array() { let _: [T; 0]; } + /// TyKind::Ptr + fn ty_ptr() { let _: *const T; let _: *mut T; } + /// TyKind::Ref + fn ty_ref() { + let _: &T; + let _: &mut T; + let _: &'static T; + let _: &'static mut [T]; + let _: &T>>>; + let _: &T>>>; + } + /// TyKind::BareFn + fn ty_bare_fn() { + let _: fn(); + let _: fn() -> (); + let _: fn(T); + let _: fn(t: T); + let _: fn(); + let _: for<'a> fn(); + } + /// TyKind::Never + fn ty_never() { let _: !; } + /// TyKind::Tup + fn ty_tup() { let _: (); let _: (T,); let _: (T, T); } + /// TyKind::Path + fn ty_path() { + let _: T; + let _: T<'static>; + let _: T; + let _: T; + let _: T; + let _: ::Owned; + } + /// TyKind::TraitObject + fn ty_trait_object() { + let _: dyn Send; + let _: dyn Send + 'static; + let _: dyn Send + 'static; + let _: dyn for<'a> Send; + let _: dyn* Send; + } + /// TyKind::ImplTrait + const fn ty_impl_trait() { + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + } + /// TyKind::Paren + fn ty_paren() { let _: T; } + /// TyKind::Typeof + /*! unused for now */ + fn ty_typeof() { } + /// TyKind::Infer + fn ty_infer() { let _: _; } + /// TyKind::ImplicitSelf + /*! there is no syntax for this */ + fn ty_implicit_self() { } + /// TyKind::MacCall + #[expect(deprecated)] + fn ty_mac_call() { let _: T; let _: T; let _: T; } + /// TyKind::CVarArgs + /*! FIXME: todo */ + fn ty_c_var_args() { } + /// TyKind::Pat + fn ty_pat() { let _: u32 is 1..=RangeMax; } +} +mod visibilities { + /// VisibilityKind::Public + mod visibility_public {/// VisibilityKind::Public + struct Pub; + } + /// VisibilityKind::Restricted + mod visibility_restricted {/// VisibilityKind::Restricted + struct PubCrate; + struct PubSelf; + struct PubSuper; + struct PubInCrate; + struct PubInSelf; + struct PubInSuper; + struct PubInCrateVisibilities; + struct PubInSelfSuper; + struct PubInSuperMod; + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/exhaustive.rs similarity index 90% rename from tests/ui/unpretty/expanded-exhaustive.rs rename to tests/ui/unpretty/exhaustive.rs index 5697f615b979..60ad3564689d 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -1,6 +1,12 @@ -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -202,8 +208,8 @@ mod expressions { move || value; async || value; async move || value; - static || value; - static move || value; + static || value; //[hir]~ ERROR closures cannot be static + static move || value; //[hir]~ ERROR closures cannot be static (static async || value); (static async move || value); || -> u8 { value }; @@ -232,7 +238,7 @@ mod expressions { /// ExprKind::Await fn expr_await() { let fut; - fut.await; + fut.await; //[hir]~ ERROR `await` is only allowed } /// ExprKind::TryBlock @@ -281,7 +287,7 @@ mod expressions { /// ExprKind::Underscore fn expr_underscore() { - _; + _; //[hir]~ ERROR in expressions, `_` can only } /// ExprKind::Path @@ -291,10 +297,14 @@ mod expressions { crate::expressions::expr_path::<'static>; ::default; ::default::<>; - x::(); - x::(T, T) -> T; + x::(); //[hir]~ ERROR parenthesized type parameters + x::(T, T) -> T; //[hir]~ ERROR parenthesized type parameters crate::() -> ()::expressions::() -> ()::expr_path; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters core::()::marker::()::PhantomData; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters } /// ExprKind::AddrOf @@ -330,18 +340,7 @@ mod expressions { return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - core::arch::asm!( - "mov {tmp}, {x}", - "shl {tmp}, 1", - "shl {x}, 2", - "add {x}, {tmp}", - x = inout(reg) x, - tmp = out(reg) _, - ); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -390,7 +389,7 @@ mod expressions { /// ExprKind::Yield fn expr_yield() { - yield; + yield; //[hir]~ ERROR `yield` can only be used yield true; } @@ -470,14 +469,11 @@ mod items { /// ItemKind::ForeignMod mod item_foreign_mod { - unsafe extern "C++" {} + unsafe extern "C++" {} //[hir]~ ERROR invalid ABI unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - core::arch::global_asm!(".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { @@ -680,7 +676,7 @@ mod patterns { /// PatKind::Rest fn pat_rest() { - let ..; + let ..; //[hir]~ ERROR `..` patterns are not allowed here } /// PatKind::Never @@ -795,7 +791,7 @@ mod types { let _: T<'static>; let _: T; let _: T::; - let _: T() -> !; + let _: T() -> !; //[hir]~ ERROR parenthesized type parameters let _: ::Owned; } @@ -810,12 +806,12 @@ mod types { /// TyKind::ImplTrait const fn ty_impl_trait() { - let _: impl Send; - let _: impl Send + 'static; - let _: impl 'static + Send; - let _: impl ?Sized; - let _: impl ~const Clone; - let _: impl for<'a> Send; + let _: impl Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl Send + 'static; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl 'static + Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ?Sized; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ~const Clone; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl for<'a> Send; //[hir]~ ERROR `impl Trait` is not allowed } /// TyKind::Paren diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/interpolation-expanded.rs similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.rs rename to tests/ui/unpretty/interpolation-expanded.rs diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/interpolation-expanded.stdout similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.stdout rename to tests/ui/unpretty/interpolation-expanded.stdout From 360012f41a7521f8a1bd488f015b5342e989aab8 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Fri, 2 May 2025 13:22:05 +1000 Subject: [PATCH 140/302] Amend language regarding the never type --- library/std/src/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b8eb0fd104c3..b6a9ba012902 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2415,8 +2415,7 @@ mod while_keyword {} /// a return from the parent function; rather, they cause the `Future` returned by the block to /// return with that value. /// -/// For example, the following Rust function will return `5`, assigning the `!` value to `x`, which -/// goes unused: +/// For example, the following Rust function will return `5`, causing `x` to take the [`!` type][never type]: /// ```rust /// #[expect(unused_variables)] /// fn example() -> i32 { @@ -2455,6 +2454,7 @@ mod while_keyword {} /// [async book]: https://rust-lang.github.io/async-book/ /// [`return`]: ../std/keyword.return.html /// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [never type]: ../reference/types/never.html /// [`Result`]: result::Result /// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {} From 042a556d8d0247361ed97e5d9217bb477c487be3 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Thu, 3 Apr 2025 17:25:46 -0700 Subject: [PATCH 141/302] Change signature of File::try_lock and File::try_lock_shared These methods now return Result<(), TryLockError> instead of Result to make their use less errorprone --- library/std/src/fs.rs | 66 +++++++++++++++++++++++---- library/std/src/fs/tests.rs | 36 +++++++++++---- library/std/src/sys/fs/hermit.rs | 11 +++-- library/std/src/sys/fs/solid.rs | 11 +++-- library/std/src/sys/fs/uefi.rs | 5 +- library/std/src/sys/fs/unix.rs | 39 ++++++++++------ library/std/src/sys/fs/unsupported.rs | 5 +- library/std/src/sys/fs/wasi.rs | 11 +++-- library/std/src/sys/fs/windows.rs | 17 +++---- 9 files changed, 140 insertions(+), 61 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 801baf3d9907..27f60ffb00c8 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -116,6 +116,22 @@ pub struct File { inner: fs_imp::File, } +/// An enumeration of possible errors which can occur while trying to acquire a lock +/// from the [`try_lock`] method and [`try_lock_shared`] method on a [`File`]. +/// +/// [`try_lock`]: File::try_lock +/// [`try_lock_shared`]: File::try_lock_shared +#[unstable(feature = "file_lock", issue = "130994")] +pub enum TryLockError { + /// The lock could not be acquired due to an I/O error on the file. The standard library will + /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] + /// + /// [`ErrorKind::WouldBlock`]: io::ErrorKind::WouldBlock + Error(io::Error), + /// The lock could not be acquired at this time because it is held by another handle/process. + WouldBlock, +} + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -352,6 +368,27 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result inner(path.as_ref(), contents.as_ref()) } +#[unstable(feature = "file_lock", issue = "130994")] +impl fmt::Debug for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TryLockError::Error(err) => err.fmt(f), + TryLockError::WouldBlock => "WouldBlock".fmt(f), + } + } +} + +#[unstable(feature = "file_lock", issue = "130994")] +impl fmt::Display for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TryLockError::Error(_) => "lock acquisition failed due to I/O error", + TryLockError::WouldBlock => "lock acquisition failed because the operation would block", + } + .fmt(f) + } +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -734,8 +771,8 @@ impl File { /// Try to acquire an exclusive lock on the file. /// - /// Returns `Ok(false)` if a different lock is already held on this file (via another - /// handle/descriptor). + /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file + /// (via another handle/descriptor). /// /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. /// @@ -777,23 +814,27 @@ impl File { /// /// ```no_run /// #![feature(file_lock)] - /// use std::fs::File; + /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { /// let f = File::create("foo.txt")?; - /// f.try_lock()?; + /// match f.try_lock() { + /// Ok(_) => (), + /// Err(TryLockError::WouldBlock) => (), // Lock not acquired + /// Err(TryLockError::Error(err)) => return Err(err), + /// } /// Ok(()) /// } /// ``` #[unstable(feature = "file_lock", issue = "130994")] - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.inner.try_lock() } /// Try to acquire a shared (non-exclusive) lock on the file. /// - /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another - /// handle/descriptor). + /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file + /// (via another handle/descriptor). /// /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may /// hold an exclusive lock at the same time. @@ -834,16 +875,21 @@ impl File { /// /// ```no_run /// #![feature(file_lock)] - /// use std::fs::File; + /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { /// let f = File::open("foo.txt")?; - /// f.try_lock_shared()?; + /// match f.try_lock_shared() { + /// Ok(_) => (), + /// Err(TryLockError::WouldBlock) => (), // Lock not acquired + /// Err(TryLockError::Error(err)) => return Err(err), + /// } + /// /// Ok(()) /// } /// ``` #[unstable(feature = "file_lock", issue = "130994")] - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.inner.try_lock_shared() } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 4712e58980cc..46b0d832fec4 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,6 +1,22 @@ use rand::RngCore; +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +use crate::assert_matches::assert_matches; use crate::char::MAX_LEN_UTF8; +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +use crate::fs::TryLockError; use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; @@ -223,8 +239,8 @@ fn file_lock_multiple_shared() { check!(f2.lock_shared()); check!(f1.unlock()); check!(f2.unlock()); - assert!(check!(f1.try_lock_shared())); - assert!(check!(f2.try_lock_shared())); + check!(f1.try_lock_shared()); + check!(f2.try_lock_shared()); } #[test] @@ -243,12 +259,12 @@ fn file_lock_blocking() { // Check that shared locks block exclusive locks check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); check!(f1.unlock()); // Check that exclusive locks block shared locks check!(f1.lock()); - assert!(!check!(f2.try_lock_shared())); + assert_matches!(f2.try_lock_shared(), Err(TryLockError::WouldBlock)); } #[test] @@ -267,9 +283,9 @@ fn file_lock_drop() { // Check that locks are released when the File is dropped check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); drop(f1); - assert!(check!(f2.try_lock())); + check!(f2.try_lock()); } #[test] @@ -288,10 +304,10 @@ fn file_lock_dup() { // Check that locks are not dropped if the File has been cloned check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); let cloned = check!(f1.try_clone()); drop(f1); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); drop(cloned) } @@ -307,9 +323,9 @@ fn file_lock_double_unlock() { // Check that both are released by unlock() check!(f1.lock()); check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); check!(f1.unlock()); - assert!(check!(f2.try_lock())); + check!(f2.try_lock()); } #[test] diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index f83a2f90ed22..d5412b2dda53 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,4 +1,5 @@ use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ @@ -12,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; pub use crate::sys::fs::common::{copy, exists}; use crate::sys::pal::fd::FileDesc; use crate::sys::time::SystemTime; -use crate::sys::{cvt, unsupported}; +use crate::sys::{cvt, unsupported, unsupported_err}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, mem}; @@ -366,12 +367,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index 39de933b7248..3bfb39bac95b 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -2,6 +2,7 @@ use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::MaybeUninit; use crate::os::raw::{c_int, c_short}; @@ -11,7 +12,7 @@ use crate::sync::Arc; pub use crate::sys::fs::common::exists; use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; -use crate::sys::unsupported; +use crate::sys::{unsupported, unsupported_err}; use crate::sys_common::ignore_notfound; type CIntNotMinusOne = core::num::niche_types::NotAllOnes; @@ -352,12 +353,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index d6ae86bd3d26..416c90b98b6d 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -2,6 +2,7 @@ use r_efi::protocols::file; use crate::ffi::OsString; use crate::fmt; +use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; @@ -227,11 +228,11 @@ impl File { self.0 } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.0 } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.0 } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 87865be0387d..9f27542849f6 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -74,6 +74,7 @@ use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, st use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt::{self, Write as _}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::os::unix::prelude::*; @@ -1307,15 +1308,17 @@ impl File { target_os = "netbsd", target_vendor = "apple", ))] - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); - if let Err(ref err) = result { + if let Err(err) = result { if err.kind() == io::ErrorKind::WouldBlock { - return Ok(false); + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) } + } else { + Ok(()) } - result?; - return Ok(true); } #[cfg(not(any( @@ -1325,8 +1328,11 @@ impl File { target_os = "netbsd", target_vendor = "apple", )))] - pub fn try_lock(&self) -> io::Result { - Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock() not supported" + ))) } #[cfg(any( @@ -1336,15 +1342,17 @@ impl File { target_os = "netbsd", target_vendor = "apple", ))] - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); - if let Err(ref err) = result { + if let Err(err) = result { if err.kind() == io::ErrorKind::WouldBlock { - return Ok(false); + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) } + } else { + Ok(()) } - result?; - return Ok(true); } #[cfg(not(any( @@ -1354,8 +1362,11 @@ impl File { target_os = "netbsd", target_vendor = "apple", )))] - pub fn try_lock_shared(&self) -> io::Result { - Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock_shared() not supported" + ))) } #[cfg(any( diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index 45e93deffa3a..0ff9533c0473 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -1,5 +1,6 @@ use crate::ffi::OsString; use crate::fmt; +use crate::fs::TryLockError; use crate::hash::{Hash, Hasher}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; @@ -206,11 +207,11 @@ impl File { self.0 } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.0 } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.0 } diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index 773040571bc9..ebfc7377a2ea 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -1,4 +1,5 @@ use crate::ffi::{CStr, OsStr, OsString}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; @@ -10,7 +11,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::WasiFd; pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; -use crate::sys::unsupported; +use crate::sys::{unsupported, unsupported_err}; use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; use crate::{fmt, iter, ptr}; @@ -461,12 +462,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 15727c996837..6e54153325fb 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -3,6 +3,7 @@ use crate::alloc::{Layout, alloc, dealloc}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit, offset_of}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; @@ -397,7 +398,7 @@ impl File { self.acquire_lock(0) } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { let mut overlapped = mem::zeroed(); c::LockFileEx( @@ -411,18 +412,18 @@ impl File { }); match result { - Ok(_) => Ok(true), + Ok(_) => Ok(()), Err(err) if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { - Ok(false) + Err(TryLockError::WouldBlock) } - Err(err) => Err(err), + Err(err) => Err(TryLockError::Error(err)), } } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { let mut overlapped = mem::zeroed(); c::LockFileEx( @@ -436,14 +437,14 @@ impl File { }); match result { - Ok(_) => Ok(true), + Ok(_) => Ok(()), Err(err) if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { - Ok(false) + Err(TryLockError::WouldBlock) } - Err(err) => Err(err), + Err(err) => Err(TryLockError::Error(err)), } } From 1d11ee2a5b84693ac37173b4515e5411e76cad82 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Sun, 6 Apr 2025 08:39:10 -0700 Subject: [PATCH 142/302] Implement error::Error for TryLockError --- library/std/src/fs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 27f60ffb00c8..a1d4354d4fd4 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -21,7 +21,6 @@ mod tests; use crate::ffi::OsString; -use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sealed::Sealed; @@ -29,6 +28,7 @@ use crate::sync::Arc; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; +use crate::{error, fmt}; /// An object providing access to an open file on the filesystem. /// @@ -368,6 +368,9 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result inner(path.as_ref(), contents.as_ref()) } +#[unstable(feature = "file_lock", issue = "130994")] +impl error::Error for TryLockError {} + #[unstable(feature = "file_lock", issue = "130994")] impl fmt::Debug for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 0ea204a5ff39564b51bf9710c45ead44f9796c28 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 28 Apr 2025 06:33:22 +1000 Subject: [PATCH 143/302] Add useful comments on `ExprKind::If` variants. Things that aren't obvious and took me a while to work out. --- compiler/rustc_ast/src/ast.rs | 3 +++ compiler/rustc_hir/src/hir.rs | 3 +++ compiler/rustc_middle/src/thir.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9d216ef3dd84..114b9835b98c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1633,6 +1633,9 @@ pub enum ExprKind { /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` + /// + /// If present, the "else" expr is always `ExprKind::Block` (for `else`) or + /// `ExprKind::If` (for `else if`). If(P, P, Option>), /// A while loop, with an optional label. /// diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af587ee5bdcd..0e6b21588ee9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2730,6 +2730,9 @@ pub enum ExprKind<'hir> { /// An `if` block, with an optional else block. /// /// I.e., `if { } else { }`. + /// + /// The "then" expr is always `ExprKind::Block`. If present, the "else" expr is always + /// `ExprKind::Block` (for `else`) or `ExprKind::If` (for `else if`). If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>), /// A conditionless loop (can be exited with `break`, `continue`, or `return`). /// diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 086ec529f33a..b9a014d14c0d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -292,7 +292,10 @@ pub enum ExprKind<'tcx> { If { if_then_scope: region::Scope, cond: ExprId, + /// `then` is always `ExprKind::Block`. then: ExprId, + /// If present, the `else_opt` expr is always `ExprKind::Block` (for + /// `else`) or `ExprKind::If` (for `else if`). else_opt: Option, }, /// A function call. Method calls and overloaded operators are converted to plain function calls. From e2d2c56b2e01ce25c9cceeaf9e460415d9d0fa31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 May 2025 09:50:28 +0200 Subject: [PATCH 144/302] add ./miri squash --- src/tools/miri/CONTRIBUTING.md | 10 ++- src/tools/miri/miri-script/src/commands.rs | 75 +++++++++++++++++++++- src/tools/miri/miri-script/src/main.rs | 9 ++- 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 0d77ca06e1b4..739f0702252a 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -19,12 +19,10 @@ When you get a review, please take care of the requested changes in new commits. existing commits. Generally avoid force-pushing. The only time you should force push is when there is a conflict with the master branch (in that case you should rebase across master, not merge), and all the way at the end of the review process when the reviewer tells you that the PR is done and you -should squash the commits. For the latter case, use `git rebase --keep-base ...` to squash without -changing the base commit your PR branches off of. Use your own judgment and the reviewer's guidance -to decide whether the PR should be squashed into a single commit or multiple logically separate -commits. (All this is to work around the fact that Github is quite bad at dealing with force pushes -and does not support `git range-diff`. Maybe one day Github will be good at git and then life can -become easier.) +should squash the commits. If you are unsure how to use `git rebase` to squash commits, use `./miri +squash` which automates the process but leaves little room for customization. (All this is to work +around the fact that Github is quite bad at dealing with force pushes and does not support `git +range-diff`. Maybe one day Github will be good at git and then life can become easier.) Most PRs bounce back and forth between the reviewer and the author several times, so it is good to keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 17a7c06b5253..1c9750e2cbdc 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use std::ffi::{OsStr, OsString}; -use std::fs::File; -use std::io::{BufReader, BufWriter, Write}; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::{self, BufRead, BufReader, BufWriter, Write as _}; use std::ops::Not; use std::path::PathBuf; use std::time::Duration; @@ -169,7 +170,8 @@ impl Command { | Command::Toolchain { .. } | Command::Bench { .. } | Command::RustcPull { .. } - | Command::RustcPush { .. } => {} + | Command::RustcPush { .. } + | Command::Squash => {} } // Then run the actual command. match self { @@ -188,6 +190,7 @@ impl Command { Command::Toolchain { flags } => Self::toolchain(flags), Command::RustcPull { commit } => Self::rustc_pull(commit.clone()), Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch), + Command::Squash => Self::squash(), } } @@ -383,6 +386,72 @@ impl Command { Ok(()) } + fn squash() -> Result<()> { + let sh = Shell::new()?; + sh.change_dir(miri_dir()?); + // Figure out base wrt latest upstream master. + // (We can't trust any of the local ones, they can all be outdated.) + let origin_master = { + cmd!(sh, "git fetch https://github.com/rust-lang/miri/") + .quiet() + .ignore_stdout() + .ignore_stderr() + .run()?; + cmd!(sh, "git rev-parse FETCH_HEAD").read()? + }; + let base = cmd!(sh, "git merge-base HEAD {origin_master}").read()?; + // Rebase onto that, setting ourselves as the sequence editor so that we can edit the sequence programmatically. + // We want to forward the host stdin so apparently we cannot use `cmd!`. + let mut cmd = process::Command::new("git"); + cmd.arg("rebase").arg(&base).arg("--interactive"); + cmd.env("GIT_SEQUENCE_EDITOR", env::current_exe()?); + cmd.env("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR", "1"); + cmd.current_dir(sh.current_dir()); + let result = cmd.status()?; + if !result.success() { + bail!("`git rebase` failed"); + } + Ok(()) + } + + pub fn squash_sequence_editor() -> Result<()> { + let sequence_file = env::args().nth(1).expect("git should pass us a filename"); + if sequence_file == "fmt" { + // This is probably us being called as a git hook as part of the rebase. Let's just + // ignore this. Sadly `git rebase` does not have a flag to skip running hooks. + return Ok(()); + } + // Read the provided sequence and adjust it. + let rebase_sequence = { + let mut rebase_sequence = String::new(); + let file = fs::File::open(&sequence_file).with_context(|| { + format!("failed to read rebase sequence from {sequence_file:?}") + })?; + let file = io::BufReader::new(file); + for line in file.lines() { + let line = line?; + // The first line is left unchanged. + if rebase_sequence.is_empty() { + writeln!(rebase_sequence, "{line}").unwrap(); + continue; + } + // If this is a "pick" like, make it "squash". + if let Some(rest) = line.strip_prefix("pick ") { + writeln!(rebase_sequence, "squash {rest}").unwrap(); + continue; + } + // We've reached the end of the relevant part of the sequence, and we can stop. + break; + } + rebase_sequence + }; + // Write out the adjusted sequence. + fs::write(&sequence_file, rebase_sequence).with_context(|| { + format!("failed to write adjusted rebase sequence to {sequence_file:?}") + })?; + Ok(()) + } + fn bench( target: Option, no_install: bool, diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 279bdf8cc3f4..6aab2f79bd78 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -133,6 +133,8 @@ pub enum Command { #[arg(default_value = "miri-sync")] branch: String, }, + /// Squash the commits of the current feature branch into one. + Squash, } impl Command { @@ -154,7 +156,7 @@ impl Command { flags.extend(remainder); Ok(()) } - Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => + Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } | Self::Squash => bail!("unexpected \"--\" found in arguments"), } } @@ -170,6 +172,11 @@ pub struct Cli { } fn main() -> Result<()> { + // If we are invoked as the git sequence editor, jump to that logic. + if !std::env::var_os("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR").unwrap_or_default().is_empty() { + return Command::squash_sequence_editor(); + } + // Split the arguments into the part before the `--` and the part after. // The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); From a9cd0a9f03c9737274170db0a1a421183b63b66f Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 2 May 2025 15:53:51 +0900 Subject: [PATCH 145/302] Add regression test for 133065 --- tests/ui/traits/trait-impl-self-mismatch.rs | 19 +++++++++++++++++++ .../ui/traits/trait-impl-self-mismatch.stderr | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/traits/trait-impl-self-mismatch.rs create mode 100644 tests/ui/traits/trait-impl-self-mismatch.stderr diff --git a/tests/ui/traits/trait-impl-self-mismatch.rs b/tests/ui/traits/trait-impl-self-mismatch.rs new file mode 100644 index 000000000000..54226cf2c9ad --- /dev/null +++ b/tests/ui/traits/trait-impl-self-mismatch.rs @@ -0,0 +1,19 @@ +//@compile-flags: -Zvalidate-mir -Zinline-mir -Zinline-mir-threshold=300 + +//! Ensure that a trait method implemented with the wrong signature +//! correctly triggers a compile error and not an ICE. +//! Regression test for . + +trait Bar { + fn bar(&self) {} +} + +impl Bar for T { + fn bar() { //~ ERROR method `bar` has a `&self` declaration in the trait, but not in the impl + let _ = "Hello".bytes().nth(3); + } +} + +fn main() { + ().bar(); +} diff --git a/tests/ui/traits/trait-impl-self-mismatch.stderr b/tests/ui/traits/trait-impl-self-mismatch.stderr new file mode 100644 index 000000000000..4ee06787c7d8 --- /dev/null +++ b/tests/ui/traits/trait-impl-self-mismatch.stderr @@ -0,0 +1,12 @@ +error[E0186]: method `bar` has a `&self` declaration in the trait, but not in the impl + --> $DIR/trait-impl-self-mismatch.rs:12:5 + | +LL | fn bar(&self) {} + | ------------- `&self` used in trait +... +LL | fn bar() { + | ^^^^^^^^ expected `&self` in impl + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0186`. From 6970813e78a1d0f4298859471aaafece5e674a33 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Thu, 1 May 2025 18:40:38 +0200 Subject: [PATCH 146/302] Use less rustc_type_ir in the compiler codebase This commit does the following: - Replaces use of rustc_type_ir by rustc_middle in rustc_infer. - The DelayedMap type is exposed by rustc_middle so everything can be accessed through rustc_middle in a coherent manner. - API-layer traits, like InferCtxtLike, Interner or inherent::* must be accessed via rustc_type_ir, not rustc_middle::ty. For this reason these are not reexported by rustc_middle::ty. - Replaces use of ty::Interner by rustc_type_ir::Interner in rustc_trait_selection --- Cargo.lock | 1 + compiler/rustc_infer/src/infer/context.rs | 26 +++++++------------ .../src/infer/outlives/obligations.rs | 2 +- .../rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_infer/src/infer/relate/mod.rs | 5 ++-- .../src/infer/relate/type_relating.rs | 3 +-- compiler/rustc_infer/src/infer/resolve.rs | 3 +-- .../rustc_infer/src/infer/snapshot/fudge.rs | 3 +-- compiler/rustc_infer/src/traits/util.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 10 ++++++- compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/solve/delegate.rs | 6 ++--- 12 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 361d237b3af8..60daa453c60d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4494,6 +4494,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_transmute", + "rustc_type_ir", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 75affa139770..22d7ce79bb46 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -121,19 +121,19 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.enter_forall(value, f) } - fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { self.inner.borrow_mut().type_variables().equate(a, b); } - fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) { + fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) { self.inner.borrow_mut().int_unification_table().union(a, b); } - fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) { + fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid) { self.inner.borrow_mut().float_unification_table().union(a, b); } - fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) { + fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid) { self.inner.borrow_mut().const_unification_table().union(a, b); } @@ -141,8 +141,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, relation: &mut R, target_is_expected: bool, - target_vid: rustc_type_ir::TyVid, - instantiation_variance: rustc_type_ir::Variance, + target_vid: ty::TyVid, + instantiation_variance: ty::Variance, source_ty: Ty<'tcx>, ) -> RelateResult<'tcx, ()> { self.instantiate_ty_var( @@ -154,19 +154,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { ) } - fn instantiate_int_var_raw( - &self, - vid: rustc_type_ir::IntVid, - value: rustc_type_ir::IntVarValue, - ) { + fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue) { self.inner.borrow_mut().int_unification_table().union_value(vid, value); } - fn instantiate_float_var_raw( - &self, - vid: rustc_type_ir::FloatVid, - value: rustc_type_ir::FloatVarValue, - ) { + fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue) { self.inner.borrow_mut().float_unification_table().union_value(vid, value); } @@ -174,7 +166,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, relation: &mut R, target_is_expected: bool, - target_vid: rustc_type_ir::ConstVid, + target_vid: ty::ConstVid, source_ct: ty::Const<'tcx>, ) -> RelateResult<'tcx, ()> { self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a89cef50c9b4..8dde99c45cfa 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -63,11 +63,11 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; +use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt, }; -use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::smallvec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c14c288c6e4e..69feecfe30a4 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; +use rustc_middle::ty::outlives::{Component, compute_alias_components_recursive}; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; -use rustc_type_ir::outlives::{Component, compute_alias_components_recursive}; use smallvec::smallvec; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index e6d1003cab61..6d25dfeb8593 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -2,9 +2,8 @@ //! (except for some relations used for diagnostics and heuristics in the compiler). //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). -pub use rustc_middle::ty::relate::RelateResult; -pub use rustc_type_ir::relate::combine::PredicateEmittingRelation; -pub use rustc_type_ir::relate::*; +pub use rustc_middle::ty::relate::combine::PredicateEmittingRelation; +pub use rustc_middle::ty::relate::{RelateResult, *}; mod generalize; mod higher_ranked; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 009271a8378f..04ff776594e6 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -3,9 +3,8 @@ use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys} use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, }; -use rustc_middle::ty::{self, Ty, TyCtxt, TyVar}; +use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar}; use rustc_span::Span; -use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; use crate::infer::BoundRegionConversionTime::HigherRankedType; diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 245f1a4ac5ed..4b0ace8c554d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,9 +1,8 @@ use rustc_middle::bug; use rustc_middle::ty::{ - self, Const, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, + self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; -use rustc_type_ir::data_structures::DelayedMap; use super::{FixupError, FixupResult, InferCtxt}; diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 39c8c40ea7d8..e210479581ba 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -3,9 +3,8 @@ use std::ops::Range; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; use rustc_middle::ty::{ self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, - TypeSuperFoldable, + TypeSuperFoldable, TypeVisitableExt, }; -use rustc_type_ir::TypeVisitableExt; use tracing::instrument; use ut::UnifyKey; diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 66ed49fe3267..6461fbe0d33b 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; +pub use rustc_middle::ty::elaborate::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Ident, Span}; -pub use rustc_type_ir::elaborate::*; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2f4c03f0953d..053845e3d69d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -50,9 +50,17 @@ use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; -pub use rustc_type_ir::data_structures::DelayedSet; +pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; +#[allow( + hidden_glob_reexports, + rustc::usage_of_type_ir_inherent, + rustc::non_glob_import_of_type_ir_inherent +)] +use rustc_type_ir::inherent; pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; +#[allow(hidden_glob_reexports, unused_imports)] +use rustc_type_ir::{InferCtxtLike, Interner}; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index a5cc8d9ea012..1c61e23362a8 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -21,6 +21,7 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2" tracing = "0.1" diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index ef64da131891..908c058aabec 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -156,9 +156,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn register_hidden_type_in_storage( &self, opaque_type_key: ty::OpaqueTypeKey<'tcx>, - hidden_ty: ::Ty, - span: ::Span, - ) -> Option<::Ty> { + hidden_ty: ::Ty, + span: ::Span, + ) -> Option<::Ty> { self.0.register_hidden_type_in_storage( opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty }, From 6f1a54bad27c49071efc11bcdb57f1bf152f7cb9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 May 2025 11:16:56 +0200 Subject: [PATCH 147/302] Remove fragile equal-pointers-unequal tests. These randomly break when i change the implementation of format_args!(). --- .../equal-pointers-unequal/as-cast/basic.rs | 21 ---------------- .../as-cast/function.rs | 22 ----------------- .../equal-pointers-unequal/as-cast/print.rs | 20 ---------------- .../exposed-provenance/basic.rs | 23 ------------------ .../exposed-provenance/function.rs | 24 ------------------- .../exposed-provenance/print.rs | 22 ----------------- .../strict-provenance/basic.rs | 23 ------------------ .../strict-provenance/function.rs | 24 ------------------- .../strict-provenance/print.rs | 22 ----------------- 9 files changed, 201 deletions(-) delete mode 100644 tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs deleted file mode 100644 index e2a00ce173d1..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -fn main() { - let a: usize = { - let v = 0u8; - &v as *const _ as usize - }; - let b: usize = { - let v = 0u8; - &v as *const _ as usize - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs deleted file mode 100644 index 15434de50f76..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -fn f() -> usize { - let v = 0; - &v as *const _ as usize -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs deleted file mode 100644 index f33a9e511b61..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -fn main() { - let a = { - let v = 0; - &v as *const _ as usize - }; - let b = { - let v = 0; - &v as *const _ as usize - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs deleted file mode 100644 index b2b4934aa5f1..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0u8; - ptr::from_ref(&v).expose_provenance() - }; - let b: usize = { - let v = 0u8; - ptr::from_ref(&v).expose_provenance() - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs deleted file mode 100644 index bf130c9f7598..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -use std::ptr; - -fn f() -> usize { - let v = 0; - ptr::from_ref(&v).expose_provenance() -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs deleted file mode 100644 index 0baf8886395e..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs deleted file mode 100644 index 4602ec654d10..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0u8; - ptr::from_ref(&v).addr() - }; - let b: usize = { - let v = 0u8; - ptr::from_ref(&v).addr() - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs deleted file mode 100644 index 789a78c15b4e..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -use std::ptr; - -fn f() -> usize { - let v = 0; - ptr::from_ref(&v).addr() -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs deleted file mode 100644 index b7165ce1e5ce..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} From ddff38703a3e56b26f5a73d56208a8adab5daae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 2 May 2025 12:24:47 +0200 Subject: [PATCH 148/302] Rename parameter to `override_def_path_data` --- compiler/rustc_middle/src/ty/context.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fffbf0513482..66ba39761ee1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1957,10 +1957,11 @@ impl<'tcx> TyCtxtAt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, - def_path_data: Option, + override_def_path_data: Option, disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let feed = self.tcx.create_def(parent, name, def_kind, def_path_data, disambiguator); + let feed = + self.tcx.create_def(parent, name, def_kind, override_def_path_data, disambiguator); feed.def_span(self.span); feed @@ -1974,10 +1975,10 @@ impl<'tcx> TyCtxt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, - def_path_data: Option, + override_def_path_data: Option, disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let data = def_path_data.unwrap_or_else(|| def_kind.def_path_data(name)); + let data = override_def_path_data.unwrap_or_else(|| def_kind.def_path_data(name)); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to // decode the on-disk cache. From 2f2d3c887063d41cf361f58b34c0e0b48c83398f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Apr 2025 15:17:33 +0200 Subject: [PATCH 149/302] forbidden target feature tests: consolidate multiple tests in a single one with revisions --- ...dfloat-target-feature-flag-disable-implied.rs | 15 --------------- ...hardfloat-target-feature-flag-disable-neon.rs | 13 ------------- ...t-target-feature-flag-disable.aarch64.stderr} | 0 ...dden-hardfloat-target-feature-flag-disable.rs | 16 +++++++++++----- ...rget-feature-flag-disable.x86-implied.stderr} | 0 ...float-target-feature-flag-disable.x86.stderr} | 0 6 files changed, 11 insertions(+), 33 deletions(-) delete mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs delete mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable-neon.stderr => forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable-implied.stderr => forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable.stderr => forbidden-hardfloat-target-feature-flag-disable.x86.stderr} (100%) diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs deleted file mode 100644 index 12e7e3bc45b3..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Ensure that if disabling a target feature implies disabling an ABI-required target feature, -//! we complain. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-sse -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs deleted file mode 100644 index 33e4f12694f3..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: aarch64 -//@ compile-flags: -Ctarget-feature=-neon -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `neon` must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs index e1bd25ffad1e..e0d095844fbb 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs @@ -1,7 +1,13 @@ //! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-x87 +//! Also covers the case of a feature indirectly disabling another via feature implications. +//@ compile-flags: --crate-type=lib +//@ revisions: x86 x86-implied aarch64 +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-x87 +//@[x86] needs-llvm-components: x86 +//@[x86-implied] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-sse +//@[x86-implied] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -Ctarget-feature=-neon +//@[aarch64] needs-llvm-components: aarch64 // For now this is just a warning. //@ build-pass @@ -11,5 +17,5 @@ #[lang = "sized"] pub trait Sized {} -//~? WARN target feature `x87` must be enabled to ensure that the ABI of the current target can be implemented correctly -//~? WARN unstable feature specified for `-Ctarget-feature`: `x87` +//~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly +//[x86]~? WARN unstable feature specified for `-Ctarget-feature` diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86.stderr From 7a2d51dc29c0184bc97a373231634e07d6f1f0f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Apr 2025 15:22:14 +0200 Subject: [PATCH 150/302] give the abi-relevant target feature tests better names --- ...tribute.rs => abi-incompatible-target-feature-attribute.rs} | 0 ...stderr => abi-incompatible-target-feature-attribute.stderr} | 2 +- ...-flag.rs => abi-incompatible-target-feature-flag-enable.rs} | 0 ...derr => abi-incompatible-target-feature-flag-enable.stderr} | 0 ...isable.rs => abi-irrelevant-target-feature-flag-disable.rs} | 3 +++ ...tderr => abi-irrelevant-target-feature-flag-disable.stderr} | 0 ...e-attribute.rs => abi-required-target-feature-attribute.rs} | 2 ++ ...=> abi-required-target-feature-flag-disable.aarch64.stderr} | 0 ...-disable.rs => abi-required-target-feature-flag-disable.rs} | 0 ...bi-required-target-feature-flag-disable.x86-implied.stderr} | 0 ...err => abi-required-target-feature-flag-disable.x86.stderr} | 0 11 files changed, 6 insertions(+), 1 deletion(-) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.rs => abi-incompatible-target-feature-attribute.rs} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.stderr => abi-incompatible-target-feature-attribute.stderr} (78%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag.rs => abi-incompatible-target-feature-flag-enable.rs} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag.stderr => abi-incompatible-target-feature-flag-enable.stderr} (100%) rename tests/ui/target-feature/{allowed-softfloat-target-feature-flag-disable.rs => abi-irrelevant-target-feature-flag-disable.rs} (59%) rename tests/ui/target-feature/{allowed-softfloat-target-feature-flag-disable.stderr => abi-irrelevant-target-feature-flag-disable.stderr} (100%) rename tests/ui/target-feature/{allowed-softfloat-target-feature-attribute.rs => abi-required-target-feature-attribute.rs} (69%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr => abi-required-target-feature-flag-disable.aarch64.stderr} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable.rs => abi-required-target-feature-flag-disable.rs} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr => abi-required-target-feature-flag-disable.x86-implied.stderr} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-flag-disable.x86.stderr => abi-required-target-feature-flag-disable.x86.stderr} (100%) diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs rename to tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr similarity index 78% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr rename to tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr index bfe767e5ffb0..baa8551b17a3 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr @@ -1,5 +1,5 @@ error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18 + --> $DIR/abi-incompatible-target-feature-attribute.rs:10:18 | LL | #[target_feature(enable = "d")] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs rename to tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr rename to tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.stderr diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs similarity index 59% rename from tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs rename to tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs index 7368ef120fa6..0013d033b9c5 100644 --- a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs @@ -1,3 +1,6 @@ +//! `x87` is a required target feature on some x86 targets, but not on this one as this one +//! uses soft-floats. So ensure disabling the target feature here (which is a NOP) does +//! not trigger a warning. //@ compile-flags: --target=x86_64-unknown-none --crate-type=lib //@ needs-llvm-components: x86 //@ compile-flags: -Ctarget-feature=-x87 diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.stderr similarity index 100% rename from tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.stderr rename to tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.stderr diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs b/tests/ui/target-feature/abi-required-target-feature-attribute.rs similarity index 69% rename from tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs rename to tests/ui/target-feature/abi-required-target-feature-attribute.rs index 8b60820cc9b6..95723c57f94d 100644 --- a/tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs +++ b/tests/ui/target-feature/abi-required-target-feature-attribute.rs @@ -1,3 +1,5 @@ +//! Enabling a target feature that is anyway required changes nothing, so this is allowed +//! for `#[target_feature]`. //@ compile-flags: --target=x86_64-unknown-none --crate-type=lib //@ needs-llvm-components: x86 //@ build-pass diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.aarch64.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.aarch64.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.aarch64.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.x86-implied.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86-implied.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.x86-implied.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.x86.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.x86.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.x86.stderr From efc51ce993f27cfb192e37f936941ff613846b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 2 May 2025 13:17:47 +0200 Subject: [PATCH 151/302] Add `DefPathData::NestedStatic` instead of reusing `DefPathData::AnonConst` --- compiler/rustc_const_eval/src/interpret/intern.rs | 7 +++---- compiler/rustc_hir/src/def.rs | 3 --- compiler/rustc_hir/src/definitions.rs | 6 +++++- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 1 + compiler/rustc_symbol_mangling/src/v0.rs | 1 + 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index adf2c255d089..47cc2d49fe27 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -17,14 +17,13 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; -use rustc_hir::definitions::DisambiguatorState; +use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; use rustc_middle::query::TyCtxtAt; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; -use rustc_span::sym; use tracing::{instrument, trace}; use super::{ @@ -108,9 +107,9 @@ fn intern_as_new_static<'tcx>( ) { let feed = tcx.create_def( static_id, - Some(sym::nested), - DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, None, + DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, + Some(DefPathData::NestedStatic), disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 5872ec5aedf2..507c94aca8b9 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -273,9 +273,6 @@ impl DefKind { // but those provide their own DefPathData. DefKind::AssocTy => DefPathData::TypeNs(name.unwrap()), - // It's not exactly an anon const, but wrt DefPathData, there - // is no difference. - DefKind::Static { nested: true, .. } => DefPathData::AnonConst, DefKind::Fn | DefKind::Const | DefKind::ConstParam diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index d66775cd20b0..74ef2f5557c8 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -313,6 +313,8 @@ pub enum DefPathData { AnonAssocTy(Symbol), /// A synthetic body for a coroutine's by-move body. SyntheticCoroutineBody, + /// Additional static data referred to by a static. + NestedStatic, } impl Definitions { @@ -455,7 +457,8 @@ impl DefPathData { | Ctor | AnonConst | OpaqueTy - | SyntheticCoroutineBody => None, + | SyntheticCoroutineBody + | NestedStatic => None, } } @@ -477,6 +480,7 @@ impl DefPathData { OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc }, SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, + NestedStatic => DefPathDataName::Anon { namespace: sym::nested }, } } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index ed32c34bb4b5..f7f354d12e8c 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -717,6 +717,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { hir::definitions::DefPathData::AnonConst => "k", hir::definitions::DefPathData::OpaqueTy => "i", hir::definitions::DefPathData::SyntheticCoroutineBody => "s", + hir::definitions::DefPathData::NestedStatic => "n", hir::definitions::DefPathData::CrateRoot | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 12aa876045c4..22c3955fa73f 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -851,6 +851,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { DefPathData::AnonConst => 'k', DefPathData::OpaqueTy => 'i', DefPathData::SyntheticCoroutineBody => 's', + DefPathData::NestedStatic => 'n', // These should never show up as `path_append` arguments. DefPathData::CrateRoot From d16daf5cbaed54758eaf928ee3f63528c2da6efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 2 May 2025 13:37:22 +0200 Subject: [PATCH 152/302] Add comment about the symbol on `AnonAssocTy` --- compiler/rustc_hir/src/definitions.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 74ef2f5557c8..1a0af38517a5 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -309,7 +309,8 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, - /// An anonymous associated type from an RPITIT. + /// An anonymous associated type from an RPITIT. The symbol refers to the name of the method + /// that defined the type. AnonAssocTy(Symbol), /// A synthetic body for a coroutine's by-move body. SyntheticCoroutineBody, From 4869e20e26c113165a3db23a3f7ad0ed2dc0463f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 2 May 2025 13:40:49 +0200 Subject: [PATCH 153/302] Split `get_opt_name` hashing use into `hashed_symbol` --- compiler/rustc_hir/src/definitions.rs | 22 +++++++++++++++++++- compiler/rustc_middle/src/ty/print/pretty.rs | 4 ---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 1a0af38517a5..98b41187f114 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -145,7 +145,7 @@ impl DefKey { let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; std::mem::discriminant(data).hash(&mut hasher); - if let Some(name) = data.get_opt_name() { + if let Some(name) = data.hashed_symbol() { // Get a stable hash by considering the symbol chars rather than // the symbol index. name.as_str().hash(&mut hasher); @@ -443,6 +443,26 @@ pub enum DefPathDataName { impl DefPathData { pub fn get_opt_name(&self) -> Option { + use self::DefPathData::*; + match *self { + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + + Impl + | ForeignMod + | CrateRoot + | Use + | GlobalAsm + | Closure + | Ctor + | AnonConst + | OpaqueTy + | AnonAssocTy(..) + | SyntheticCoroutineBody + | NestedStatic => None, + } + } + + fn hashed_symbol(&self) -> Option { use self::DefPathData::*; match *self { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f589c7df6285..1df3bff52442 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -391,10 +391,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let visible_parent_map = self.tcx().visible_parent_map(()); let kind = self.tcx().def_kind(def_id); - if let DefPathData::AnonAssocTy(..) = key.disambiguated_data.data { - return Ok(false); - } - let get_local_name = |this: &Self, name, def_id, key: DefKey| { if let Some(visible_parent) = visible_parent_map.get(&def_id) && let actual_parent = this.tcx().opt_parent(def_id) From 6873a46626fef5f8f95488272fc605b4847d011e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Apr 2025 15:40:44 +0200 Subject: [PATCH 154/302] add more revisions to cover more architectures --- ...ible-target-feature-attribute.riscv.stderr | 8 +++++++ ...i-incompatible-target-feature-attribute.rs | 13 ++++++++---- ...compatible-target-feature-attribute.stderr | 8 ------- ...atible-target-feature-attribute.x86.stderr | 8 +++++++ ...le-target-feature-flag-enable.riscv.stderr | 19 +++++++++++++++++ ...incompatible-target-feature-flag-enable.rs | 21 ++++++++++++------- ...ble-target-feature-flag-enable.x86.stderr} | 0 ...rget-feature-flag-disable.loongarch.stderr | 11 ++++++++++ ...d-target-feature-flag-disable.riscv.stderr | 11 ++++++++++ ...bi-required-target-feature-flag-disable.rs | 10 +++++++-- 10 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr delete mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr create mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr create mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr rename tests/ui/target-feature/{abi-incompatible-target-feature-flag-enable.stderr => abi-incompatible-target-feature-flag-enable.x86.stderr} (100%) create mode 100644 tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr create mode 100644 tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr new file mode 100644 index 000000000000..49c5479275f3 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr @@ -0,0 +1,8 @@ +error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/abi-incompatible-target-feature-attribute.rs:15:90 + | +LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs index 215e64979f73..a87334407592 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs @@ -1,12 +1,17 @@ //! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. -//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib -//@ needs-llvm-components: riscv -#![feature(no_core, lang_items, riscv_target_feature)] +// ignore-tidy-linelength +//@ compile-flags: --crate-type=lib +//@ revisions: x86 riscv +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu +//@[x86] needs-llvm-components: x86 +//@[riscv] compile-flags: --target=riscv32e-unknown-none-elf +//@[riscv] needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature, x87_target_feature)] #![no_core] #[lang = "sized"] pub trait Sized {} -#[target_feature(enable = "d")] +#[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] //~^ERROR: cannot be enabled with pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr deleted file mode 100644 index baa8551b17a3..000000000000 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/abi-incompatible-target-feature-attribute.rs:10:18 - | -LL | #[target_feature(enable = "d")] - | ^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr new file mode 100644 index 000000000000..81471fd7e303 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr @@ -0,0 +1,8 @@ +error: target feature `soft-float` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/abi-incompatible-target-feature-attribute.rs:15:32 + | +LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr new file mode 100644 index 000000000000..2dca0c220332 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr @@ -0,0 +1,19 @@ +warning: target feature `d` must be disabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `f` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `zicsr` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 4 warnings emitted + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs index 4ccc6e0e941f..68e1d3b9ddc6 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs @@ -1,15 +1,22 @@ //! Ensure ABI-incompatible features cannot be enabled via `-Ctarget-feature`. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=+soft-float -// For now this is just a warning. -//@ build-pass +// These are just warnings for now. +//@ check-pass +//@ compile-flags: --crate-type=lib +//@ revisions: x86 riscv +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=+soft-float +//@[x86] needs-llvm-components: x86 +//@[riscv] compile-flags: --target=riscv32e-unknown-none-elf -Ctarget-feature=+d +//@[riscv] needs-llvm-components: riscv #![feature(no_core, lang_items, riscv_target_feature)] #![no_core] #[lang = "sized"] pub trait Sized {} +#[lang = "freeze"] +pub trait Freeze {} -//~? WARN target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctl -//~? WARN unstable feature specified for `-Ctarget-feature`: `soft-float` +//~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly +//~? WARN unstable feature specified for `-Ctarget-feature` +//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` +//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr similarity index 100% rename from tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.stderr rename to tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr new file mode 100644 index 000000000000..35102e0571f4 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr @@ -0,0 +1,11 @@ +warning: target feature `d` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 2 warnings emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr new file mode 100644 index 000000000000..35102e0571f4 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr @@ -0,0 +1,11 @@ +warning: target feature `d` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 2 warnings emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs index e0d095844fbb..c3ce05baa64b 100644 --- a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs @@ -1,15 +1,21 @@ //! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`. //! Also covers the case of a feature indirectly disabling another via feature implications. //@ compile-flags: --crate-type=lib -//@ revisions: x86 x86-implied aarch64 +//@ revisions: x86 x86-implied aarch64 riscv loongarch //@[x86] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-x87 //@[x86] needs-llvm-components: x86 //@[x86-implied] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-sse //@[x86-implied] needs-llvm-components: x86 //@[aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -Ctarget-feature=-neon //@[aarch64] needs-llvm-components: aarch64 +//@[riscv] compile-flags: --target=riscv64gc-unknown-none-elf -Ctarget-feature=-d +//@[riscv] needs-llvm-components: riscv +//@[loongarch] compile-flags: --target=loongarch64-unknown-none -Ctarget-feature=-d +//@[loongarch] needs-llvm-components: loongarch // For now this is just a warning. //@ build-pass +// Remove some LLVM warnings that only show up sometimes. +//@ normalize-stderr: "\n[^\n]*(target-abi|lp64f)[^\n]*" -> "" #![feature(no_core, lang_items)] #![no_core] @@ -18,4 +24,4 @@ pub trait Sized {} //~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly -//[x86]~? WARN unstable feature specified for `-Ctarget-feature` +//[x86,riscv,loongarch]~? WARN unstable feature specified for `-Ctarget-feature` From ce4d3958501eaa0dd6bc00b57d2c569f06225957 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 May 2025 14:25:27 +0200 Subject: [PATCH 155/302] Update sysinfo version to `0.35.0` --- src/bootstrap/Cargo.lock | 145 +++++++++++++++++++++++++++++++++++---- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 131 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index d415668f54a7..cdad3bd46fab 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "walkdir", - "windows", + "windows 0.57.0", "xz2", ] @@ -158,12 +158,6 @@ dependencies = [ "cc", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "cpufeatures" version = "0.2.15" @@ -440,6 +434,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.36.5" @@ -700,15 +713,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46" +checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "windows", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.1", ] [[package]] @@ -927,22 +941,67 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core", + "windows-core 0.57.0", "windows-targets", ] +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.0", +] + [[package]] name = "windows-core" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -954,6 +1013,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.57.0" @@ -965,6 +1035,33 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -974,6 +1071,24 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 712a9b04c1a1..e34de924cc18 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -58,7 +58,7 @@ walkdir = "2.4" xz2 = "0.1" # Dependencies needed by the build-metrics feature -sysinfo = { version = "0.33.0", default-features = false, optional = true, features = ["system"] } +sysinfo = { version = "0.35.0", default-features = false, optional = true, features = ["system"] } # Dependencies needed by the `tracing` feature tracing = { version = "0.1", optional = true, features = ["attributes"] } From fbfc3297955faa53d62b480f91a0a7d10918bbf3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 May 2025 14:27:27 +0200 Subject: [PATCH 156/302] Update sysinfo to `0.35.0` in `src/tools/opt-dist` --- Cargo.lock | 101 ++++++++++++---------------------- src/tools/opt-dist/Cargo.toml | 2 +- 2 files changed, 35 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 361d237b3af8..5ea2f885cca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -747,7 +747,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows 0.59.0", + "windows", ] [[package]] @@ -2466,6 +2466,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.32.2" @@ -3469,7 +3488,7 @@ dependencies = [ "thorin-dwp", "tracing", "wasm-encoder 0.219.2", - "windows 0.59.0", + "windows", ] [[package]] @@ -3528,7 +3547,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -3591,7 +3610,7 @@ dependencies = [ "serde_json", "shlex", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -3646,7 +3665,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -4389,7 +4408,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -5071,13 +5090,14 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.31.4" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" +checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" dependencies = [ - "core-foundation-sys", "libc", - "windows 0.57.0", + "objc2-core-foundation", + "objc2-io-kit", + "windows", ] [[package]] @@ -5952,16 +5972,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.59.0" @@ -5983,18 +5993,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.59.0" @@ -6002,8 +6000,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ "windows-implement 0.59.0", - "windows-interface 0.59.1", - "windows-result 0.3.2", + "windows-interface", + "windows-result", "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -6015,23 +6013,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-interface", "windows-link", - "windows-result 0.3.2", + "windows-result", "windows-strings 0.4.0", ] -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "windows-implement" version = "0.59.0" @@ -6054,17 +6041,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -6082,15 +6058,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.2" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index cea234cc74cb..b0db8346f7ed 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -10,7 +10,7 @@ log = "0.4" anyhow = "1" humantime = "2" humansize = "2" -sysinfo = { version = "0.31.2", default-features = false, features = ["disk"] } +sysinfo = { version = "0.35.0", default-features = false, features = ["disk"] } fs_extra = "1" camino = "1" tar = "0.4" From f20e853e65b7b957c5d829c506cef3ab88ad5a9a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 14 Apr 2025 10:17:22 +0200 Subject: [PATCH 157/302] Render more lifetimes --- .../crates/hir-ty/src/display.rs | 69 ++++++++++++++-- .../crates/hir-ty/src/tests/coercion.rs | 6 +- .../hir-ty/src/tests/display_source_code.rs | 18 ++--- .../hir-ty/src/tests/method_resolution.rs | 8 +- .../crates/hir-ty/src/tests/regression.rs | 4 +- .../crates/hir-ty/src/tests/simple.rs | 10 +-- .../crates/hir-ty/src/tests/traits.rs | 78 +++++++++---------- .../src/handlers/convert_closure_to_fn.rs | 6 +- .../src/handlers/extract_function.rs | 2 +- .../src/handlers/extract_variable.rs | 28 +++---- .../src/handlers/generate_function.rs | 8 +- .../crates/ide-assists/src/tests/generated.rs | 2 +- .../ide-completion/src/tests/expression.rs | 2 +- .../ide-completion/src/tests/special.rs | 4 +- .../ide-completion/src/tests/type_pos.rs | 18 ++--- .../src/handlers/expected_function.rs | 2 +- .../src/handlers/invalid_cast.rs | 6 +- .../src/handlers/type_mismatch.rs | 7 +- .../src/handlers/typed_hole.rs | 2 +- .../src/handlers/unresolved_method.rs | 2 +- .../crates/ide/src/hover/tests.rs | 42 +++++----- .../crates/ide/src/inlay_hints/bind_pat.rs | 20 ++--- .../ide/src/inlay_hints/closing_brace.rs | 2 +- .../rust-analyzer/tests/slow-tests/main.rs | 4 +- 24 files changed, 201 insertions(+), 149 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index e810467b994a..f0989d9de91f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -90,11 +90,26 @@ pub struct HirFormatter<'a> { show_container_bounds: bool, omit_verbose_types: bool, closure_style: ClosureStyle, + display_lifetimes: DisplayLifetime, display_kind: DisplayKind, display_target: DisplayTarget, bounds_formatting_ctx: BoundsFormattingCtx, } +// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should +// not be when in signatures +// So this enum does not encode this well enough +// Also 'static can be omitted for ref and dyn trait lifetimes in static/const item types +// FIXME: Also named lifetimes may be rendered in places where their name is not in scope? +#[derive(Copy, Clone)] +pub enum DisplayLifetime { + Always, + OnlyStatic, + OnlyNamed, + OnlyNamedOrStatic, + Never, +} + #[derive(Default)] enum BoundsFormattingCtx { Entered { @@ -155,6 +170,21 @@ impl HirFormatter<'_> { } } } + + fn render_lifetime(&self, lifetime: &Lifetime) -> bool { + match self.display_lifetimes { + DisplayLifetime::Always => true, + DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static), + DisplayLifetime::OnlyNamed => { + matches!(***lifetime.interned(), LifetimeData::Placeholder(_)) + } + DisplayLifetime::OnlyNamedOrStatic => matches!( + ***lifetime.interned(), + LifetimeData::Static | LifetimeData::Placeholder(_) + ), + DisplayLifetime::Never => false, + } + } } pub trait HirDisplay { @@ -189,6 +219,7 @@ pub trait HirDisplay { display_kind, closure_style, show_container_bounds, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -212,6 +243,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -236,6 +268,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -260,6 +293,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -284,6 +318,7 @@ pub trait HirDisplay { display_target: DisplayTarget::from_crate(db, module_id.krate()), display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque }, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, bounds_formatting_ctx: Default::default(), }) { Ok(()) => {} @@ -312,6 +347,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Test, show_container_bounds: false, + display_lifetimes: DisplayLifetime::Always, } } @@ -336,6 +372,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } } @@ -480,6 +517,7 @@ pub struct HirDisplayWrapper<'a, T> { display_kind: DisplayKind, display_target: DisplayTarget, show_container_bounds: bool, + display_lifetimes: DisplayLifetime, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -502,7 +540,7 @@ impl HirDisplayWrapper<'_, T> { self.t.hir_fmt(&mut HirFormatter { db: self.db, fmt: f, - buf: String::with_capacity(20), + buf: String::with_capacity(self.max_size.unwrap_or(20)), curr_size: 0, max_size: self.max_size, entity_limit: self.limited_size, @@ -511,6 +549,7 @@ impl HirDisplayWrapper<'_, T> { display_target: self.display_target, closure_style: self.closure_style, show_container_bounds: self.show_container_bounds, + display_lifetimes: self.display_lifetimes, bounds_formatting_ctx: Default::default(), }) } @@ -519,6 +558,11 @@ impl HirDisplayWrapper<'_, T> { self.closure_style = c; self } + + pub fn with_lifetime_display(mut self, l: DisplayLifetime) -> Self { + self.display_lifetimes = l; + self + } } impl fmt::Display for HirDisplayWrapper<'_, T> @@ -1022,9 +1066,7 @@ impl HirDisplay for Ty { kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => { if let TyKind::Ref(_, l, _) = kind { f.write_char('&')?; - if cfg!(test) { - // rendering these unconditionally is probably too much (at least for inlay - // hints) so we gate it to testing only for the time being + if f.render_lifetime(l) { l.hir_fmt(f)?; f.write_char(' ')?; } @@ -1055,9 +1097,10 @@ impl HirDisplay for Ty { }) }; let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) { - TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => { + TyKind::Dyn(dyn_ty) => { let bounds = dyn_ty.bounds.skip_binders().interned(); - (bounds.len(), contains_impl_fn(bounds)) + let render_lifetime = f.render_lifetime(&dyn_ty.lifetime); + (bounds.len() + render_lifetime as usize, contains_impl_fn(bounds)) } TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, @@ -1479,7 +1522,7 @@ impl HirDisplay for Ty { TyKind::BoundVar(idx) => idx.hir_fmt(f)?, TyKind::Dyn(dyn_ty) => { // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation. - // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it + // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it // more efficient when either of them hits stable. let mut bounds: SmallVec<[_; 4]> = dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect(); @@ -1488,6 +1531,17 @@ impl HirDisplay for Ty { bounds.extend(others); bounds.extend(auto_traits); + if f.render_lifetime(&dyn_ty.lifetime) { + // we skip the binders in `write_bounds_like_dyn_trait_with_prefix` + bounds.push(Binders::empty( + Interner, + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: self.clone(), + lifetime: dyn_ty.lifetime.clone(), + }), + )); + } + write_bounds_like_dyn_trait_with_prefix( f, "dyn", @@ -1989,7 +2043,6 @@ impl HirDisplay for LifetimeData { write!(f, "{}", param_data.name.display(f.db, f.edition()))?; Ok(()) } - _ if f.display_kind.is_source_code() => write!(f, "'_"), LifetimeData::BoundVar(idx) => idx.hir_fmt(f), LifetimeData::InferenceVar(_) => write!(f, "_"), LifetimeData::Static => write!(f, "'static"), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index eeaacbf12eac..ddc5b715194d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -561,7 +561,7 @@ trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; - //^ expected &'? dyn Foo, got &'? impl Foo + ?Sized + //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized } "#, ); @@ -827,11 +827,11 @@ struct V { t: T } fn main() { let a: V<&dyn Tr>; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) let mut a: V<&dyn Tr> = V { t: &S }; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index 60c03b52246c..a986b54a7b06 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -65,13 +65,13 @@ trait A { } trait B: A {} -fn test( +fn test<'a>( _: &(dyn A + Send), - //^ &'_ (dyn A + Send) - _: &(dyn Send + A), - //^ &'_ (dyn A + Send) + //^ &(dyn A + Send + 'static) + _: &'a (dyn Send + A), + //^ &'a (dyn A + Send + 'static) _: &dyn B, - //^ &'_ (dyn B) + //^ &(dyn B + 'static) ) {} "#, ); @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &'_ dyn Foo<'_> + // ^^^ &(dyn Foo<'?> + 'static) "#, ); } @@ -111,11 +111,11 @@ fn test( b; //^ impl Foo c; - //^ &'_ impl Foo + ?Sized + //^ &impl Foo + ?Sized d; //^ S ref_any; - //^^^^^^^ &'_ impl ?Sized + //^^^^^^^ &impl ?Sized empty; } //^^^^^ impl Sized "#, @@ -192,7 +192,7 @@ fn test( b; //^ fn(impl Foo) -> impl Foo c; -} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized +} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 3a258ecad10a..1f8b06fcc561 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() { 51..55 'self': &'? Self 64..69 '{ 0 }': u32 66..67 '0': u32 - 176..177 'd': &'? dyn Trait + 176..177 'd': &'? (dyn Trait + 'static) 191..207 '{ ...o(); }': () - 197..198 'd': &'? dyn Trait + 197..198 'd': &'? (dyn Trait + 'static) 197..204 'd.foo()': u32 "#]], ); @@ -2019,10 +2019,10 @@ impl dyn Error + Send { /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; - // ^^^^ expected Box, got Box + // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) - //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> + //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> } } "#, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 638306054a9d..644b0d392bcf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() { 488..522 '{ ... }': () 498..502 'self': SelectStatement 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment + 498..515 'self.o...into()': dyn QueryFragment + 'static "#]], ); } @@ -773,7 +773,7 @@ fn issue_4800() { "#, expect![[r#" 379..383 'self': &'? mut PeerSet - 401..424 '{ ... }': dyn Future + 401..424 '{ ... }': dyn Future + 'static 411..418 'loop {}': ! 416..418 '{}': () 575..579 'self': &'? mut Self diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 0f5e44151de2..eeebe38f1826 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2741,11 +2741,11 @@ impl B for Astruct {} 715..744 '#[rust...1i32])': Box<[i32; 1], Global> 737..743 '[1i32]': [i32; 1] 738..742 '1i32': i32 - 755..756 'v': Vec, Global> - 776..793 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 776..850 '<[_]> ...ct)]))': Vec, Global> - 794..849 '#[rust...uct)])': Box<[Box; 1], Global> - 816..848 '[#[rus...ruct)]': [Box; 1] + 755..756 'v': Vec, Global> + 776..793 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 776..850 '<[_]> ...ct)]))': Vec, Global> + 794..849 '#[rust...uct)])': Box<[Box; 1], Global> + 816..848 '[#[rus...ruct)]': [Box; 1] 817..847 '#[rust...truct)': Box 839..846 'Astruct': Astruct "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 2fb51acea873..14137605c9f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1475,26 +1475,26 @@ fn test(x: Box>, y: &dyn Trait) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 198..200 '{}': Box> - 210..211 'x': Box> - 234..235 'y': &'? dyn Trait + 198..200 '{}': Box + 'static> + 210..211 'x': Box + 'static> + 234..235 'y': &'? (dyn Trait + 'static) 254..371 '{ ...2(); }': () - 260..261 'x': Box> - 267..268 'y': &'? dyn Trait - 278..279 'z': Box> - 282..285 'bar': fn bar() -> Box> - 282..287 'bar()': Box> - 293..294 'x': Box> + 260..261 'x': Box + 'static> + 267..268 'y': &'? (dyn Trait + 'static) + 278..279 'z': Box + 'static> + 282..285 'bar': fn bar() -> Box + 'static> + 282..287 'bar()': Box + 'static> + 293..294 'x': Box + 'static> 293..300 'x.foo()': u64 - 306..307 'y': &'? dyn Trait + 306..307 'y': &'? (dyn Trait + 'static) 306..313 'y.foo()': u64 - 319..320 'z': Box> + 319..320 'z': Box + 'static> 319..326 'z.foo()': u64 - 332..333 'x': Box> + 332..333 'x': Box + 'static> 332..340 'x.foo2()': i64 - 346..347 'y': &'? dyn Trait + 346..347 'y': &'? (dyn Trait + 'static) 346..354 'y.foo2()': i64 - 360..361 'z': Box> + 360..361 'z': Box + 'static> 360..368 'z.foo2()': i64 "#]], ); @@ -1523,14 +1523,14 @@ fn test(s: S) { expect![[r#" 32..36 'self': &'? Self 102..106 'self': &'? S - 128..139 '{ loop {} }': &'? dyn Trait + 128..139 '{ loop {} }': &'? (dyn Trait + 'static) 130..137 'loop {}': ! 135..137 '{}': () 175..179 'self': &'? Self 251..252 's': S 267..289 '{ ...z(); }': () 273..274 's': S - 273..280 's.bar()': &'? dyn Trait + 273..280 's.bar()': &'? (dyn Trait + 'static) 273..286 's.bar().baz()': (u32, i32) "#]], ); @@ -1556,20 +1556,20 @@ fn test(x: Trait, y: &Trait) -> u64 { }"#, expect![[r#" 26..30 'self': &'? Self - 60..62 '{}': dyn Trait - 72..73 'x': dyn Trait - 82..83 'y': &'? dyn Trait + 60..62 '{}': dyn Trait + 'static + 72..73 'x': dyn Trait + 'static + 82..83 'y': &'? (dyn Trait + 'static) 100..175 '{ ...o(); }': u64 - 106..107 'x': dyn Trait - 113..114 'y': &'? dyn Trait - 124..125 'z': dyn Trait - 128..131 'bar': fn bar() -> dyn Trait - 128..133 'bar()': dyn Trait - 139..140 'x': dyn Trait + 106..107 'x': dyn Trait + 'static + 113..114 'y': &'? (dyn Trait + 'static) + 124..125 'z': dyn Trait + 'static + 128..131 'bar': fn bar() -> dyn Trait + 'static + 128..133 'bar()': dyn Trait + 'static + 139..140 'x': dyn Trait + 'static 139..146 'x.foo()': u64 - 152..153 'y': &'? dyn Trait + 152..153 'y': &'? (dyn Trait + 'static) 152..159 'y.foo()': u64 - 165..166 'z': dyn Trait + 165..166 'z': dyn Trait + 'static 165..172 'z.foo()': u64 "#]], ); @@ -1589,10 +1589,10 @@ fn main() { expect![[r#" 31..35 'self': &'? S 37..39 '{}': () - 47..48 '_': &'? dyn Fn(S) + 47..48 '_': &'? (dyn Fn(S) + 'static) 58..60 '{}': () 71..105 '{ ...()); }': () - 77..78 'f': fn f(&'? dyn Fn(S)) + 77..78 'f': fn f(&'? (dyn Fn(S) + 'static)) 77..102 'f(&|nu...foo())': () 79..101 '&|numb....foo()': &'? impl Fn(S) 80..101 '|numbe....foo()': impl Fn(S) @@ -2927,13 +2927,13 @@ fn test(x: &dyn Foo) { foo(x); }"#, expect![[r#" - 21..22 'x': &'? dyn Foo + 21..22 'x': &'? (dyn Foo + 'static) 34..36 '{}': () - 46..47 'x': &'? dyn Foo + 46..47 'x': &'? (dyn Foo + 'static) 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&'? dyn Foo) + 65..68 'foo': fn foo(&'? (dyn Foo + 'static)) 65..71 'foo(x)': () - 69..70 'x': &'? dyn Foo + 69..70 'x': &'? (dyn Foo + 'static) "#]], ); } @@ -3210,13 +3210,13 @@ fn foo() { 218..324 '{ ...&s); }': () 228..229 's': Option 232..236 'None': Option - 246..247 'f': Box)> - 281..310 'Box { ... {}) }': Box)> + 246..247 'f': Box) + 'static> + 281..310 'Box { ... {}) }': Box) + 'static> 294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option) 300..307 '|ps| {}': impl FnOnce(&'? Option) 301..303 'ps': &'? Option 305..307 '{}': () - 316..317 'f': Box)> + 316..317 'f': Box) + 'static> 316..321 'f(&s)': () 318..320 '&s': &'? Option 319..320 's': Option @@ -4252,9 +4252,9 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait = &'a i32>) + 127..128 'v': &'? (dyn Trait = &'a i32> + 'static) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait = &'a i32>) + 170..171 'v': &'? (dyn Trait = &'a i32> + 'static) 170..184 'v.get::()': &'? i32 170..192 'v.get:...eref()': &'? i32 "#]], @@ -4735,7 +4735,7 @@ pub async fn foo_async<'a>() -> Box { fn foo() { foo_async(); - //^^^^^^^^^^^impl Future> + ?Sized + //^^^^^^^^^^^impl Future> + ?Sized } "#, ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 1d3a2db3352b..43515de71e20 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -1066,7 +1066,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { *a = 1.2; let c = *b; } @@ -1098,7 +1098,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { let _: &mut bool = p2; *a = 1.2; let c = *b; @@ -1136,7 +1136,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { let _: &mut bool = p2; *a = 1.2; let c = *b; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 046af71a9dc0..e977798c4fd0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -5033,7 +5033,7 @@ fn main() { fun_name(bar); } -fn $0fun_name(bar: &str) { +fn $0fun_name(bar: &'static str) { m!(bar); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 3971b60f2532..31e84e9adcf4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -631,7 +631,7 @@ fn main() { "#, r#" fn main() { - const $0HELLO: &str = "hello"; + const $0HELLO: &'static str = "hello"; } "#, "Extract into constant", @@ -726,7 +726,7 @@ fn main() { "#, r#" fn main() { - static $0HELLO: &str = "hello"; + static $0HELLO: &'static str = "hello"; } "#, "Extract into static", @@ -2528,13 +2528,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let $0hello = "Hello"; let entry = Entry(hello); @@ -2546,13 +2546,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { const $0HELLO: &str = "Hello"; let entry = Entry(HELLO); @@ -2564,13 +2564,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { static $0HELLO: &str = "Hello"; let entry = Entry(HELLO); @@ -2587,13 +2587,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let $0message = "Hello"; let entry = Entry { message }; @@ -2605,13 +2605,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { const $0HELLO: &str = "Hello"; let entry = Entry { message: HELLO }; @@ -2623,13 +2623,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { static $0HELLO: &str = "Hello"; let entry = Entry { message: HELLO }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index aac145a72150..30084d23d1fb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -47,7 +47,7 @@ use crate::{ // bar("", baz()); // } // -// fn bar(arg: &str, baz: Baz) ${0:-> _} { +// fn bar(arg: &'static str, baz: Baz) ${0:-> _} { // todo!() // } // @@ -1518,7 +1518,7 @@ fn foo() { bar("bar") } -fn bar(arg: &str) { +fn bar(arg: &'static str) { ${0:todo!()} } "#, @@ -2135,7 +2135,7 @@ fn foo() { bar(baz(), baz(), "foo", "bar") } -fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { +fn bar(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) { ${0:todo!()} } "#, @@ -3103,7 +3103,7 @@ pub struct Foo { field_2: String, } impl Foo { - fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self { + fn new(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) -> Self { ${0:Self { field_1: todo!(), field_2: todo!() }} } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 54d060cc7909..01ab0be34b28 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1737,7 +1737,7 @@ fn foo() { bar("", baz()); } -fn bar(arg: &str, baz: Baz) ${0:-> _} { +fn bar(arg: &'static str, baz: Baz) ${0:-> _} { todo!() } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 27d6bc7b14f2..d5137949d42f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1517,7 +1517,7 @@ fn main() { en Enum Enum fn function() fn() fn main() fn() - lc variable &str + lc variable &'static str ma helper!(…) macro_rules! helper ma m!(…) macro_rules! m ma makro!(…) macro_rules! makro diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 15518e98370e..148203107c4c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -1358,7 +1358,7 @@ pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone, { 0u8 } fn main() { fo$0 } "#, CompletionItemKind::SymbolKind(ide_db::SymbolKind::Function), - expect!("fn(&mut T) -> u8"), + expect!("fn(&'x mut T) -> u8"), expect!("pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone,"), ); @@ -1391,7 +1391,7 @@ fn main() { } "#, CompletionItemKind::SymbolKind(SymbolKind::Method), - expect!("const fn(&'foo mut self, &Foo) -> !"), + expect!("const fn(&'foo mut self, &'foo Foo) -> !"), expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"), ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index c7e2d058257e..125e11e9e358 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -429,18 +429,18 @@ trait Tr { impl Tr<$0 "#, expect![[r#" - en Enum Enum - ma makro!(…) macro_rules! makro + en Enum Enum + ma makro!(…) macro_rules! makro md module - sp Self dyn Tr<{unknown}> - st Record Record - st S S - st Tuple Tuple - st Unit Unit + sp Self dyn Tr<{unknown}> + 'static + st Record Record + st S S + st Tuple Tuple + st Unit Unit tt Tr tt Trait - un Union Union - bt u32 u32 + un Union Union + bt u32 u32 kw crate:: kw self:: "#]], diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index af25c2b2e332..a6da0fd9c5e3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -31,7 +31,7 @@ fn foo() { x(); // ^^^ error: expected function, found i32 ""(); - // ^^^^ error: expected function, found &str + // ^^^^ error: expected function, found &'static str foo(); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs index b56255b1fde4..d72b21099ce3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -166,7 +166,7 @@ fn main() { let _ = ptr as bool; //^^^^^^^^^^^ error: cannot cast `*const ()` as `bool` let v = "hello" as bool; - //^^^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + //^^^^^^^^^^^^^^^ error: casting `&'static str` as `bool` is invalid: needs casting through a raw pointer first } "#, ); @@ -956,7 +956,7 @@ fn main() { fn main() { let pointer: usize = &1_i32 as *const i32 as usize; let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&i32` + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&'static i32` } "#, ); @@ -992,7 +992,7 @@ impl Deref for Foo { fn main() { let _ = "foo" as bool; - //^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + //^^^^^^^^^^^^^ error: casting `&'static str` as `bool` is invalid: needs casting through a raw pointer first let _ = Foo as bool; //^^^^^^^^^^^ error: non-primitive cast: `Foo` as `bool` diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 1db9b6d04944..500c5de791dc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -306,10 +306,9 @@ fn str_ref_to_owned( acc: &mut Vec, ) -> Option<()> { let expected = d.expected.display(ctx.sema.db, ctx.display_target); - let actual = d.actual.display(ctx.sema.db, ctx.display_target); - // FIXME do this properly - if expected.to_string() != "String" || actual.to_string() != "&str" { + let is_applicable = d.actual.strip_reference().is_str() && expected.to_string() == "String"; + if !is_applicable { return None; } @@ -1176,7 +1175,7 @@ trait B {} fn test(a: &dyn A) -> &dyn B { a - //^ error: expected &dyn B, found &dyn A + //^ error: expected &(dyn B + 'static), found &(dyn A + 'static) } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 1e7f00c23313..a933f1b42611 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -151,7 +151,7 @@ fn main() { fn main() { let mut x = t(); x = _; - //^ 💡 error: invalid `_` expression, expected type `&str` + //^ 💡 error: invalid `_` expression, expected type `&'static str` x = ""; } fn t() -> T { loop {} } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 4422d8f8262f..7f07009dc561 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -269,7 +269,7 @@ impl A { } fn main() { let a = A {a: 0, b: ""}; - A::::foo(); + A::::foo(); } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index d469cd7c0cd5..7b7eef9d5793 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -7085,9 +7085,9 @@ fn foo() { } "#, expect![[r#" - ```rust - &str - ```"#]], + ```rust + &'static str + ```"#]], ); } @@ -8228,7 +8228,7 @@ format_args!("{aaaaa$0}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8248,7 +8248,7 @@ format_args!("{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8268,7 +8268,7 @@ format_args!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8293,7 +8293,7 @@ foo!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8337,7 +8337,7 @@ fn main() { expect![[r#" *"🦀\u{1f980}\\\x41"* ```rust - &str + &'static str ``` ___ @@ -8353,7 +8353,7 @@ fn main() { expect![[r#" *r"🦀\u{1f980}\\\x41"* ```rust - &str + &'static str ``` ___ @@ -8375,7 +8375,7 @@ fsdghs"; fsdghs"* ```rust - &str + &'static str ``` ___ @@ -8395,7 +8395,7 @@ fn main() { expect![[r#" *c"🦀\u{1f980}\\\x41"* ```rust - &{unknown} + &'static {unknown} ``` ___ @@ -8414,7 +8414,7 @@ fn main() { expect![[r#" *r"`[^`]*`"* ```rust - &str + &'static str ``` ___ @@ -8429,7 +8429,7 @@ fn main() { expect![[r#" *r"`"* ```rust - &str + &'static str ``` ___ @@ -8444,7 +8444,7 @@ fn main() { expect![[r#" *r" "* ```rust - &str + &'static str ``` ___ @@ -8460,12 +8460,12 @@ fn main() { expect![[r#" *r" Hello World "* ```rust - &str + &'static str ``` ___ value of literal: ` Hello World ` -"#]], + "#]], ) } @@ -8480,7 +8480,7 @@ fn main() { expect![[r#" *b"\xF0\x9F\xA6\x80\\"* ```rust - &[u8; 5] + &'static [u8; 5] ``` ___ @@ -8496,7 +8496,7 @@ fn main() { expect![[r#" *br"\xF0\x9F\xA6\x80\\"* ```rust - &[u8; 18] + &'static [u8; 18] ``` ___ @@ -9070,7 +9070,7 @@ struct Pedro$0<'a> { ```rust struct Pedro<'a> { - hola: &str, + hola: &'a str, } ``` @@ -9937,7 +9937,7 @@ fn baz() { --- - `U` = `i32`, `T` = `&str` + `U` = `i32`, `T` = `&'static str` "#]], ); } @@ -10030,7 +10030,7 @@ fn bar() { --- - `T` = `i8`, `U` = `&str` + `T` = `i8`, `U` = `&'static str` "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 52ea2e5ec58b..36fdd90e8aea 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -380,9 +380,9 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 + // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) let foo = foo5(); - // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + // ^^^ &'static (dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 + 'static) let foo = foo6(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo7(); @@ -413,7 +413,7 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 + // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) let foo = foo5(); let foo = foo6(); let foo = foo7(); @@ -528,7 +528,7 @@ fn main() { //^^^^ i32 let _ = 22; let test = "test"; - //^^^^ &str + //^^^^ &'static str let test = InnerStruct {}; //^^^^ InnerStruct @@ -618,12 +618,12 @@ impl Iterator for IntoIter { fn main() { let mut data = Vec::new(); - //^^^^ Vec<&str> + //^^^^ Vec<&'static str> data.push("foo"); for i in data { - //^ &str + //^ &'static str let z = i; - //^ &str + //^ &'static str } } "#, @@ -651,8 +651,8 @@ fn main() { //^^ Vec> let _v = { Vec::>::new() }; //^^ Vec> - let _v = { Vec::>::new() }; - //^^ Vec> + let _v = { Vec::>::new() }; + //^^ Vec> } "#, ); @@ -1017,7 +1017,7 @@ fn test(t: T) { "#, expect![[r#" fn test(t: T) { - let f = |a: i32, b: &str, c: T| {}; + let f = |a: i32, b: &'static str, c: T| {}; let result: () = f(42, "", t); } "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index de9ca8c000f0..2ec85da4a429 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -194,7 +194,7 @@ impl Tr for () { //^ impl Tr for () impl dyn Tr { } -//^ impl dyn Tr +//^ impl dyn Tr + 'static static S0: () = 0; static S1: () = {}; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 96c2ceef6ba1..f6bcb5642c3b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -1064,7 +1064,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&str")); + assert!(res.to_string().contains("&'static str")); let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( @@ -1073,7 +1073,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&str")); + assert!(res.to_string().contains("&'static str")); server.request::( GotoDefinitionParams { From d940d0b7584fd7753f49d897c64eccc5535d2374 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 14 Mar 2025 09:58:46 +0100 Subject: [PATCH 158/302] Implement skeleton code for adding GenMC support to Miri (not yet functional). - Add a cargo feature to enable GenMC support (off by default) - Add support for GenMC datastructures to MiriMachine - Adjust several functions where GenMC needs to be informed about relevant events (e.g., atomic accesses) - Add skeleton code for parsing GenMC command line arguments - Some cleanup - Finish sentences with a `.` - Fix some spelling errors/typos Co-authored-by: Ralf Jung --- src/tools/miri/.gitignore | 5 +- src/tools/miri/Cargo.toml | 1 + src/tools/miri/src/alloc_addresses/mod.rs | 12 +- src/tools/miri/src/bin/miri.rs | 60 +++- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- src/tools/miri/src/concurrency/data_race.rs | 256 +++++++++++----- .../miri/src/concurrency/data_race_handler.rs | 91 ++++++ .../miri/src/concurrency/genmc/config.rs | 19 ++ src/tools/miri/src/concurrency/genmc/dummy.rs | 239 +++++++++++++++ src/tools/miri/src/concurrency/genmc/mod.rs | 284 ++++++++++++++++++ src/tools/miri/src/concurrency/init_once.rs | 4 +- src/tools/miri/src/concurrency/mod.rs | 16 + src/tools/miri/src/concurrency/sync.rs | 23 +- src/tools/miri/src/concurrency/thread.rs | 230 ++++++++------ .../miri/src/concurrency/vector_clock.rs | 10 +- src/tools/miri/src/concurrency/weak_memory.rs | 34 ++- src/tools/miri/src/diagnostics.rs | 9 + src/tools/miri/src/eval.rs | 67 +++-- src/tools/miri/src/intrinsics/atomic.rs | 31 +- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/machine.rs | 163 ++++++---- 22 files changed, 1254 insertions(+), 307 deletions(-) create mode 100644 src/tools/miri/src/concurrency/data_race_handler.rs create mode 100644 src/tools/miri/src/concurrency/genmc/config.rs create mode 100644 src/tools/miri/src/concurrency/genmc/dummy.rs create mode 100644 src/tools/miri/src/concurrency/genmc/mod.rs diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore index 03c5591b7875..ed2d0ba7ba07 100644 --- a/src/tools/miri/.gitignore +++ b/src/tools/miri/.gitignore @@ -9,6 +9,9 @@ tex/*/out *.mm_profdata perf.data perf.data.old -flamegraph.svg +flamegraph*.svg +rustc-ice*.txt tests/native-lib/libtestlib.so .auto-* + +/genmc/ diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index bb24e700e738..7b7be97aa518 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -65,6 +65,7 @@ harness = false [features] default = ["stack-cache"] +genmc = [] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 335e8d76999c..75eb0415a6f7 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -114,8 +114,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); - let mut rng = this.machine.rng.borrow_mut(); let info = this.get_alloc_info(alloc_id); + + // Miri's address assignment leaks state across thread boundaries, which is incompatible + // with GenMC execution. So we instead let GenMC assign addresses to allocations. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?; + return interp_ok(addr); + } + + let mut rng = this.machine.rng.borrow_mut(); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an @@ -490,7 +498,7 @@ impl<'tcx> MiriMachine<'tcx> { // Also remember this address for future reuse. let thread = self.threads.active_thread(); global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || { - if let Some(data_race) = &self.data_race { + if let Some(data_race) = self.data_race.as_vclocks_ref() { data_race.release_clock(&self.threads, |clock| clock.clone()) } else { VClock::default() diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index dce2ac77c2ac..411f9191bdae 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -28,13 +28,14 @@ use std::env::{self, VarError}; use std::num::NonZero; use std::ops::Range; use std::path::PathBuf; +use std::rc::Rc; use std::str::FromStr; use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use std::sync::{Arc, Once}; use miri::{ - BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields, - ValidationMode, + BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, + ProvenanceMode, RetagFields, ValidationMode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -60,6 +61,8 @@ use tracing::debug; struct MiriCompilerCalls { miri_config: Option, many_seeds: Option, + /// Settings for using GenMC with Miri. + genmc_config: Option, } struct ManySeedsConfig { @@ -68,8 +71,12 @@ struct ManySeedsConfig { } impl MiriCompilerCalls { - fn new(miri_config: MiriConfig, many_seeds: Option) -> Self { - Self { miri_config: Some(miri_config), many_seeds } + fn new( + miri_config: MiriConfig, + many_seeds: Option, + genmc_config: Option, + ) -> Self { + Self { miri_config: Some(miri_config), many_seeds, genmc_config } } } @@ -179,6 +186,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { optimizations is usually marginal at best."); } + if let Some(genmc_config) = &self.genmc_config { + let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config)); + + todo!("GenMC mode not yet implemented"); + }; + if let Some(many_seeds) = self.many_seeds.take() { assert!(config.seed.is_none()); let exit_code = sync::IntoDynSyncSend(AtomicI32::new(rustc_driver::EXIT_SUCCESS)); @@ -187,8 +200,14 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let mut config = config.clone(); config.seed = Some((*seed).into()); eprintln!("Trying seed: {seed}"); - let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config) - .unwrap_or(rustc_driver::EXIT_FAILURE); + let return_code = miri::eval_entry( + tcx, + entry_def_id, + entry_type, + &config, + /* genmc_ctx */ None, + ) + .unwrap_or(rustc_driver::EXIT_FAILURE); if return_code != rustc_driver::EXIT_SUCCESS { eprintln!("FAILING SEED: {seed}"); if !many_seeds.keep_going { @@ -206,11 +225,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } std::process::exit(exit_code.0.into_inner()); } else { - let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config) + let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None) .unwrap_or_else(|| { tcx.dcx().abort_if_errors(); rustc_driver::EXIT_FAILURE }); + std::process::exit(return_code); } @@ -506,6 +526,7 @@ fn main() { let mut many_seeds_keep_going = false; let mut miri_config = MiriConfig::default(); miri_config.env = env_snapshot; + let mut genmc_config = None; let mut rustc_args = vec![]; let mut after_dashdash = false; @@ -603,6 +624,10 @@ fn main() { many_seeds = Some(0..64); } else if arg == "-Zmiri-many-seeds-keep-going" { many_seeds_keep_going = true; + } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") { + // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. + miri_config.borrow_tracker = None; + GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") { @@ -697,7 +722,7 @@ fn main() { rustc_args.push(arg); } } - // `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows` + // `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows`. if miri_config.unique_is_unique && !matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) { @@ -734,7 +759,24 @@ fn main() { let many_seeds = many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going }); + // Validate settings for data race detection and GenMC mode. + assert_eq!(genmc_config.is_some(), miri_config.genmc_mode); + if genmc_config.is_some() { + if !miri_config.data_race_detector { + show_error!("Cannot disable data race detection in GenMC mode (currently)"); + } else if !miri_config.weak_memory_emulation { + show_error!("Cannot disable weak memory emulation in GenMC mode"); + } + } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector { + show_error!( + "Weak memory emulation cannot be enabled when the data race detector is disabled" + ); + }; + debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds)) + run_compiler_and_exit( + &rustc_args, + &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config), + ) } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 18a5a0612bb0..45863fee8720 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -740,7 +740,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { if let Some(access) = access { assert_eq!(access, AccessKind::Write); // Make sure the data race model also knows about this. - if let Some(data_race) = alloc_extra.data_race.as_mut() { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_mut() { data_race.write( alloc_id, range, @@ -789,7 +789,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { if let Some(access) = access { assert_eq!(access, AccessKind::Read); // Make sure the data race model also knows about this. - if let Some(data_race) = alloc_extra.data_race.as_ref() { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { data_race.read( alloc_id, range, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index ff09821394ab..ce7d7ab25d76 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -317,7 +317,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Also inform the data race model (but only if any bytes are actually affected). if range.size.bytes() > 0 && new_perm.initial_read { - if let Some(data_race) = alloc_extra.data_race.as_ref() { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { data_race.read( alloc_id, range, diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 847c68234759..714eb1fba91c 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -1,4 +1,4 @@ -//! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks +//! Implementation of a data-race detector using Lamport Timestamps / Vector clocks //! based on the Dynamic Race Detection for C++: //! //! which does not report false-positives when fences are used, and gives better @@ -54,6 +54,7 @@ use rustc_span::Span; use super::vector_clock::{VClock, VTimestamp, VectorIdx}; use super::weak_memory::EvalContextExt as _; +use crate::concurrency::GlobalDataRaceHandler; use crate::diagnostics::RacingOp; use crate::*; @@ -259,7 +260,7 @@ enum AccessType { /// Per-byte vector clock metadata for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need + /// The vector clock timestamp and the thread that did the last non-atomic write. We don't need /// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective /// clock is all-0 except for the thread that did the write. write: (VectorIdx, VTimestamp), @@ -269,7 +270,7 @@ struct MemoryCellClocks { /// a deallocation of memory. write_type: NaWriteType, - /// The vector-clock of all non-atomic reads that happened since the last non-atomic write + /// The vector clock of all non-atomic reads that happened since the last non-atomic write /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to /// zero on each write operation. read: VClock, @@ -298,7 +299,7 @@ struct ThreadExtraState { } /// Global data-race detection state, contains the currently -/// executing thread as well as the vector-clocks associated +/// executing thread as well as the vector clocks associated /// with each of the threads. // FIXME: it is probably better to have one large RefCell, than to have so many small ones. #[derive(Debug, Clone)] @@ -335,7 +336,7 @@ pub struct GlobalState { /// for use as the index for a new thread. /// Elements in this set may still require the vector index to /// report data-races, and can only be re-used after all - /// active vector-clocks catch up with the threads timestamp. + /// active vector clocks catch up with the threads timestamp. reuse_candidates: RefCell>, /// We make SC fences act like RMWs on a global location. @@ -348,6 +349,9 @@ pub struct GlobalState { /// Track when an outdated (weak memory) load happens. pub track_outdated_loads: bool, + + /// Whether weak memory emulation is enabled + pub weak_memory: bool, } impl VisitProvenance for GlobalState { @@ -680,6 +684,23 @@ impl MemoryCellClocks { } } +impl GlobalDataRaceHandler { + /// Select whether data race checking is disabled. This is solely an + /// implementation detail of `allow_data_races_*` and must not be used anywhere else! + fn set_ongoing_action_data_race_free(&self, enable: bool) { + match self { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => { + let old = data_race.ongoing_action_data_race_free.replace(enable); + assert_ne!(old, enable, "cannot nest allow_data_races"); + } + GlobalDataRaceHandler::Genmc(genmc_ctx) => { + genmc_ctx.set_ongoing_action_data_race_free(enable); + } + } + } +} + /// Evaluation context extensions. impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { @@ -696,6 +717,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is fine with StackedBorrow and race checks because they don't concern metadata on // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. + + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let old_val = None; + return genmc_ctx.atomic_load( + this, + place.ptr().addr(), + place.layout.size, + atomic, + old_val, + ); + } + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?; let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) @@ -718,6 +752,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); + // Inform GenMC about the atomic store. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?; + return interp_ok(()); + } this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) @@ -737,6 +777,21 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + // Inform GenMC about the atomic rmw operation. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, new_val) = genmc_ctx.atomic_rmw_op( + this, + place.ptr().addr(), + place.layout.size, + atomic, + (op, not), + rhs.to_scalar(), + )?; + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + return interp_ok(ImmTy::from_scalar(old_val, old.layout)); + } + let val = this.binary_op(op, &old, rhs)?; let val = if not { this.unary_op(mir::UnOp::Not, &val)? } else { val }; this.allow_data_races_mut(|this| this.write_immediate(*val, place))?; @@ -761,6 +816,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let old = this.allow_data_races_mut(|this| this.read_scalar(place))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?; + // Inform GenMC about the atomic atomic exchange. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, _is_success) = genmc_ctx.atomic_exchange( + this, + place.ptr().addr(), + place.layout.size, + new, + atomic, + )?; + return interp_ok(old_val); + } + this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw(new, place, atomic, old)?; @@ -780,6 +848,23 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.atomic_access_check(place, AtomicAccessType::Rmw)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + + // Inform GenMC about the atomic min/max operation. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, new_val) = genmc_ctx.atomic_min_max_op( + this, + place.ptr().addr(), + place.layout.size, + atomic, + min, + old.layout.backend_repr.is_signed(), + rhs.to_scalar(), + )?; + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + return interp_ok(ImmTy::from_scalar(old_val, old.layout)); + } + let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; #[rustfmt::skip] // rustfmt makes this unreadable @@ -823,6 +908,25 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + + // Inform GenMC about the atomic atomic compare exchange. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( + this, + place.ptr().addr(), + place.layout.size, + this.read_scalar(expect_old)?, + new, + success, + fail, + can_fail_spuriously, + )?; + if cmpxchg_success { + this.allow_data_races_mut(|this| this.write_scalar(new, place))?; + } + return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success))); + } + // `binary_op` will bail if either of them is not a scalar. let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion @@ -859,49 +963,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let current_span = this.machine.current_span(); - if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation( - &this.machine.threads, - current_span, - |index, mut clocks| { - trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); - - // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as an acquire - // and release fence applied in the same timestamp. - if atomic != AtomicFenceOrd::Release { - // Either Acquire | AcqRel | SeqCst - clocks.apply_acquire_fence(); - } - if atomic == AtomicFenceOrd::SeqCst { - // Behave like an RMW on the global fence location. This takes full care of - // all the SC fence requirements, including C++17 §32.4 [atomics.order] - // paragraph 6 (which would limit what future reads can see). It also rules - // out many legal behaviors, but we don't currently have a model that would - // be more precise. - // Also see the second bullet on page 10 of - // . - let mut sc_fence_clock = data_race.last_sc_fence.borrow_mut(); - sc_fence_clock.join(&clocks.clock); - clocks.clock.join(&sc_fence_clock); - // Also establish some sort of order with the last SC write that happened, globally - // (but this is only respected by future reads). - clocks.write_seqcst.join(&data_race.last_sc_write_per_thread.borrow()); - } - // The release fence is last, since both of the above could alter our clock, - // which should be part of what is being released. - if atomic != AtomicFenceOrd::Acquire { - // Either Release | AcqRel | SeqCst - clocks.apply_release_fence(); - } - - // Increment timestamp in case of release semantics. - interp_ok(atomic != AtomicFenceOrd::Acquire) - }, - ) - } else { - interp_ok(()) + let machine = &this.machine; + match &this.machine.data_race { + GlobalDataRaceHandler::None => interp_ok(()), + GlobalDataRaceHandler::Vclocks(data_race) => data_race.atomic_fence(machine, atomic), + GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.atomic_fence(machine, atomic), } } @@ -910,10 +976,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { fn allow_data_races_all_threads_done(&mut self) { let this = self.eval_context_ref(); assert!(this.have_all_terminated()); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); } /// Calls the callback with the "release" clock of the current thread. @@ -923,14 +986,16 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// The closure will only be invoked if data race handling is on. fn release_clock(&self, callback: impl FnOnce(&VClock) -> R) -> Option { let this = self.eval_context_ref(); - Some(this.machine.data_race.as_ref()?.release_clock(&this.machine.threads, callback)) + Some( + this.machine.data_race.as_vclocks_ref()?.release_clock(&this.machine.threads, callback), + ) } /// Acquire the given clock into the current thread, establishing synchronization with /// the moment when that clock snapshot was taken via `release_clock`. fn acquire_clock(&self, clock: &VClock) { let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(clock, &this.machine.threads); } } @@ -1132,7 +1197,7 @@ impl VClockAlloc { machine: &MiriMachine<'_>, ) -> InterpResult<'tcx> { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return interp_ok(()); } @@ -1174,7 +1239,7 @@ impl VClockAlloc { machine: &mut MiriMachine<'_>, ) -> InterpResult<'tcx> { let current_span = machine.current_span(); - let global = machine.data_race.as_mut().unwrap(); + let global = machine.data_race.as_vclocks_mut().unwrap(); if !global.race_detecting() { return interp_ok(()); } @@ -1228,7 +1293,7 @@ impl Default for LocalClocks { impl FrameState { pub fn local_write(&self, local: mir::Local, storage_live: bool, machine: &MiriMachine<'_>) { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1258,7 +1323,7 @@ impl FrameState { pub fn local_read(&self, local: mir::Local, machine: &MiriMachine<'_>) { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1281,7 +1346,7 @@ impl FrameState { alloc: &mut VClockAlloc, machine: &MiriMachine<'_>, ) { - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1314,14 +1379,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriInterpCx<'tcx>) -> R) -> R { let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } + this.machine.data_race.set_ongoing_action_data_race_free(false); result } @@ -1331,14 +1391,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriInterpCx<'tcx>) -> R) -> R { let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } + this.machine.data_race.set_ongoing_action_data_race_free(false); result } @@ -1355,7 +1410,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.check_ptr_align(place.ptr(), align)?; // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable - // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // memory on many targets (i.e., they segfault if that memory is mapped read-only), and // atomic loads can be implemented via compare_exchange on some targets. There could // possibly be some very specific exceptions to this, see // for details. @@ -1486,7 +1541,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); assert!(access.is_atomic()); - let Some(data_race) = &this.machine.data_race else { return interp_ok(()) }; + let Some(data_race) = this.machine.data_race.as_vclocks_ref() else { + return interp_ok(()); + }; if !data_race.race_detecting() { return interp_ok(()); } @@ -1494,7 +1551,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_vclocks_ref().unwrap(); trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", access.description(None, None), @@ -1565,6 +1622,7 @@ impl GlobalState { last_sc_fence: RefCell::new(VClock::default()), last_sc_write_per_thread: RefCell::new(VClock::default()), track_outdated_loads: config.track_outdated_loads, + weak_memory: config.weak_memory_emulation, }; // Setup the main-thread since it is not explicitly created: @@ -1728,7 +1786,7 @@ impl GlobalState { } } - /// On thread termination, the vector-clock may re-used + /// On thread termination, the vector clock may be re-used /// in the future once all remaining thread-clocks catch /// up with the time index of the terminated thread. /// This assigns thread termination with a unique index @@ -1750,6 +1808,50 @@ impl GlobalState { reuse.insert(current_index); } + /// Update the data-race detector for an atomic fence on the current thread. + fn atomic_fence<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let current_span = machine.current_span(); + self.maybe_perform_sync_operation(&machine.threads, current_span, |index, mut clocks| { + trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); + + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as an acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOrd::Release { + // Either Acquire | AcqRel | SeqCst + clocks.apply_acquire_fence(); + } + if atomic == AtomicFenceOrd::SeqCst { + // Behave like an RMW on the global fence location. This takes full care of + // all the SC fence requirements, including C++17 §32.4 [atomics.order] + // paragraph 6 (which would limit what future reads can see). It also rules + // out many legal behaviors, but we don't currently have a model that would + // be more precise. + // Also see the second bullet on page 10 of + // . + let mut sc_fence_clock = self.last_sc_fence.borrow_mut(); + sc_fence_clock.join(&clocks.clock); + clocks.clock.join(&sc_fence_clock); + // Also establish some sort of order with the last SC write that happened, globally + // (but this is only respected by future reads). + clocks.write_seqcst.join(&self.last_sc_write_per_thread.borrow()); + } + // The release fence is last, since both of the above could alter our clock, + // which should be part of what is being released. + if atomic != AtomicFenceOrd::Acquire { + // Either Release | AcqRel | SeqCst + clocks.apply_release_fence(); + } + + // Increment timestamp in case of release semantics. + interp_ok(atomic != AtomicFenceOrd::Acquire) + }) + } + /// Attempt to perform a synchronized operation, this /// will perform no operation if multi-threading is /// not currently enabled. diff --git a/src/tools/miri/src/concurrency/data_race_handler.rs b/src/tools/miri/src/concurrency/data_race_handler.rs new file mode 100644 index 000000000000..047c37e56b8f --- /dev/null +++ b/src/tools/miri/src/concurrency/data_race_handler.rs @@ -0,0 +1,91 @@ +use std::rc::Rc; + +use super::{data_race, weak_memory}; +use crate::concurrency::GenmcCtx; +use crate::{VisitProvenance, VisitWith}; + +pub enum GlobalDataRaceHandler { + /// No data race detection will be done. + None, + /// State required to run in GenMC mode. + /// In this mode, the program will be executed repeatedly to explore different concurrent executions. + /// The `GenmcCtx` must persist across multiple executions, so it is behind an `Rc`. + /// + /// The `GenmcCtx` has several methods with which to inform it about events like atomic memory accesses. + /// In GenMC mode, some functionality is taken over by GenMC: + /// - Memory Allocation: Allocated addresses need to be consistent across executions, which Miri's allocator doesn't guarantee + /// - Scheduling: To influence which concurrent execution we will explore next, GenMC takes over scheduling + /// - Atomic operations: GenMC will ensure that we explore all possible values that the memory model allows + /// an atomic operation to see at any specific point of the program. + Genmc(Rc), + /// The default data race detector for Miri using vector clocks. + Vclocks(Box), +} + +#[derive(Debug)] +pub enum AllocDataRaceHandler { + None, + Genmc, + /// Data race detection via the use of vector clocks. + /// Weak memory emulation via the use of store buffers (if enabled). + Vclocks(data_race::AllocState, Option), +} + +impl GlobalDataRaceHandler { + pub fn is_none(&self) -> bool { + matches!(self, GlobalDataRaceHandler::None) + } + + pub fn as_vclocks_ref(&self) -> Option<&data_race::GlobalState> { + if let Self::Vclocks(data_race) = self { Some(data_race) } else { None } + } + + pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::GlobalState> { + if let Self::Vclocks(data_race) = self { Some(data_race) } else { None } + } + + pub fn as_genmc_ref(&self) -> Option<&GenmcCtx> { + if let Self::Genmc(genmc_ctx) = self { Some(genmc_ctx) } else { None } + } +} + +impl AllocDataRaceHandler { + pub fn as_vclocks_ref(&self) -> Option<&data_race::AllocState> { + if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None } + } + + pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::AllocState> { + if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None } + } + + pub fn as_weak_memory_ref(&self) -> Option<&weak_memory::AllocState> { + if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_ref() } else { None } + } + + pub fn as_weak_memory_mut(&mut self) -> Option<&mut weak_memory::AllocState> { + if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_mut() } else { None } + } +} + +impl VisitProvenance for GlobalDataRaceHandler { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => data_race.visit_provenance(visit), + GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.visit_provenance(visit), + } + } +} + +impl VisitProvenance for AllocDataRaceHandler { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + AllocDataRaceHandler::None => {} + AllocDataRaceHandler::Genmc => {} + AllocDataRaceHandler::Vclocks(data_race, weak_memory) => { + data_race.visit_provenance(visit); + weak_memory.visit_provenance(visit); + } + } + } +} diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs new file mode 100644 index 000000000000..f91211a670f6 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/config.rs @@ -0,0 +1,19 @@ +use crate::MiriConfig; + +#[derive(Debug, Default, Clone)] +pub struct GenmcConfig { + // TODO: add fields +} + +impl GenmcConfig { + /// Function for parsing command line options for GenMC mode. + /// All GenMC arguments start with the string "-Zmiri-genmc". + /// + /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed + pub fn parse_arg(genmc_config: &mut Option, trimmed_arg: &str) { + if genmc_config.is_none() { + *genmc_config = Some(Default::default()); + } + todo!("implement parsing of GenMC options") + } +} diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs new file mode 100644 index 000000000000..3d0558fb6853 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -0,0 +1,239 @@ +#![allow(unused)] + +use rustc_abi::{Align, Size}; +use rustc_const_eval::interpret::{InterpCx, InterpResult}; +use rustc_middle::mir; + +use crate::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, +}; + +#[derive(Debug)] +pub struct GenmcCtx {} + +#[derive(Debug, Default, Clone)] +pub struct GenmcConfig {} + +impl GenmcCtx { + pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self { + unreachable!() + } + + pub fn get_stuck_execution_count(&self) -> usize { + unreachable!() + } + + pub fn print_genmc_graph(&self) { + unreachable!() + } + + pub fn is_exploration_done(&self) -> bool { + unreachable!() + } + + /**** Memory access handling ****/ + + pub(crate) fn handle_execution_start(&self) { + unreachable!() + } + + pub(crate) fn handle_execution_end<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> Result<(), String> { + unreachable!() + } + + pub(super) fn set_ongoing_action_data_race_free(&self, _enable: bool) { + unreachable!() + } + + //* might fails if there's a race, load might also not read anything (returns None) */ + pub(crate) fn atomic_load<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicReadOrd, + _old_val: Option, + ) -> InterpResult<'tcx, Scalar> { + unreachable!() + } + + pub(crate) fn atomic_store<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _value: Scalar, + _ordering: AtomicWriteOrd, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn atomic_fence<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _ordering: AtomicFenceOrd, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn atomic_rmw_op<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + (rmw_op, not): (mir::BinOp, bool), + _rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + unreachable!() + } + + pub(crate) fn atomic_min_max_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + min: bool, + is_signed: bool, + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + unreachable!() + } + + pub(crate) fn atomic_exchange<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _rhs_scalar: Scalar, + _ordering: AtomicRwOrd, + ) -> InterpResult<'tcx, (Scalar, bool)> { + unreachable!() + } + + pub(crate) fn atomic_compare_exchange<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _expected_old_value: Scalar, + _new_value: Scalar, + _success: AtomicRwOrd, + _fail: AtomicReadOrd, + _can_fail_spuriously: bool, + ) -> InterpResult<'tcx, (Scalar, bool)> { + unreachable!() + } + + pub(crate) fn memory_load<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn memory_store<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Memory (de)allocation ****/ + + pub(crate) fn handle_alloc<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _size: Size, + _alignment: Align, + _memory_kind: MemoryKind, + ) -> InterpResult<'tcx, u64> { + unreachable!() + } + + pub(crate) fn handle_dealloc<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + _align: Align, + _kind: MemoryKind, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Thread management ****/ + + pub(crate) fn handle_thread_create<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + _new_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn handle_thread_join<'tcx>( + &self, + _active_thread_id: ThreadId, + _child_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) { + unreachable!() + } + + pub(crate) fn handle_thread_finish<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Scheduling functionality ****/ + + pub(crate) fn schedule_thread<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + unreachable!() + } + + /**** Blocking instructions ****/ + + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _condition: bool, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } +} + +impl VisitProvenance for GenmcCtx { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + unreachable!() + } +} + +impl GenmcConfig { + pub fn parse_arg(_genmc_config: &mut Option, trimmed_arg: &str) { + unimplemented!( + "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + ); + } + + pub fn should_print_graph(&self, _rep: usize) -> bool { + unreachable!() + } +} diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs new file mode 100644 index 000000000000..0dfd4b9b80f9 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -0,0 +1,284 @@ +#![allow(unused)] // FIXME(GenMC): remove this + +use std::cell::Cell; + +use rustc_abi::{Align, Size}; +use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; +use rustc_middle::mir; + +use crate::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, +}; + +mod config; + +pub use self::config::GenmcConfig; + +// FIXME(GenMC): add fields +pub struct GenmcCtx { + /// Some actions Miri does are allowed to cause data races. + /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set. + allow_data_races: Cell, +} + +impl GenmcCtx { + /// Create a new `GenmcCtx` from a given config. + pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self { + assert!(miri_config.genmc_mode); + todo!() + } + + pub fn get_stuck_execution_count(&self) -> usize { + todo!() + } + + pub fn print_genmc_graph(&self) { + todo!() + } + + /// This function determines if we should continue exploring executions or if we are done. + /// + /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. + pub fn is_exploration_done(&self) -> bool { + todo!() + } + + /// Inform GenMC that a new program execution has started. + /// This function should be called at the start of every execution. + pub(crate) fn handle_execution_start(&self) { + todo!() + } + + /// Inform GenMC that the program's execution has ended. + /// + /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + pub(crate) fn handle_execution_end<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> Result<(), String> { + todo!() + } + + /**** Memory access handling ****/ + + /// Select whether data race free actions should be allowed. This function should be used carefully! + /// + /// If `true` is passed, allow for data races to happen without triggering an error, until this function is called again with argument `false`. + /// This allows for racy non-atomic memory accesses to be ignored (GenMC is not informed about them at all). + /// + /// Certain operations are not permitted in GenMC mode with data races disabled and will cause a panic, e.g., atomic accesses or asking for scheduling decisions. + /// + /// # Panics + /// If data race free is attempted to be set more than once (i.e., no nesting allowed). + pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) { + let old = self.allow_data_races.replace(enable); + assert_ne!(old, enable, "cannot nest allow_data_races"); + } + + pub(crate) fn atomic_load<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicReadOrd, + old_val: Option, + ) -> InterpResult<'tcx, Scalar> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_store<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + value: Scalar, + ordering: AtomicWriteOrd, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_fence<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + ordering: AtomicFenceOrd, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about an atomic read-modify-write operation. + /// + /// Returns `(old_val, new_val)`. + pub(crate) fn atomic_rmw_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + (rmw_op, not): (mir::BinOp, bool), + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about an atomic `min` or `max` operation. + /// + /// Returns `(old_val, new_val)`. + pub(crate) fn atomic_min_max_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + min: bool, + is_signed: bool, + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_exchange<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + rhs_scalar: Scalar, + ordering: AtomicRwOrd, + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_compare_exchange<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + expected_old_value: Scalar, + new_value: Scalar, + success: AtomicRwOrd, + fail: AtomicReadOrd, + can_fail_spuriously: bool, + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about a non-atomic memory load + /// + /// NOTE: Unlike for *atomic* loads, we don't return a value here. Non-atomic values are still handled by Miri. + pub(crate) fn memory_load<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + pub(crate) fn memory_store<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + /**** Memory (de)allocation ****/ + + pub(crate) fn handle_alloc<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + size: Size, + alignment: Align, + memory_kind: MemoryKind, + ) -> InterpResult<'tcx, u64> { + todo!() + } + + pub(crate) fn handle_dealloc<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + align: Align, + kind: MemoryKind, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + /**** Thread management ****/ + + pub(crate) fn handle_thread_create<'tcx>( + &self, + threads: &ThreadManager<'tcx>, + new_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn handle_thread_join<'tcx>( + &self, + active_thread_id: ThreadId, + child_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) { + todo!() + } + + pub(crate) fn handle_thread_finish<'tcx>( + &self, + threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /**** Scheduling functionality ****/ + + /// Ask for a scheduling decision. This should be called before every MIR instruction. + /// + /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + /// + /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors. + pub(crate) fn schedule_thread<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /**** Blocking instructions ****/ + + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + condition: bool, + ) -> InterpResult<'tcx, ()> { + if condition { interp_ok(()) } else { self.handle_user_block(machine) } + } +} + +impl VisitProvenance for GenmcCtx { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // We don't have any tags. + } +} + +impl GenmcCtx { + fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { + todo!() + } +} diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 534f02545bde..c26384f65f6c 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -72,7 +72,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Complete; // Each complete happens-before the end of the wait - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); } @@ -99,7 +99,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Uninitialized; // Each complete happens-before the end of the wait - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); } diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index c5082b4e40b4..dd33f90f153d 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,5 +1,6 @@ pub mod cpu_affinity; pub mod data_race; +mod data_race_handler; pub mod init_once; mod range_object_map; pub mod sync; @@ -7,4 +8,19 @@ pub mod thread; mod vector_clock; pub mod weak_memory; +// Import either the real genmc adapter or a dummy module. +cfg_match! { + feature = "genmc" => { + mod genmc; + pub use self::genmc::{GenmcCtx, GenmcConfig}; + } + _ => { + #[path = "genmc/dummy.rs"] + mod genmc_dummy; + use self::genmc_dummy as genmc; + pub use self::genmc::{GenmcCtx, GenmcConfig}; + } +} + +pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; pub use self::vector_clock::VClock; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 268268848ed2..64f34d3e21cc 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -361,7 +361,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.strict_add(1); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&mutex.clock, &this.machine.threads); } } @@ -385,7 +385,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex.owner = None; // The mutex is completely unlocked. Try transferring ownership // to another thread. - if let Some(data_race) = &this.machine.data_race { + + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| { mutex.clock.clone_from(clock) }); @@ -477,7 +478,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let rwlock = &mut this.machine.sync.rwlocks[id]; let count = rwlock.readers.entry(thread).or_insert(0); *count = count.strict_add(1); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); } } @@ -502,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock } - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { // Add this to the shared-release clock of all concurrent readers. data_race.release_clock(&this.machine.threads, |clock| { rwlock.clock_current_readers.join(clock) @@ -565,7 +566,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("rwlock_writer_lock: {:?} now held by {:?}", id, thread); let rwlock = &mut this.machine.sync.rwlocks[id]; rwlock.writer = Some(thread); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); } } @@ -585,7 +586,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { rwlock.writer = None; trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, thread); // Record release clock for next lock holder. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| { rwlock.clock_unlocked.clone_from(clock) }); @@ -691,7 +692,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match unblock { UnblockKind::Ready => { // The condvar was signaled. Make sure we get the clock for that. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock( &this.machine.sync.condvars[condvar].clock, &this.machine.threads, @@ -721,10 +722,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn condvar_signal(&mut self, id: CondvarId) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let condvar = &mut this.machine.sync.condvars[id]; - let data_race = &this.machine.data_race; // Each condvar signal happens-before the end of the condvar wake - if let Some(data_race) = data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| condvar.clock.clone_from(clock)); } let Some(waiter) = condvar.waiters.pop_front() else { @@ -764,7 +764,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { UnblockKind::Ready => { let futex = futex_ref.0.borrow(); // Acquire the clock of the futex. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&futex.clock, &this.machine.threads); } }, @@ -792,10 +792,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, usize> { let this = self.eval_context_mut(); let mut futex = futex_ref.0.borrow_mut(); - let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait - if let Some(data_race) = data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock)); } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index f8ff47e71137..8aa65e6cb612 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -6,7 +6,6 @@ use std::task::Poll; use std::time::{Duration, SystemTime}; use either::Either; -use rand::rngs::StdRng; use rand::seq::IteratorRandom; use rustc_abi::ExternAbi; use rustc_const_eval::CTRL_C_RECEIVED; @@ -17,7 +16,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::Span; -use crate::concurrency::data_race; +use crate::concurrency::GlobalDataRaceHandler; use crate::shims::tls; use crate::*; @@ -584,13 +583,28 @@ impl<'tcx> ThreadManager<'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: Option<&mut data_race::GlobalState>, + data_race_handler: &mut GlobalDataRaceHandler, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached { // On Windows this corresponds to joining on a closed handle. throw_ub_format!("trying to join a detached thread"); } + fn after_join<'tcx>( + threads: &mut ThreadManager<'_>, + joined_thread_id: ThreadId, + data_race_handler: &mut GlobalDataRaceHandler, + ) -> InterpResult<'tcx> { + match data_race_handler { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_joined(threads, joined_thread_id), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?, + } + interp_ok(()) + } + // Mark the joined thread as being joined so that we detect if other // threads try to join it. self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; @@ -610,18 +624,13 @@ impl<'tcx> ThreadManager<'tcx> { } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); - if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_joined(&this.machine.threads, joined_thread_id); - } - interp_ok(()) + after_join(&mut this.machine.threads, joined_thread_id, &mut this.machine.data_race) } ), ); } else { // The thread has already terminated - establish happens-before - if let Some(data_race) = data_race { - data_race.thread_joined(self, joined_thread_id); - } + after_join(self, joined_thread_id, data_race_handler)?; } interp_ok(()) } @@ -631,7 +640,7 @@ impl<'tcx> ThreadManager<'tcx> { fn join_thread_exclusive( &mut self, joined_thread_id: ThreadId, - data_race: Option<&mut data_race::GlobalState>, + data_race_handler: &mut GlobalDataRaceHandler, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined { throw_ub_format!("trying to join an already joined thread"); @@ -649,7 +658,7 @@ impl<'tcx> ThreadManager<'tcx> { "this thread already has threads waiting for its termination" ); - self.join_thread(joined_thread_id, data_race) + self.join_thread(joined_thread_id, data_race_handler) } /// Set the name of the given thread. @@ -699,77 +708,6 @@ impl<'tcx> ThreadManager<'tcx> { }) .min() } - - /// Decide which action to take next and on which thread. - /// - /// The currently implemented scheduling policy is the one that is commonly - /// used in stateless model checkers such as Loom: run the active thread as - /// long as we can and switch only when we have to (the active thread was - /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule( - &mut self, - clock: &MonotonicClock, - rng: &mut StdRng, - ) -> InterpResult<'tcx, SchedulingAction> { - // This thread and the program can keep going. - if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread { - // The currently active thread is still enabled, just continue with it. - return interp_ok(SchedulingAction::ExecuteStep); - } - // The active thread yielded or got terminated. Let's see if there are any timeouts to take - // care of. We do this *before* running any other thread, to ensure that timeouts "in the - // past" fire before any other thread can take an action. This ensures that for - // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by - // abstime has already been passed at the time of the call". - // - let potential_sleep_time = self.next_callback_wait_time(clock); - if potential_sleep_time == Some(Duration::ZERO) { - return interp_ok(SchedulingAction::ExecuteTimeoutCallback); - } - // No callbacks immediately scheduled, pick a regular thread to execute. - // The active thread blocked or yielded. So we go search for another enabled thread. - // We build the list of threads by starting with the threads after the current one, followed by - // the threads before the current one and then the current thread itself (i.e., this iterator acts - // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first - // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step. - let mut threads_iter = self - .threads - .iter_enumerated() - .skip(self.active_thread.index() + 1) - .chain(self.threads.iter_enumerated().take(self.active_thread.index() + 1)) - .filter(|(_id, thread)| thread.state.is_enabled()); - // Pick a new thread, and switch to it. - let new_thread = - if self.fixed_scheduling { threads_iter.next() } else { threads_iter.choose(rng) }; - - if let Some((id, _thread)) = new_thread { - if self.active_thread != id { - info!( - "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------", - self.get_thread_display_name(id), - self.get_thread_display_name(self.active_thread) - ); - self.active_thread = id; - } - } - // This completes the `yield`, if any was requested. - self.yield_active_thread = false; - - if self.threads[self.active_thread].state.is_enabled() { - return interp_ok(SchedulingAction::ExecuteStep); - } - // We have not found a thread to execute. - if self.threads.iter().all(|thread| thread.state.is_terminated()) { - unreachable!("all threads terminated without the main thread terminating?!"); - } else if let Some(sleep_time) = potential_sleep_time { - // All threads are currently blocked, but we have unexecuted - // timeout_callbacks, which may unblock some of the threads. Hence, - // sleep until the first callback. - interp_ok(SchedulingAction::Sleep(sleep_time)) - } else { - throw_machine_stop!(TerminationInfo::Deadlock); - } - } } impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} @@ -817,6 +755,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); + // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let thread_id = this.active_thread(); + genmc_ctx.handle_thread_stack_empty(thread_id); + } let mut callback = this .active_thread_mut() .on_stack_empty @@ -826,6 +769,102 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { this.active_thread_mut().on_stack_empty = Some(callback); interp_ok(res) } + + /// Decide which action to take next and on which thread. + /// + /// The currently implemented scheduling policy is the one that is commonly + /// used in stateless model checkers such as Loom: run the active thread as + /// long as we can and switch only when we have to (the active thread was + /// blocked, terminated, or has explicitly asked to be preempted). + /// + /// If GenMC mode is active, the scheduling is instead handled by GenMC. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + let this = self.eval_context_mut(); + // In GenMC mode, we let GenMC do the scheduling + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let next_thread_id = genmc_ctx.schedule_thread(this)?; + + let thread_manager = &mut this.machine.threads; + thread_manager.active_thread = next_thread_id; + thread_manager.yield_active_thread = false; + + assert!(thread_manager.threads[thread_manager.active_thread].state.is_enabled()); + return interp_ok(SchedulingAction::ExecuteStep); + } + + // We are not in GenMC mode, so we control the schedule + let thread_manager = &mut this.machine.threads; + let clock = &this.machine.monotonic_clock; + let rng = this.machine.rng.get_mut(); + // This thread and the program can keep going. + if thread_manager.threads[thread_manager.active_thread].state.is_enabled() + && !thread_manager.yield_active_thread + { + // The currently active thread is still enabled, just continue with it. + return interp_ok(SchedulingAction::ExecuteStep); + } + // The active thread yielded or got terminated. Let's see if there are any timeouts to take + // care of. We do this *before* running any other thread, to ensure that timeouts "in the + // past" fire before any other thread can take an action. This ensures that for + // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by + // abstime has already been passed at the time of the call". + // + let potential_sleep_time = thread_manager.next_callback_wait_time(clock); + if potential_sleep_time == Some(Duration::ZERO) { + return interp_ok(SchedulingAction::ExecuteTimeoutCallback); + } + // No callbacks immediately scheduled, pick a regular thread to execute. + // The active thread blocked or yielded. So we go search for another enabled thread. + // We build the list of threads by starting with the threads after the current one, followed by + // the threads before the current one and then the current thread itself (i.e., this iterator acts + // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first + // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step. + let mut threads_iter = thread_manager + .threads + .iter_enumerated() + .skip(thread_manager.active_thread.index() + 1) + .chain( + thread_manager + .threads + .iter_enumerated() + .take(thread_manager.active_thread.index() + 1), + ) + .filter(|(_id, thread)| thread.state.is_enabled()); + // Pick a new thread, and switch to it. + let new_thread = if thread_manager.fixed_scheduling { + threads_iter.next() + } else { + threads_iter.choose(rng) + }; + + if let Some((id, _thread)) = new_thread { + if thread_manager.active_thread != id { + info!( + "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------", + thread_manager.get_thread_display_name(id), + thread_manager.get_thread_display_name(thread_manager.active_thread) + ); + thread_manager.active_thread = id; + } + } + // This completes the `yield`, if any was requested. + thread_manager.yield_active_thread = false; + + if thread_manager.threads[thread_manager.active_thread].state.is_enabled() { + return interp_ok(SchedulingAction::ExecuteStep); + } + // We have not found a thread to execute. + if thread_manager.threads.iter().all(|thread| thread.state.is_terminated()) { + unreachable!("all threads terminated without the main thread terminating?!"); + } else if let Some(sleep_time) = potential_sleep_time { + // All threads are currently blocked, but we have unexecuted + // timeout_callbacks, which may unblock some of the threads. Hence, + // sleep until the first callback. + interp_ok(SchedulingAction::Sleep(sleep_time)) + } else { + throw_machine_stop!(TerminationInfo::Deadlock); + } + } } // Public interface to thread management. @@ -891,10 +930,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Box::new(move |m| state.on_stack_empty(m)) }); let current_span = this.machine.current_span(); - if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_created(&this.machine.threads, new_thread_id, current_span); + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_created(&this.machine.threads, new_thread_id, current_span), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?, } - // Write the current thread-id, switch to the next thread later // to treat this write operation as occurring on the current thread. if let Some(thread_info_place) = thread { @@ -941,12 +983,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// This is called by the eval loop when a thread's on_stack_empty returns `Ready`. fn terminate_active_thread(&mut self, tls_alloc_action: TlsAllocAction) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Mark thread as terminated. let thread = this.active_thread_mut(); assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated"); thread.state = ThreadState::Terminated; - if let Some(ref mut data_race) = this.machine.data_race { - data_race.thread_terminated(&this.machine.threads); + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_terminated(&this.machine.threads), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_finish(&this.machine.threads)?, } // Deallocate TLS. let gone_thread = this.active_thread(); @@ -1062,7 +1109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?; + this.machine.threads.join_thread(joined_thread_id, &mut this.machine.data_race)?; interp_ok(()) } @@ -1071,7 +1118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.machine .threads - .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?; + .join_thread_exclusive(joined_thread_id, &mut this.machine.data_race)?; interp_ok(()) } @@ -1165,8 +1212,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.handle_abnormal_termination(); throw_machine_stop!(TerminationInfo::Interrupted); } - let rng = this.machine.rng.get_mut(); - match this.machine.threads.schedule(&this.machine.monotonic_clock, rng)? { + match this.schedule()? { SchedulingAction::ExecuteStep => { if !this.step()? { // See if this thread can do something else. diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 345726634299..78858fcedaec 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -40,8 +40,8 @@ impl From for VectorIdx { } } -/// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap +/// The size of the vector clock to store inline. +/// Clock vectors larger than this will be stored on the heap. const SMALL_VECTOR: usize = 4; /// The time-stamps recorded in the data-race detector consist of both @@ -136,7 +136,7 @@ impl Ord for VTimestamp { pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { - /// Create a new vector-clock containing all zeros except + /// Create a new vector clock containing all zeros except /// for a value at the given index pub(super) fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { if timestamp.time() == 0 { @@ -185,8 +185,8 @@ impl VClock { } } - // Join the two vector-clocks together, this - // sets each vector-element to the maximum value + // Join the two vector clocks together, this + // sets each vector element to the maximum value // of that element in either of the two source elements. pub fn join(&mut self, other: &Self) { let rhs_slice = other.as_slice(); diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 1a3e9614f8af..95c010be2fd2 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -77,7 +77,7 @@ // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) // and here. // -// 4. W_SC ; R_SC case requires the SC load to ignore all but last store maked SC (stores not marked SC are not +// 4. W_SC ; R_SC case requires the SC load to ignore all but last store marked SC (stores not marked SC are not // affected). But this rule is applied to all loads in ReadsFromSet from the paper (last two lines of code), not just SC load. // This is implemented correctly in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295) @@ -88,9 +88,11 @@ use std::collections::VecDeque; use rustc_data_structures::fx::FxHashMap; +use super::AllocDataRaceHandler; use super::data_race::{GlobalState as DataRaceState, ThreadClockSet}; use super::range_object_map::{AccessType, RangeObjectMap}; use super::vector_clock::{VClock, VTimestamp, VectorIdx}; +use crate::concurrency::GlobalDataRaceHandler; use crate::*; pub type AllocState = StoreBufferAlloc; @@ -459,8 +461,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::MiriMachine { data_race: Some(global), threads, .. }, + crate::AllocExtra { + data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + .. + }, + crate::MiriMachine { + data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. + }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicRwOrd::SeqCst { @@ -484,9 +491,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); 'fallback: { - if let Some(global) = &this.machine.data_race { + if let Some(global) = this.machine.data_race.as_vclocks_ref() { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if let Some(alloc_buffers) = + this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref() + { if atomic == AtomicReadOrd::SeqCst { global.sc_read(&this.machine.threads); } @@ -534,8 +543,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?; if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::MiriMachine { data_race: Some(global), threads, .. }, + crate::AllocExtra { + data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + .. + }, + crate::MiriMachine { + data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. + }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicWriteOrd::SeqCst { @@ -561,13 +575,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - if let Some(global) = &this.machine.data_race { + if let Some(global) = this.machine.data_race.as_vclocks_ref() { if atomic == AtomicReadOrd::SeqCst { global.sc_read(&this.machine.threads); } let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if let Some(alloc_buffers) = + this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref() + { let Some(buffer) = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))? else { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 014b1299f2dd..89768077d878 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -31,6 +31,8 @@ pub enum TerminationInfo { }, Int2PtrWithStrictProvenance, Deadlock, + /// In GenMC mode, an execution can get stuck in certain cases. This is not an error. + GenmcStuckExecution, MultipleSymbolDefinitions { link_name: Symbol, first: SpanData, @@ -75,6 +77,7 @@ impl fmt::Display for TerminationInfo { StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), TreeBorrowsUb { title, .. } => write!(f, "{title}"), Deadlock => write!(f, "the evaluated program deadlocked"), + GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => @@ -235,6 +238,12 @@ pub fn report_error<'tcx>( StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), + GenmcStuckExecution => { + // This case should only happen in GenMC mode. We treat it like a normal program exit. + assert!(ecx.machine.data_race.as_genmc_ref().is_some()); + tracing::info!("GenMC: found stuck execution"); + return Some((0, true)); + } MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; #[rustfmt::skip] diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index ef8d9dab15ad..f41062dae454 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -3,6 +3,7 @@ use std::ffi::{OsStr, OsString}; use std::panic::{self, AssertUnwindSafe}; use std::path::PathBuf; +use std::rc::Rc; use std::task::Poll; use std::{iter, thread}; @@ -14,6 +15,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::EntryFnType; +use crate::concurrency::GenmcCtx; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; use crate::shims::tls; @@ -117,16 +119,18 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrows pointer ids to report about + /// The stacked borrows pointer ids to report about. pub tracked_pointer_tags: FxHashSet, /// The allocation ids to report about. pub tracked_alloc_ids: FxHashSet, /// For the tracked alloc ids, also report read/write accesses. pub track_alloc_accesses: bool, - /// Determine if data race detection should be enabled + /// Determine if data race detection should be enabled. pub data_race_detector: bool, - /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled + /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled. pub weak_memory_emulation: bool, + /// Determine if we are running in GenMC mode. In this mode, Miri will explore multiple concurrent executions of the given program. + pub genmc_mode: bool, /// Track when an outdated (weak memory) load happens. pub track_outdated_loads: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, @@ -137,7 +141,7 @@ pub struct MiriConfig { pub measureme_out: Option, /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, - /// Which provenance to use for int2ptr casts + /// Which provenance to use for int2ptr casts. pub provenance_mode: ProvenanceMode, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. @@ -155,7 +159,7 @@ pub struct MiriConfig { pub gc_interval: u32, /// The number of CPUs to be reported by miri. pub num_cpus: u32, - /// Requires Miri to emulate pages of a certain size + /// Requires Miri to emulate pages of a certain size. pub page_size: Option, /// Whether to collect a backtrace when each allocation is created, just in case it leaks. pub collect_leak_backtraces: bool, @@ -186,6 +190,7 @@ impl Default for MiriConfig { track_alloc_accesses: false, data_race_detector: true, weak_memory_emulation: true, + genmc_mode: false, track_outdated_loads: false, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, @@ -233,16 +238,22 @@ impl<'tcx> MainThreadState<'tcx> { match state.on_stack_empty(this)? { Poll::Pending => {} // just keep going Poll::Ready(()) => { - // Give background threads a chance to finish by yielding the main thread a - // couple of times -- but only if we would also preempt threads randomly. - if this.machine.preemption_rate > 0.0 { - // There is a non-zero chance they will yield back to us often enough to - // make Miri terminate eventually. - *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN }; - } else { - // The other threads did not get preempted, so no need to yield back to - // them. + if this.machine.data_race.as_genmc_ref().is_some() { + // In GenMC mode, we don't yield at the end of the main thread. + // Instead, the `GenmcCtx` will ensure that unfinished threads get a chance to run at this point. *self = Done; + } else { + // Give background threads a chance to finish by yielding the main thread a + // couple of times -- but only if we would also preempt threads randomly. + if this.machine.preemption_rate > 0.0 { + // There is a non-zero chance they will yield back to us often enough to + // make Miri terminate eventually. + *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN }; + } else { + // The other threads did not get preempted, so no need to yield back to + // them. + *self = Done; + } } } }, @@ -294,11 +305,16 @@ pub fn create_ecx<'tcx>( entry_id: DefId, entry_type: MiriEntryFnType, config: &MiriConfig, + genmc_ctx: Option>, ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { let typing_env = ty::TypingEnv::fully_monomorphized(); let layout_cx = LayoutCx::new(tcx, typing_env); - let mut ecx = - InterpCx::new(tcx, rustc_span::DUMMY_SP, typing_env, MiriMachine::new(config, layout_cx)); + let mut ecx = InterpCx::new( + tcx, + rustc_span::DUMMY_SP, + typing_env, + MiriMachine::new(config, layout_cx, genmc_ctx), + ); // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { @@ -452,12 +468,17 @@ pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, entry_type: MiriEntryFnType, - config: MiriConfig, + config: &MiriConfig, + genmc_ctx: Option>, ) -> Option { // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config).report_err() { + if let Some(genmc_ctx) = &genmc_ctx { + genmc_ctx.handle_execution_start(); + } + + let mut ecx = match create_ecx(tcx, entry_id, entry_type, config, genmc_ctx).report_err() { Ok(v) => v, Err(err) => { let (kind, backtrace) = err.into_parts(); @@ -476,9 +497,19 @@ pub fn eval_entry<'tcx>( // `Ok` can never happen; the interpreter loop always exits with an "error" // (but that "error" might be just "regular program termination"). let Err(err) = res.report_err(); + // Show diagnostic, if any. let (return_code, leak_check) = report_error(&ecx, err)?; + // We inform GenMC that the execution is complete. + if let Some(genmc_ctx) = ecx.machine.data_race.as_genmc_ref() + && let Err(error) = genmc_ctx.handle_execution_end(&ecx) + { + // FIXME(GenMC): Improve error reporting. + tcx.dcx().err(format!("GenMC returned an error: \"{error}\"")); + return None; + } + // If we get here there was no fatal error. // Possibly check for memory leaks. diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index dcafa7b6cabe..2eb8086f578f 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -149,7 +149,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // Perform regular load. let val = this.read_scalar(val)?; - // Perform atomic store + // Perform atomic store. this.write_scalar_atomic(val, &place, atomic)?; interp_ok(()) } @@ -161,7 +161,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let [] = check_intrinsic_arg_count(args)?; let _ = atomic; - //FIXME: compiler fences are currently ignored + // FIXME, FIXME(GenMC): compiler fences are currently ignored (also ignored in GenMC mode) interp_ok(()) } @@ -199,23 +199,16 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); } - match atomic_op { - AtomicOp::Min => { - let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - AtomicOp::Max => { - let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - AtomicOp::MirOp(op, not) => { - let old = this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - } + let old = match atomic_op { + AtomicOp::Min => + this.atomic_min_max_scalar(&place, rhs, /* min */ true, atomic)?, + AtomicOp::Max => + this.atomic_min_max_scalar(&place, rhs, /* min */ false, atomic)?, + AtomicOp::MirOp(op, not) => + this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?, + }; + this.write_immediate(*old, dest)?; // old value is returned + interp_ok(()) } fn atomic_exchange( diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index e03611e9b509..58b93ae82a1e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -133,6 +133,7 @@ pub use crate::concurrency::thread::{ BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; +pub use crate::concurrency::{GenmcConfig, GenmcCtx}; pub use crate::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 201b950e29ca..6060d41dac59 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -6,6 +6,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::path::Path; +use std::rc::Rc; use std::{fmt, process}; use rand::rngs::StdRng; @@ -27,9 +28,10 @@ use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{Span, SpanData, Symbol}; use rustc_target::callconv::FnAbi; +use crate::alloc_addresses::EvalContextExt; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; use crate::concurrency::data_race::{self, NaReadType, NaWriteType}; -use crate::concurrency::weak_memory; +use crate::concurrency::{AllocDataRaceHandler, GenmcCtx, GlobalDataRaceHandler, weak_memory}; use crate::*; /// First real-time signal. @@ -332,12 +334,10 @@ impl ProvenanceExtra { pub struct AllocExtra<'tcx> { /// Global state of the borrow tracker, if enabled. pub borrow_tracker: Option, - /// Data race detection via the use of a vector-clock. - /// This is only added if it is enabled. - pub data_race: Option, - /// Weak memory emulation via the use of store buffers. - /// This is only added if it is enabled. - pub weak_memory: Option, + /// Extra state for data race detection. + /// + /// Invariant: The enum variant must match the enum variant in the `data_race` field on `MiriMachine` + pub data_race: AllocDataRaceHandler, /// A backtrace to where this allocation was allocated. /// As this is recorded for leak reports, it only exists /// if this allocation is leakable. The backtrace is not @@ -360,11 +360,10 @@ impl<'tcx> Clone for AllocExtra<'tcx> { impl VisitProvenance for AllocExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _, sync: _ } = self; + let AllocExtra { borrow_tracker, data_race, backtrace: _, sync: _ } = self; borrow_tracker.visit_provenance(visit); data_race.visit_provenance(visit); - weak_memory.visit_provenance(visit); } } @@ -447,8 +446,12 @@ pub struct MiriMachine<'tcx> { /// Global data for borrow tracking. pub borrow_tracker: Option, - /// Data race detector global data. - pub data_race: Option, + /// Depending on settings, this will be `None`, + /// global data for a data race detector, + /// or the context required for running in GenMC mode. + /// + /// Invariant: The enum variant must match the enum variant of `AllocDataRaceHandler` in the `data_race` field of all `AllocExtra`. + pub data_race: GlobalDataRaceHandler, /// Ptr-int-cast module global data. pub alloc_addresses: alloc_addresses::GlobalState, @@ -544,9 +547,6 @@ pub struct MiriMachine<'tcx> { /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. pub(crate) mute_stdout_stderr: bool, - /// Whether weak memory emulation is enabled - pub(crate) weak_memory: bool, - /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, @@ -617,7 +617,11 @@ pub struct MiriMachine<'tcx> { } impl<'tcx> MiriMachine<'tcx> { - pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self { + pub(crate) fn new( + config: &MiriConfig, + layout_cx: LayoutCx<'tcx>, + genmc_ctx: Option>, + ) -> Self { let tcx = layout_cx.tcx(); let local_crates = helpers::get_local_crates(tcx); let layouts = @@ -636,7 +640,14 @@ impl<'tcx> MiriMachine<'tcx> { }); let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config)); - let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config)); + let data_race = if config.genmc_mode { + // `genmc_ctx` persists across executions, so we don't create a new one here. + GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap()) + } else if config.data_race_detector { + GlobalDataRaceHandler::Vclocks(Box::new(data_race::GlobalState::new(config))) + } else { + GlobalDataRaceHandler::None + }; // Determine page size, stack address, and stack size. // These values are mostly meaningless, but the stack address is also where we start // allocating physical integer addresses for all allocations. @@ -709,7 +720,6 @@ impl<'tcx> MiriMachine<'tcx> { check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, - weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, report_progress: config.report_progress, basic_block_count: 0, @@ -835,16 +845,25 @@ impl<'tcx> MiriMachine<'tcx> { .as_ref() .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine)); - let data_race = ecx.machine.data_race.as_ref().map(|data_race| { - data_race::AllocState::new_allocation( - data_race, - &ecx.machine.threads, - size, - kind, - ecx.machine.current_span(), - ) - }); - let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation); + let data_race = match &ecx.machine.data_race { + GlobalDataRaceHandler::None => AllocDataRaceHandler::None, + GlobalDataRaceHandler::Vclocks(data_race) => + AllocDataRaceHandler::Vclocks( + data_race::AllocState::new_allocation( + data_race, + &ecx.machine.threads, + size, + kind, + ecx.machine.current_span(), + ), + data_race.weak_memory.then(weak_memory::AllocState::new_allocation), + ), + GlobalDataRaceHandler::Genmc(_genmc_ctx) => { + // GenMC learns about new allocations directly from the alloc_addresses module, + // since it has to be able to control the address at which they are placed. + AllocDataRaceHandler::Genmc + } + }; // If an allocation is leaked, we want to report a backtrace to indicate where it was // allocated. We don't need to record a backtrace for allocations which are allowed to @@ -862,13 +881,7 @@ impl<'tcx> MiriMachine<'tcx> { .insert(id, (ecx.machine.current_span(), None)); } - interp_ok(AllocExtra { - borrow_tracker, - data_race, - weak_memory, - backtrace, - sync: FxHashMap::default(), - }) + interp_ok(AllocExtra { borrow_tracker, data_race, backtrace, sync: FxHashMap::default() }) } } @@ -909,7 +922,6 @@ impl VisitProvenance for MiriMachine<'_> { check_alignment: _, cmpxchg_weak_failure_rate: _, mute_stdout_stderr: _, - weak_memory: _, preemption_rate: _, report_progress: _, basic_block_count: _, @@ -1378,7 +1390,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &Self, alloc_extra: &AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { @@ -1386,15 +1398,25 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read)); } - if let Some(data_race) = &alloc_extra.data_race { - data_race.read(alloc_id, range, NaReadType::Read, None, machine)?; + // The order of checks is deliberate, to prefer reporting a data race over a borrow tracker error. + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.memory_load(machine, ptr.addr(), range.size)?, + GlobalDataRaceHandler::Vclocks(_data_race) => { + let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &alloc_extra.data_race + else { + unreachable!(); + }; + data_race.read(alloc_id, range, NaReadType::Read, None, machine)?; + if let Some(weak_memory) = weak_memory { + weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap()); + } + } } if let Some(borrow_tracker) = &alloc_extra.borrow_tracker { borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?; } - if let Some(weak_memory) = &alloc_extra.weak_memory { - weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); - } interp_ok(()) } @@ -1403,7 +1425,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { @@ -1411,15 +1433,26 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write)); } - if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?; + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => { + genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; + } + GlobalDataRaceHandler::Vclocks(_global_state) => { + let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = + &mut alloc_extra.data_race + else { + unreachable!() + }; + data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?; + if let Some(weak_memory) = weak_memory { + weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap()); + } + } } if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker { borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?; } - if let Some(weak_memory) = &alloc_extra.weak_memory { - weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); - } interp_ok(()) } @@ -1428,7 +1461,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), size: Size, align: Align, @@ -1437,14 +1470,20 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if machine.tracked_alloc_ids.contains(&alloc_id) { machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } - if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write( - alloc_id, - alloc_range(Size::ZERO, size), - NaWriteType::Deallocate, - None, - machine, - )?; + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, + GlobalDataRaceHandler::Vclocks(_global_state) => { + let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); + data_race.write( + alloc_id, + alloc_range(Size::ZERO, size), + NaWriteType::Deallocate, + None, + machine, + )?; + } } if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker { borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?; @@ -1531,7 +1570,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL), - data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()), + data_race: ecx + .machine + .data_race + .as_vclocks_ref() + .map(|_| data_race::FrameState::default()), }; interp_ok(frame.with_extra(extra)) @@ -1677,7 +1720,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(data_race) = &machine.threads.active_thread_stack().last().unwrap().extra.data_race { - data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine); + data_race.local_moved_to_memory( + local, + alloc_info.data_race.as_vclocks_mut().unwrap(), + machine, + ); } interp_ok(()) } From 3eee3dad5c8aa36a88d6ed2e927c53f2ba174819 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Mar 2025 16:11:45 +0300 Subject: [PATCH 159/302] resolve: Support imports of associated types and glob imports from traits --- .../src/error_codes/E0253.md | 6 ++- .../src/hir_ty_lowering/mod.rs | 34 +++++++------ compiler/rustc_resolve/messages.ftl | 7 --- compiler/rustc_resolve/src/diagnostics.rs | 8 ++- compiler/rustc_resolve/src/errors.rs | 16 ------ compiler/rustc_resolve/src/imports.rs | 43 ++++++++-------- compiler/rustc_resolve/src/lib.rs | 10 +--- tests/ui/error-codes/E0253.rs | 10 ---- tests/ui/error-codes/E0253.stderr | 9 ---- ...-gate-import-trait-associated-functions.rs | 3 ++ ...e-import-trait-associated-functions.stderr | 12 ++++- tests/ui/imports/issue-30560.rs | 3 -- tests/ui/imports/issue-30560.stderr | 8 +-- .../use/import_trait_associated_item_bad.rs | 18 +++++++ .../import_trait_associated_item_bad.stderr | 49 +++++++++++++++++++ .../use/import_trait_associated_item_glob.rs | 17 +++++++ tests/ui/use/use-from-trait-xc.rs | 2 +- tests/ui/use/use-from-trait-xc.stderr | 12 +++-- tests/ui/use/use-from-trait.rs | 2 +- tests/ui/use/use-from-trait.stderr | 12 +++-- 20 files changed, 168 insertions(+), 113 deletions(-) delete mode 100644 tests/ui/error-codes/E0253.rs delete mode 100644 tests/ui/error-codes/E0253.stderr create mode 100644 tests/ui/use/import_trait_associated_item_bad.rs create mode 100644 tests/ui/use/import_trait_associated_item_bad.stderr create mode 100644 tests/ui/use/import_trait_associated_item_glob.rs diff --git a/compiler/rustc_error_codes/src/error_codes/E0253.md b/compiler/rustc_error_codes/src/error_codes/E0253.md index 705d1bfc53e5..628f5e252fbb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0253.md +++ b/compiler/rustc_error_codes/src/error_codes/E0253.md @@ -1,9 +1,13 @@ +#### Note: this error code is no longer emitted by the compiler. + Attempt was made to import an unimportable type. This can happen when trying to import a type from a trait. Erroneous code example: -```compile_fail,E0253 +``` +#![feature(import_trait_associated_functions)] + mod foo { pub trait MyTrait { type SomeType; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fcb7382549f4..5e79e9320153 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1770,7 +1770,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { match self.lower_qpath_shared( @@ -1795,7 +1795,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Const<'tcx> { match self.lower_qpath_shared( @@ -1820,7 +1820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { @@ -1840,7 +1840,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?self_ty); let trait_ref = - self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false); + self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment.unwrap(), false); debug!(?trait_ref); let item_args = @@ -2196,16 +2196,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } Res::Def(DefKind::AssocTy, def_id) => { - debug_assert!(path.segments.len() >= 2); - let _ = self.prohibit_generic_args( - path.segments[..path.segments.len() - 2].iter(), - GenericsArgsErrExtend::None, - ); + let trait_segment = if let [modules @ .., trait_, _item] = path.segments { + let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); + Some(trait_) + } else { + None + }; self.lower_qpath_ty( span, opt_self_ty, def_id, - &path.segments[path.segments.len() - 2], + trait_segment, path.segments.last().unwrap(), ) } @@ -2413,16 +2414,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } Res::Def(DefKind::AssocConst, did) => { - debug_assert!(path.segments.len() >= 2); - let _ = self.prohibit_generic_args( - path.segments[..path.segments.len() - 2].iter(), - GenericsArgsErrExtend::None, - ); + let trait_segment = if let [modules @ .., trait_, _item] = path.segments { + let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); + Some(trait_) + } else { + None + }; self.lower_qpath_const( span, opt_self_ty, did, - &path.segments[path.segments.len() - 2], + trait_segment, path.segments.last().unwrap(), ) } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 558a01713dc7..38cdfa72a14d 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -218,10 +218,6 @@ resolve_invalid_asm_sym = .label = is a local variable .help = `sym` operands must refer to either a function or a static -resolve_is_not_directly_importable = - `{$target}` is not directly importable - .label = cannot be imported directly - resolve_is_private = {$ident_descr} `{$ident}` is private .label = private {$ident_descr} @@ -231,9 +227,6 @@ resolve_item_was_behind_feature = resolve_item_was_cfg_out = the item is gated here -resolve_items_in_traits_are_not_importable = - items in traits are not importable - resolve_label_with_similar_name_reachable = a label with a similar name is reachable diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 363a75911ad4..74daad083946 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1181,11 +1181,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } { let in_module_is_extern = !in_module.def_id().is_local(); in_module.for_each_child(self, |this, ident, ns, name_binding| { - // avoid non-importable candidates - if !name_binding.is_importable() - // FIXME(import_trait_associated_functions): remove this when `import_trait_associated_functions` is stable - || name_binding.is_assoc_const_or_fn() - && !this.tcx.features().import_trait_associated_functions() + // Avoid non-importable candidates. + if name_binding.is_assoc_item() + && !this.tcx.features().import_trait_associated_functions() { return; } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e26b300f13ef..7fe74378b674 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -781,22 +781,6 @@ pub(crate) struct CannotGlobImportAllCrates { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(resolve_items_in_traits_are_not_importable)] -pub(crate) struct ItemsInTraitsAreNotImportable { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(resolve_is_not_directly_importable, code = E0253)] -pub(crate) struct IsNotDirectlyImportable { - #[primary_span] - #[label] - pub(crate) span: Span, - pub(crate) target: Ident, -} - #[derive(Subdiagnostic)] #[suggestion( resolve_unexpected_res_change_ty_to_const_param_sugg, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 762e08b2be5f..816efd0d5fa2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -30,8 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, - ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable, - ItemsInTraitsAreNotImportable, + ConsiderAddingMacroExport, ConsiderMarkingAsPub, }; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, Finalize, ImportSuggestion, Module, @@ -835,11 +834,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent = import.parent_scope.module; match source_bindings[ns].get() { - Err(Undetermined) => indeterminate_count += 1, - // Don't update the resolution, because it was never added. - Err(Determined) if target.name == kw::Underscore => {} - Ok(binding) if binding.is_importable() => { - if binding.is_assoc_const_or_fn() + Ok(binding) => { + if binding.is_assoc_item() && !this.tcx.features().import_trait_associated_functions() { feature_err( @@ -850,21 +846,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } + let imported_binding = this.import(binding, import); target_bindings[ns].set(Some(imported_binding)); this.define(parent, target, ns, imported_binding); } - source_binding @ (Ok(..) | Err(Determined)) => { - if source_binding.is_ok() { - this.dcx() - .create_err(IsNotDirectlyImportable { span: import.span, target }) - .emit(); + Err(Determined) => { + // Don't update the resolution for underscores, because it was never added. + if target.name != kw::Underscore { + let key = BindingKey::new(target, ns); + this.update_resolution(parent, key, false, |_, resolution| { + resolution.single_imports.swap_remove(&import); + }); } - let key = BindingKey::new(target, ns); - this.update_resolution(parent, key, false, |_, resolution| { - resolution.single_imports.swap_remove(&import); - }); } + Err(Undetermined) => indeterminate_count += 1, } } }); @@ -1428,10 +1424,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; }; - if module.is_trait() { - self.dcx().emit_err(ItemsInTraitsAreNotImportable { span: import.span }); - return; - } else if module == import.parent_scope.module { + if module.is_trait() && !self.tcx.features().import_trait_associated_functions() { + feature_err( + self.tcx.sess, + sym::import_trait_associated_functions, + import.span, + "`use` associated items of traits is unstable", + ) + .emit(); + } + + if module == import.parent_scope.module { return; } else if is_prelude { self.prelude = Some(module); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d2da3ac7d86f..d23e588e2e3d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -949,14 +949,8 @@ impl<'ra> NameBindingData<'ra> { } } - fn is_importable(&self) -> bool { - !matches!(self.res(), Res::Def(DefKind::AssocTy, _)) - } - - // FIXME(import_trait_associated_functions): associate `const` or `fn` are not importable unless - // the feature `import_trait_associated_functions` is enable - fn is_assoc_const_or_fn(&self) -> bool { - matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn, _)) + fn is_assoc_item(&self) -> bool { + matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _)) } fn macro_kind(&self) -> Option { diff --git a/tests/ui/error-codes/E0253.rs b/tests/ui/error-codes/E0253.rs deleted file mode 100644 index 8284f791c648..000000000000 --- a/tests/ui/error-codes/E0253.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod foo { - pub trait MyTrait { - type SomeType; - } -} - -use foo::MyTrait::SomeType; - //~^ ERROR E0253 - -fn main() {} diff --git a/tests/ui/error-codes/E0253.stderr b/tests/ui/error-codes/E0253.stderr deleted file mode 100644 index 954dbc816939..000000000000 --- a/tests/ui/error-codes/E0253.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0253]: `SomeType` is not directly importable - --> $DIR/E0253.rs:7:5 - | -LL | use foo::MyTrait::SomeType; - | ^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0253`. diff --git a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs index aec13fb02028..c2c010eaba63 100644 --- a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs +++ b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs @@ -60,4 +60,7 @@ fn f() { let t: Option = DEFAULT; } +trait Glob {} +use Glob::*; //~ ERROR `use` associated items of traits is unstable + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr index d342f5bd5512..fca3cef3e203 100644 --- a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr +++ b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr @@ -48,6 +48,16 @@ LL | use super::A::{self, DEFAULT, new}; = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error[E0658]: `use` associated items of traits is unstable + --> $DIR/feature-gate-import-trait-associated-functions.rs:64:5 + | +LL | use Glob::*; + | ^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/imports/issue-30560.rs b/tests/ui/imports/issue-30560.rs index d8d4ca608f1c..fe5d17c18736 100644 --- a/tests/ui/imports/issue-30560.rs +++ b/tests/ui/imports/issue-30560.rs @@ -3,7 +3,4 @@ use Alias::*; //~ ERROR unresolved import `Alias` [E0432] use std::io::Result::*; //~ ERROR unresolved import `std::io::Result` [E0432] -trait T {} -use T::*; //~ ERROR items in traits are not importable - fn main() {} diff --git a/tests/ui/imports/issue-30560.stderr b/tests/ui/imports/issue-30560.stderr index 69cfd4c06a8b..89492261cbaf 100644 --- a/tests/ui/imports/issue-30560.stderr +++ b/tests/ui/imports/issue-30560.stderr @@ -1,9 +1,3 @@ -error: items in traits are not importable - --> $DIR/issue-30560.rs:7:5 - | -LL | use T::*; - | ^^^^ - error[E0432]: unresolved import `Alias` --> $DIR/issue-30560.rs:2:5 | @@ -16,6 +10,6 @@ error[E0432]: unresolved import `std::io::Result` LL | use std::io::Result::*; | ^^^^^^ `Result` is a type alias, not a module -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/use/import_trait_associated_item_bad.rs b/tests/ui/use/import_trait_associated_item_bad.rs new file mode 100644 index 000000000000..d3d2a8e83cdd --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_bad.rs @@ -0,0 +1,18 @@ +#![feature(import_trait_associated_functions)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] + +trait Trait { + type AssocTy; + const CONST: usize; +} + +use Trait::AssocTy; +type Alias1 = AssocTy; //~ ERROR ambiguous associated type +type Alias2 = self::AssocTy; //~ ERROR ambiguous associated type + +use Trait::CONST; +type Alias3 = [u8; CONST]; //~ ERROR ambiguous associated constant +type Alias4 = [u8; self::CONST]; //~ ERROR ambiguous associated constant + +fn main() {} diff --git a/tests/ui/use/import_trait_associated_item_bad.stderr b/tests/ui/use/import_trait_associated_item_bad.stderr new file mode 100644 index 000000000000..d5cd5d37bd71 --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_bad.stderr @@ -0,0 +1,49 @@ +error[E0223]: ambiguous associated type + --> $DIR/import_trait_associated_item_bad.rs:11:15 + | +LL | type Alias1 = AssocTy; + | ^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | type Alias1 = ::AssocTy; + | ++++++++++++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/import_trait_associated_item_bad.rs:12:15 + | +LL | type Alias2 = self::AssocTy; + | ^^^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL - type Alias2 = self::AssocTy; +LL + type Alias2 = ::AssocTy; + | + +error[E0223]: ambiguous associated constant + --> $DIR/import_trait_associated_item_bad.rs:15:20 + | +LL | type Alias3 = [u8; CONST]; + | ^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | type Alias3 = [u8; ::CONST]; + | ++++++++++++++++++++ + +error[E0223]: ambiguous associated constant + --> $DIR/import_trait_associated_item_bad.rs:16:20 + | +LL | type Alias4 = [u8; self::CONST]; + | ^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL - type Alias4 = [u8; self::CONST]; +LL + type Alias4 = [u8; ::CONST]; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/use/import_trait_associated_item_glob.rs b/tests/ui/use/import_trait_associated_item_glob.rs new file mode 100644 index 000000000000..8a712514ed59 --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_glob.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![feature(import_trait_associated_functions)] + +trait Trait: Default { + fn f() -> Self { Default::default() } + fn g() -> Self { Default::default() } +} + +impl Trait for u8 {} + +use Trait::*; + +fn main() { + let _: u8 = f(); + let _: u8 = g(); +} diff --git a/tests/ui/use/use-from-trait-xc.rs b/tests/ui/use/use-from-trait-xc.rs index b030892aa269..220bf8cad46f 100644 --- a/tests/ui/use/use-from-trait-xc.rs +++ b/tests/ui/use/use-from-trait-xc.rs @@ -6,7 +6,7 @@ use use_from_trait_xc::Trait::foo; //~^ ERROR `use` associated items of traits is unstable [E0658] use use_from_trait_xc::Trait::Assoc; -//~^ ERROR `Assoc` is not directly importable +//~^ ERROR `use` associated items of traits is unstable [E0658] use use_from_trait_xc::Trait::CONST; //~^ ERROR `use` associated items of traits is unstable [E0658] diff --git a/tests/ui/use/use-from-trait-xc.stderr b/tests/ui/use/use-from-trait-xc.stderr index 0f8440aa5307..c8ee29b18d0c 100644 --- a/tests/ui/use/use-from-trait-xc.stderr +++ b/tests/ui/use/use-from-trait-xc.stderr @@ -8,11 +8,15 @@ LL | use use_from_trait_xc::Trait::foo; = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0253]: `Assoc` is not directly importable +error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait-xc.rs:8:5 | LL | use use_from_trait_xc::Trait::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait-xc.rs:11:5 @@ -74,5 +78,5 @@ LL | struct Foo; error: aborting due to 9 previous errors -Some errors have detailed explanations: E0253, E0432, E0603, E0658. -For more information about an error, try `rustc --explain E0253`. +Some errors have detailed explanations: E0432, E0603, E0658. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/use/use-from-trait.rs b/tests/ui/use/use-from-trait.rs index 89b7aaa4ba38..cab661a29e8e 100644 --- a/tests/ui/use/use-from-trait.rs +++ b/tests/ui/use/use-from-trait.rs @@ -1,5 +1,5 @@ use Trait::foo; //~ ERROR `use` associated items of traits is unstable [E0658] -use Trait::Assoc; //~ ERROR `Assoc` is not directly importable +use Trait::Assoc; //~ ERROR `use` associated items of traits is unstable [E0658] use Trait::C; //~ ERROR `use` associated items of traits is unstable [E0658] use Foo::new; //~ ERROR unresolved import `Foo` [E0432] diff --git a/tests/ui/use/use-from-trait.stderr b/tests/ui/use/use-from-trait.stderr index 2dd78a354529..63cfcc207504 100644 --- a/tests/ui/use/use-from-trait.stderr +++ b/tests/ui/use/use-from-trait.stderr @@ -8,11 +8,15 @@ LL | use Trait::foo; = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0253]: `Assoc` is not directly importable +error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait.rs:2:5 | LL | use Trait::Assoc; - | ^^^^^^^^^^^^ cannot be imported directly + | ^^^^^^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait.rs:3:5 @@ -38,5 +42,5 @@ LL | use Foo::C2; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0253, E0432, E0658. -For more information about an error, try `rustc --explain E0253`. +Some errors have detailed explanations: E0432, E0658. +For more information about an error, try `rustc --explain E0432`. From 842858f7650cae36d1b7194e4c758f42b2ca700c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 30 Apr 2025 13:02:45 +0300 Subject: [PATCH 160/302] linker: Quote symbol names in .def files To support weird symbol names, including dots in particular. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 +++- tests/ui/linking/weird-export-names.rs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/ui/linking/weird-export-names.rs diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a09eec5dd74b..e1f903726fbd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -816,7 +816,9 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "EXPORTS")?; for symbol in symbols { debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; + // Quote the name in case it's reserved by linker in some way + // (this accounts for names with dots in particular). + writeln!(f, " \"{symbol}\"")?; } }; if let Err(error) = res { diff --git a/tests/ui/linking/weird-export-names.rs b/tests/ui/linking/weird-export-names.rs new file mode 100644 index 000000000000..8fb2dc6bf5e8 --- /dev/null +++ b/tests/ui/linking/weird-export-names.rs @@ -0,0 +1,10 @@ +//@ build-pass +//@ needs-crate-type: cdylib + +#![crate_type = "cdylib"] + +#[export_name = "foo.0123"] +pub extern "C" fn foo() {} + +#[export_name = "EXPORTS"] +pub extern "C" fn bar() {} From 6a48217efc1e5874eda45ac7a1af6c3a12fe7d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 2 May 2025 14:55:36 +0200 Subject: [PATCH 161/302] Move `DisambiguatorState` into `intern_const_alloc_recursive` --- .../src/const_eval/dummy_machine.rs | 4 +- .../src/const_eval/machine.rs | 5 +-- .../rustc_const_eval/src/interpret/intern.rs | 37 +++++++++++++------ .../rustc_const_eval/src/interpret/util.rs | 5 +-- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index dc5f84adb76f..46dcebc46e9c 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -1,5 +1,3 @@ -use rustc_hir::def_id::LocalDefId; -use rustc_hir::definitions::DisambiguatorState; use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult}; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; @@ -44,7 +42,7 @@ pub macro throw_machine_stop_str($($tt:tt)*) {{ pub struct DummyMachine; impl HasStaticRootDefId for DummyMachine { - fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)> { + fn static_def_id(&self) -> Option { None } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index dddfc6a4e092..61a7ec13511c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -6,7 +6,6 @@ use rustc_abi::{Align, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; @@ -64,7 +63,7 @@ pub struct CompileTimeMachine<'tcx> { /// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`, /// storing the result in the given `AllocId`. /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops. - pub(crate) static_root_ids: Option<(AllocId, LocalDefId, DisambiguatorState)>, + pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). union_data_ranges: FxHashMap, RangeSet>, @@ -707,7 +706,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { // Check if this is the currently evaluated static. - if Some(alloc_id) == ecx.machine.static_root_ids.as_ref().map(|(id, ..)| *id) { + if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 47cc2d49fe27..1dd96297d1fd 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -46,13 +46,12 @@ pub trait CompileTimeMachine<'tcx, T> = Machine< pub trait HasStaticRootDefId { /// Returns the `DefId` of the static item that is currently being evaluated. /// Used for interning to be able to handle nested allocations. - fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)>; + fn static_def_id(&self) -> Option; } impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { - fn static_parent_and_disambiguator(&mut self) -> Option<(LocalDefId, &mut DisambiguatorState)> { - let (_, static_id, d) = self.static_root_ids.as_mut()?; - Some((*static_id, d)) + fn static_def_id(&self) -> Option { + Some(self.static_root_ids?.1) } } @@ -67,6 +66,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, + disambiguator: Option<&mut DisambiguatorState>, ) -> Result + 'tcx, ()> { trace!("intern_shallow {:?}", alloc_id); // remove allocation @@ -88,8 +88,14 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( } // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); - if let Some((static_id, disambiguator)) = ecx.machine.static_parent_and_disambiguator() { - intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc, disambiguator); + if let Some(static_id) = ecx.machine.static_def_id() { + intern_as_new_static( + ecx.tcx, + static_id, + alloc_id, + alloc, + disambiguator.expect("disambiguator needed"), + ); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } @@ -105,6 +111,10 @@ fn intern_as_new_static<'tcx>( alloc: ConstAllocation<'tcx>, disambiguator: &mut DisambiguatorState, ) { + // `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`. + // The `::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the + // `DisambiguatorState` ensures the generated path is unique for this call as we generate + // `::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call. let feed = tcx.create_def( static_id, None, @@ -158,6 +168,8 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), InternResult> { + let mut disambiguator = DisambiguatorState::new(); + // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. let (base_mutability, inner_mutability, is_static) = match intern_kind { @@ -201,7 +213,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval alloc.1.mutability = base_mutability; alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().collect() + intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator)) + .unwrap() + .collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -295,7 +309,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - match intern_shallow(ecx, alloc_id, inner_mutability) { + match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) { Ok(nested) => todo.extend(nested), Err(()) => { ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning"); @@ -317,8 +331,9 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> return interp_ok(()); } // Move allocation to `tcx`. - if let Some(_) = - (intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?).next() + if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None) + .map_err(|()| err_ub!(DeadLocal))? + .next() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a @@ -344,7 +359,7 @@ impl<'tcx> InterpCx<'tcx, DummyMachine> { let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance - for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() { + for prov in intern_shallow(self, alloc_id, Mutability::Not, None).unwrap() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index faaa2bd24bbd..ba579e25f036 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,5 +1,4 @@ use rustc_hir::def_id::LocalDefId; -use rustc_hir::definitions::DisambiguatorState; use rustc_middle::mir; use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; @@ -41,8 +40,8 @@ pub(crate) fn create_static_alloc<'tcx>( ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); - assert!(ecx.machine.static_root_ids.is_none()); - ecx.machine.static_root_ids = Some((alloc_id, static_def_id, DisambiguatorState::new())); + assert_eq!(ecx.machine.static_root_ids, None); + ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } From a8fb9d0979ae883967c23e956b617774b8c4a000 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 May 2025 17:26:48 +0200 Subject: [PATCH 162/302] refactor: Simplify macro call id construction --- src/tools/rust-analyzer/Cargo.toml | 1 + .../crates/hir-def/src/expr_store/expander.rs | 31 +++++- .../rust-analyzer/crates/hir-def/src/lib.rs | 99 ++----------------- .../hir-def/src/macro_expansion_tests/mbe.rs | 10 +- .../hir-def/src/macro_expansion_tests/mod.rs | 85 ++++++++-------- .../crates/hir-def/src/nameres/assoc.rs | 18 ++-- .../crates/hir-def/src/nameres/collector.rs | 42 +++----- .../rust-analyzer/crates/syntax/Cargo.toml | 2 +- 8 files changed, 113 insertions(+), 175 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index dd39cf59bb44..c4c2fdf34bae 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,6 +131,7 @@ process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" +rowan = "=0.15.15" salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] } salsa-macros = "0.21.1" semver = "1.0.26" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index d24f4b7028d7..3823fb5a1e75 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -5,20 +5,22 @@ use std::mem; use base_db::Crate; use cfg::CfgOptions; use drop_bomb::DropBomb; +use hir_expand::AstId; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, }; use span::{AstIdMap, Edition, SyntaxContext}; use syntax::ast::HasAttrs; -use syntax::{Parse, ast}; +use syntax::{AstNode, Parse, ast}; use triomphe::Arc; use tt::TextRange; use crate::attr::Attrs; use crate::expr_store::HygieneId; +use crate::macro_call_as_call_id; use crate::nameres::DefMap; -use crate::{AsMacroCall, MacroId, UnresolvedMacro, db::DefDatabase}; +use crate::{MacroId, UnresolvedMacro, db::DefDatabase}; #[derive(Debug)] pub(super) struct Expander { @@ -92,8 +94,31 @@ impl Expander { let result = self.within_limit(db, |this| { let macro_call = this.in_file(¯o_call); - match macro_call.as_call_id_with_errors( + + let expands_to = hir_expand::ExpandTo::from_call_site(macro_call.value); + let ast_id = AstId::new(macro_call.file_id, this.ast_id_map().ast_id(macro_call.value)); + let path = macro_call.value.path().and_then(|path| { + let range = path.syntax().text_range(); + let mod_path = ModPath::from_src(db, path, &mut |range| { + this.span_map.span_for_range(range).ctx + })?; + let call_site = this.span_map.span_for_range(range); + Some((call_site, mod_path)) + }); + + let Some((call_site, path)) = path else { + return ExpandResult::only_err(ExpandError::other( + this.span_map.span_for_range(macro_call.value.syntax().text_range()), + "malformed macro invocation", + )); + }; + + match macro_call_as_call_id( db, + ast_id, + &path, + call_site.ctx, + expands_to, krate, |path| resolver(path).map(|it| db.macro_def(it)), eager_callback, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index cf65e6355925..28011bda7c54 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -64,8 +64,8 @@ use std::hash::{Hash, Hasher}; use base_db::{Crate, impl_intern_key}; use hir_expand::{ - AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, - MacroDefId, MacroDefKind, + AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, + MacroDefKind, builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, eager::expand_eager_macro_input, @@ -79,7 +79,7 @@ use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; -use syntax::{AstNode, ast}; +use syntax::ast; pub use hir_expand::{Intern, Lookup, tt}; @@ -1166,66 +1166,6 @@ impl ModuleDefId { }) } } - -// FIXME: Replace this with a plain function, it only has one impl -/// A helper trait for converting to MacroCallId -trait AsMacroCall { - fn as_call_id_with_errors( - &self, - db: &dyn ExpandDatabase, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), - ) -> Result>, UnresolvedMacro>; -} - -impl AsMacroCall for InFile<&ast::MacroCall> { - fn as_call_id_with_errors( - &self, - db: &dyn ExpandDatabase, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), - ) -> Result>, UnresolvedMacro> { - let expands_to = hir_expand::ExpandTo::from_call_site(self.value); - let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); - let span_map = db.span_map(self.file_id); - let path = self.value.path().and_then(|path| { - let range = path.syntax().text_range(); - let mod_path = ModPath::from_src(db, path, &mut |range| { - span_map.as_ref().span_for_range(range).ctx - })?; - let call_site = span_map.span_for_range(range); - Some((call_site, mod_path)) - }); - - let Some((call_site, path)) = path else { - return Ok(ExpandResult::only_err(ExpandError::other( - span_map.span_for_range(self.value.syntax().text_range()), - "malformed macro invocation", - ))); - }; - - macro_call_as_call_id_with_eager( - db, - ast_id, - &path, - call_site.ctx, - expands_to, - krate, - resolver, - resolver, - eager_callback, - ) - } -} - /// Helper wrapper for `AstId` with `ModPath` #[derive(Clone, Debug, Eq, PartialEq)] struct AstIdWithPath { @@ -1239,41 +1179,14 @@ impl AstIdWithPath { } } -fn macro_call_as_call_id( - db: &dyn ExpandDatabase, - call: &AstIdWithPath, - call_site: SyntaxContext, - expand_to: ExpandTo, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), -) -> Result, UnresolvedMacro> { - macro_call_as_call_id_with_eager( - db, - call.ast_id, - &call.path, - call_site, - expand_to, - krate, - resolver, - resolver, - eager_callback, - ) - .map(|res| res.value) -} - -fn macro_call_as_call_id_with_eager( +pub fn macro_call_as_call_id( db: &dyn ExpandDatabase, ast_id: AstId, path: &ModPath, call_site: SyntaxContext, expand_to: ExpandTo, krate: Crate, - resolver: impl FnOnce(&ModPath) -> Option, - eager_resolver: impl Fn(&ModPath) -> Option, + resolver: impl Fn(&ModPath) -> Option + Copy, eager_callback: &mut dyn FnMut( InFile<(syntax::AstPtr, span::FileAstId)>, MacroCallId, @@ -1289,7 +1202,7 @@ fn macro_call_as_call_id_with_eager( ast_id, def, call_site, - &|path| eager_resolver(path).filter(MacroDefId::is_fn_like), + &|path| resolver(path).filter(MacroDefId::is_fn_like), eager_callback, ), _ if def.is_fn_like() => ExpandResult { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index abb5bd5ed726..38fc4b3d118a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -2001,8 +2001,9 @@ macro_rules! bug { true }; } - -let _ = bug!(a;;;test); +fn f() { + let _ = bug!(a;;;test); +} "#, expect![[r#" macro_rules! bug { @@ -2022,8 +2023,9 @@ macro_rules! bug { true }; } - -let _ = true; +fn f() { + let _ = true; +} "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 143b5df77305..800c96ebdae0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -19,7 +19,7 @@ use std::{iter, ops::Range, sync}; use base_db::RootQueryDb; use expect_test::Expect; use hir_expand::{ - InFile, MacroCallKind, MacroKind, + AstId, InFile, MacroCallId, MacroCallKind, MacroKind, db::ExpandDatabase, proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind}, span_map::SpanMapRef, @@ -29,7 +29,7 @@ use itertools::Itertools; use span::{Edition, Span}; use stdx::{format_to, format_to_acc}; use syntax::{ - AstNode, + AstNode, AstPtr, SyntaxKind::{COMMENT, EOF, IDENT, LIFETIME_IDENT}, SyntaxNode, T, ast::{self, edit::IndentLevel}, @@ -37,10 +37,9 @@ use syntax::{ use test_fixture::WithFixture; use crate::{ - AdtId, AsMacroCall, Lookup, ModuleDefId, + AdtId, Lookup, ModuleDefId, db::DefDatabase, - nameres::{DefMap, MacroSubNs, ModuleSource}, - resolver::HasResolver, + nameres::{DefMap, ModuleSource}, src::HasSource, test_db::TestDB, tt::TopSubtree, @@ -78,7 +77,6 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) expect.assert_eq(&errors); } -#[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { let extra_proc_macros = vec![( r#" @@ -95,54 +93,59 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream disabled: false, }, )]; + + fn resolve( + db: &dyn DefDatabase, + def_map: &DefMap, + ast_id: AstId, + ast_ptr: InFile>, + ) -> Option { + def_map.modules().find_map(|module| { + for decl in + module.1.scope.declarations().chain(module.1.scope.unnamed_consts().map(Into::into)) + { + let body = match decl { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => continue, + }; + + let (body, sm) = db.body_with_source_map(body); + if let Some(it) = + body.blocks(db).find_map(|block| resolve(db, &block.1, ast_id, ast_ptr)) + { + return Some(it); + } + if let Some((_, res)) = sm.macro_calls().find(|it| it.0 == ast_ptr) { + return Some(res); + } + } + module.1.scope.macro_invoc(ast_id) + }) + } + let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); let krate = db.fetch_test_crate(); let def_map = db.crate_def_map(krate); let local_id = DefMap::ROOT; - let module = def_map.module_id(local_id); - let resolver = module.resolver(&db); let source = def_map[local_id].definition_source(&db); let source_file = match source.value { ModuleSource::SourceFile(it) => it, ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), }; - // What we want to do is to replace all macros (fn-like, derive, attr) with - // their expansions. Turns out, we don't actually store enough information - // to do this precisely though! Specifically, if a macro expands to nothing, - // it leaves zero traces in def-map, so we can't get its expansion after the - // fact. - // - // This is the usual - // - // resolve/record tension! - // - // So here we try to do a resolve, which is necessary a heuristic. For macro - // calls, we use `as_call_id_with_errors`. For derives, we look at the impls - // in the module and assume that, if impls's source is a different - // `HirFileId`, than it came from macro expansion. - let mut text_edits = Vec::new(); let mut expansions = Vec::new(); - for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { - let macro_call = InFile::new(source.file_id, ¯o_call); - let res = macro_call - .as_call_id_with_errors( - &db, - krate, - |path| { - resolver - .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang)) - .map(|(it, _)| db.macro_def(it)) - }, - &mut |_, _| (), - ) - .unwrap(); - let macro_call_id = res.value.unwrap(); - let mut expansion_result = db.parse_macro_expansion(macro_call_id); - expansion_result.err = expansion_result.err.or(res.err); - expansions.push((macro_call.value.clone(), expansion_result)); + for macro_call_node in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { + let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); + let ast_id = InFile::new(source.file_id, ast_id); + let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); + let macro_call_id = resolve(&db, &def_map, ast_id, ptr) + .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}")); + let expansion_result = db.parse_macro_expansion(macro_call_id); + expansions.push((macro_call_node.clone(), expansion_result)); } for (call, exp) in expansions.into_iter().rev() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index b09706552947..448b908936a2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -259,7 +259,8 @@ impl<'a> AssocItemCollector<'a> { }; match macro_call_as_call_id( self.db, - &AstIdWithPath::new(tree_id.file_id(), ast_id, Clone::clone(path)), + InFile::new(tree_id.file_id(), ast_id), + path, ctxt, expand_to, self.module_id.krate(), @@ -268,12 +269,15 @@ impl<'a> AssocItemCollector<'a> { self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id)) }, ) { - Ok(Some(call_id)) => { - self.macro_calls - .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); - self.collect_macro_items(call_id); - } - Ok(None) => (), + // FIXME: Expansion error? + Ok(call_id) => match call_id.value { + Some(call_id) => { + self.macro_calls + .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); + self.collect_macro_items(call_id); + } + None => (), + }, Err(_) => { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.module_id.local_id, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 77effbcc8800..8df0f092cd0b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -39,7 +39,7 @@ use crate::{ ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, - macro_call_as_call_id, macro_call_as_call_id_with_eager, + macro_call_as_call_id, nameres::{ BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode, attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id}, @@ -1256,7 +1256,8 @@ impl DefCollector<'_> { MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => { let call_id = macro_call_as_call_id( self.db, - ast_id, + ast_id.ast_id, + &ast_id.path, *call_site, *expand_to, self.def_map.krate, @@ -1265,15 +1266,18 @@ impl DefCollector<'_> { eager_callback_buffer.push((directive.module_id, ptr, call_id)); }, ); - if let Ok(Some(call_id)) = call_id { - self.def_map.modules[directive.module_id] - .scope - .add_macro_invoc(ast_id.ast_id, call_id); + if let Ok(call_id) = call_id { + // FIXME: Expansion error + if let Some(call_id) = call_id.value { + self.def_map.modules[directive.module_id] + .scope + .add_macro_invoc(ast_id.ast_id, call_id); - push_resolved(directive, call_id); + push_resolved(directive, call_id); - res = ReachedFixedPoint::No; - return Resolved::Yes; + res = ReachedFixedPoint::No; + return Resolved::Yes; + } } } MacroDirectiveKind::Derive { @@ -1542,7 +1546,8 @@ impl DefCollector<'_> { // FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error! let macro_call_as_call_id = macro_call_as_call_id( self.db, - ast_id, + ast_id.ast_id, + &ast_id.path, *call_site, *expand_to, self.def_map.krate, @@ -2420,7 +2425,7 @@ impl ModCollector<'_, '_> { let mut eager_callback_buffer = vec![]; // Case 1: try to resolve macro calls with single-segment name and expand macro_rules - if let Ok(res) = macro_call_as_call_id_with_eager( + if let Ok(res) = macro_call_as_call_id( db, ast_id.ast_id, &ast_id.path, @@ -2445,21 +2450,6 @@ impl ModCollector<'_, '_> { .map(|it| self.def_collector.db.macro_def(it)) }) }, - |path| { - let resolved_res = self.def_collector.def_map.resolve_path_fp_with_macro( - self.def_collector - .crate_local_def_map - .as_deref() - .unwrap_or(&self.def_collector.local_def_map), - db, - ResolveMode::Other, - self.module_id, - path, - BuiltinShadowMode::Module, - Some(MacroSubNs::Bang), - ); - resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it)) - }, &mut |ptr, call_id| eager_callback_buffer.push((ptr, call_id)), ) { for (ptr, call_id) in eager_callback_buffer { diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 510d44d00917..4c7704803ef3 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -14,7 +14,7 @@ rust-version.workspace = true [dependencies] either.workspace = true itertools.workspace = true -rowan = "=0.15.15" +rowan.workspace = true rustc-hash.workspace = true rustc-literal-escaper.workspace = true smol_str.workspace = true From 9eb1e83a12121302dd5ae09c7ba419de08e2da34 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sat, 3 May 2025 00:31:33 +0900 Subject: [PATCH 163/302] fix: Correct assoc ty bound var starting index --- .../crates/hir-ty/src/chalk_db.rs | 5 +++- .../crates/hir-ty/src/tests/regression.rs | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 376daccbdae8..cd799c03ddf7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -637,7 +637,10 @@ pub(crate) fn associated_ty_data_query( .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0) .build(); let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst)) - .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self()) + .fill_with_bound_vars( + crate::DebruijnIndex::INNERMOST, + generic_params.parent_generics().map_or(0, |it| it.len()), + ) .build(); let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 644b0d392bcf..47c695c69748 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2278,3 +2278,26 @@ fn test(x: bool) { "#]], ); } + +#[test] +fn issue_19730() { + check_infer( + r#" +trait Trait {} + +trait Foo { + type Bar: Trait; + + fn foo(bar: Self::Bar) { + let _ = bar; + } +} +"#, + expect![[r#" + 83..86 'bar': Foo::Bar + 105..133 '{ ... }': () + 119..120 '_': Foo::Bar + 123..126 'bar': Foo::Bar + "#]], + ); +} From 867b4c9e489c71246915ebe3e1ceddef66d760a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 2 May 2025 13:26:35 +0200 Subject: [PATCH 164/302] Test that names of variables in external macros are not shown on a borrow error --- .../rustc_borrowck/src/diagnostics/mod.rs | 8 +++++ .../auxiliary/return_from_external_macro.rs | 11 +++++++ tests/ui/macros/return_from_external_macro.rs | 17 +++++++++++ .../macros/return_from_external_macro.stderr | 29 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 tests/ui/macros/auxiliary/return_from_external_macro.rs create mode 100644 tests/ui/macros/return_from_external_macro.rs create mode 100644 tests/ui/macros/return_from_external_macro.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f9f63ae92a84..5e3f3ffa2ea8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -317,6 +317,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { opt: DescribePlaceOpt, ) -> Option { let local = place.local; + if self.body.local_decls[local] + .source_info + .span + .in_external_macro(self.infcx.tcx.sess.source_map()) + { + return None; + } + let mut autoderef_index = None; let mut buf = String::new(); let mut ok = self.append_local_to_string(local, &mut buf); diff --git a/tests/ui/macros/auxiliary/return_from_external_macro.rs b/tests/ui/macros/auxiliary/return_from_external_macro.rs new file mode 100644 index 000000000000..df59d8bdcb0d --- /dev/null +++ b/tests/ui/macros/auxiliary/return_from_external_macro.rs @@ -0,0 +1,11 @@ +#![feature(super_let)] + +#[macro_export] +macro_rules! foo { + () => { + { + super let args = 1; + &args + } + }; +} diff --git a/tests/ui/macros/return_from_external_macro.rs b/tests/ui/macros/return_from_external_macro.rs new file mode 100644 index 000000000000..43fe99e63add --- /dev/null +++ b/tests/ui/macros/return_from_external_macro.rs @@ -0,0 +1,17 @@ +//@ aux-crate: ret_from_ext=return_from_external_macro.rs + +#![feature(super_let)] +extern crate ret_from_ext; + +fn foo() -> impl Sized { + drop(|| ret_from_ext::foo!()); + //~^ ERROR cannot return reference to local binding + + ret_from_ext::foo!() + //~^ ERROR temporary value dropped while borrowed +} +//~^ NOTE temporary value is freed at the end of this statement + +fn main() { + foo(); +} diff --git a/tests/ui/macros/return_from_external_macro.stderr b/tests/ui/macros/return_from_external_macro.stderr new file mode 100644 index 000000000000..b6010b8ec793 --- /dev/null +++ b/tests/ui/macros/return_from_external_macro.stderr @@ -0,0 +1,29 @@ +error[E0515]: cannot return reference to local binding + --> $DIR/return_from_external_macro.rs:7:13 + | +LL | drop(|| ret_from_ext::foo!()); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | returns a reference to data owned by the current function + | local binding introduced here + | + = note: this error originates in the macro `ret_from_ext::foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> $DIR/return_from_external_macro.rs:10:5 + | +LL | ret_from_ext::foo!() + | ^^^^^^^^^^^^^^^^^^^^ + | | + | creates a temporary value which is freed while still in use + | opaque type requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + | + = note: this error originates in the macro `ret_from_ext::foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0515, E0716. +For more information about an error, try `rustc --explain E0515`. From 3cc172074a1ed94aa90372360688a000b47e6946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 2 May 2025 13:44:51 +0200 Subject: [PATCH 165/302] collateral damage in derive tests, improves errors by not refering to implementation details --- .../deriving-with-repr-packed-move-errors.rs | 18 ++++----- ...riving-with-repr-packed-move-errors.stderr | 39 ++++++++++--------- tests/ui/derives/deriving-with-repr-packed.rs | 2 +- .../derives/deriving-with-repr-packed.stderr | 12 +++--- .../lifetime_errors_on_promotion_misusage.rs | 4 +- ...fetime_errors_on_promotion_misusage.stderr | 16 ++++---- 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.rs b/tests/ui/derives/deriving-with-repr-packed-move-errors.rs index ffeb02d78b84..17aa750332c4 100644 --- a/tests/ui/derives/deriving-with-repr-packed-move-errors.rs +++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.rs @@ -11,15 +11,15 @@ use std::cmp::Ordering; #[repr(packed)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] struct StructA(String); -//~^ ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference +//~^ ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] // Unrelated impl: additinal diagnostic should NOT be emitted diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr index 68c3c8ae9ead..4b085425033d 100644 --- a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ----- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -12,13 +12,13 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -26,27 +26,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -54,27 +55,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -82,27 +84,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -110,13 +113,13 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ----- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index d17b52842cef..cba0413c992e 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -20,7 +20,7 @@ struct Y(usize); #[derive(Debug, Default)] #[repr(packed)] struct X(Y); -//~^ ERROR cannot move out of `self` which is behind a shared reference +//~^ ERROR cannot move out of a shared reference [E0507] #[derive(Debug)] #[repr(packed)] diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 5117f8d1112c..9cfc4abdc0cb 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:22:10 | LL | #[derive(Debug, Default)] | ----- in this derive macro expansion LL | #[repr(packed)] LL | struct X(Y); - | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait + | ^ move occurs because value has type `Y`, which does not implement the `Copy` trait | note: if `Y` implemented `Clone`, you could clone the value --> $DIR/deriving-with-repr-packed.rs:16:1 @@ -23,14 +23,14 @@ error[E0161]: cannot move a value of type `[u8]` LL | data: [u8], | ^^^^^^^^^^ the size of `[u8]` cannot be statically determined -error[E0507]: cannot move out of `self.data` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:29:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: [u8], - | ^^^^^^^^^^ move occurs because `self.data` has type `[u8]`, which does not implement the `Copy` trait + | ^^^^^^^^^^ move occurs because value has type `[u8]`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour @@ -40,14 +40,14 @@ error[E0161]: cannot move a value of type `str` LL | data: str, | ^^^^^^^^^ the size of `str` cannot be statically determined -error[E0507]: cannot move out of `self.data` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:38:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: str, - | ^^^^^^^^^ move occurs because `self.data` has type `str`, which does not implement the `Copy` trait + | ^^^^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs index e505fe435207..2771b4717fbf 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs @@ -9,14 +9,14 @@ use core::{ fn function_call_stops_borrow_extension() { let phantom_pinned = identity(pin!(PhantomPinned)); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed [E0716] stuff(phantom_pinned) } fn promotion_only_works_for_the_innermost_block() { let phantom_pinned = { let phantom_pinned = pin!(PhantomPinned); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed [E0716] phantom_pinned }; stuff(phantom_pinned) diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr index 43fb82be7c2f..4ecc6370d3ca 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr @@ -1,29 +1,31 @@ -error[E0597]: value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35 | LL | let phantom_pinned = identity(pin!(PhantomPinned)); - | ^^^^^^^^^^^^^^^^^^^ - value dropped here while still borrowed + | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | borrowed value does not live long enough + | creates a temporary value which is freed while still in use LL | LL | stuff(phantom_pinned) | -------------- borrow later used here | + = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0597]: value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30 | LL | let phantom_pinned = { | -------------- borrow later stored here LL | let phantom_pinned = pin!(PhantomPinned); - | ^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use ... LL | }; - | - value dropped here while still borrowed + | - temporary value is freed at the end of this statement | + = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. From 5424e4f1db86d49e632d8a8e96f400e012c9153f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 2 May 2025 16:36:48 +0200 Subject: [PATCH 166/302] remove an unused codepath --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0f8acadb978c..3b7d31b1b13b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2954,12 +2954,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) { - // Don't name local variables in external macros. - "value".to_string() - } else { - format!("`{name}`") - }; + let name = format!("`{name}`"); let mut err = self.path_does_not_live_long_enough(borrow_span, &name); From 8b3637635b46d74dfa7bcd1a7d30910c02b48ec4 Mon Sep 17 00:00:00 2001 From: Xinglu Chen Date: Wed, 30 Apr 2025 10:22:15 +0200 Subject: [PATCH 167/302] Correctly handle interior mutable data in `Box` Previously, the pointee type would be behind a `*const` pointer, so `ty_is_freeze` would always be `true`, even if there was an `UnsafeCell` in `Box`. --- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- .../pass/tree_borrows/cell-inside-box.rs | 19 +++++++++++++++++++ .../pass/tree_borrows/cell-inside-box.stderr | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs create mode 100644 src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index ce7d7ab25d76..17e452ec5b45 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -173,7 +173,7 @@ impl<'tcx> NewPermission { pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs new file mode 100644 index 000000000000..a2eb4ede44b2 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs @@ -0,0 +1,19 @@ +//@compile-flags: -Zmiri-tree-borrows +#![feature(box_as_ptr)] +#[path = "../../utils/mod.rs"] +#[macro_use] +mod utils; + +use std::cell::UnsafeCell; + +pub fn main() { + let cell = UnsafeCell::new(42); + let mut root = Box::new(cell); + + let a = Box::as_mut_ptr(&mut root); + unsafe { + name!(a); + let alloc_id = alloc_id!(a); + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr new file mode 100644 index 000000000000..89421380a3ff --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr @@ -0,0 +1,6 @@ +────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 4 +| Act | └─┬── +| ReIM| └──── +────────────────────────────────────────────────── From b7c933a495a42d684f7acb493caeee3f3c4e87bf Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 2 May 2025 12:13:40 -0500 Subject: [PATCH 168/302] doc(std): fix typo lchown -> lchmod --- library/std/src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 462c06dcea26..68e26d796537 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2994,7 +2994,7 @@ pub fn read_dir>(path: P) -> io::Result { /// When possible, permissions should be set at creation time instead. /// /// # Rationale -/// POSIX does not specify an `lchown` function, +/// POSIX does not specify an `lchmod` function, /// and symlinks can be followed regardless of what permission bits are set. /// /// # Errors From 45d4bb2541c240087c86fa1eb742c04feabe9392 Mon Sep 17 00:00:00 2001 From: Xinglu Chen Date: Fri, 2 May 2025 19:46:09 +0200 Subject: [PATCH 169/302] Construct test so that it would fail for old code --- .../pass/tree_borrows/cell-inside-box.rs | 24 +++++++++++++++---- .../pass/tree_borrows/cell-inside-box.stderr | 3 ++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs index a2eb4ede44b2..adf2f4e845b5 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs @@ -8,12 +8,28 @@ use std::cell::UnsafeCell; pub fn main() { let cell = UnsafeCell::new(42); - let mut root = Box::new(cell); + let box1 = Box::new(cell); - let a = Box::as_mut_ptr(&mut root); unsafe { - name!(a); - let alloc_id = alloc_id!(a); + let ptr1: *mut UnsafeCell = Box::into_raw(box1); + name!(ptr1); + + let mut box2 = Box::from_raw(ptr1); + // `ptr2` will be a descendant of `ptr1`. + let ptr2: *mut UnsafeCell = Box::as_mut_ptr(&mut box2); + name!(ptr2); + + // We perform a write through `x`. + // Because `ptr1` is ReservedIM, a child write will make it transition to Active. + // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it. + let x = (*ptr1).get(); + *x = 1; + + // We can still read from `ptr2`. + let val = *(*ptr2).get(); + assert_eq!(val, 1); + + let alloc_id = alloc_id!(ptr1); print_state!(alloc_id); } } diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr index 89421380a3ff..5dbfff718b1e 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr @@ -2,5 +2,6 @@ Warning: this tree is indicative only. Some tags may have been hidden. 0.. 4 | Act | └─┬── -| ReIM| └──── +| Act | └─┬── +| ReIM| └──── ────────────────────────────────────────────────── From d8a52dbbf82e07b82c574bda26d7963992985491 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sat, 3 May 2025 03:00:49 +0900 Subject: [PATCH 170/302] fix: Implement mut to const ptr cast for method resolution --- .../crates/hir-ty/src/method_resolution.rs | 72 +++++++++++++++---- .../hir-ty/src/tests/method_resolution.rs | 23 ++++++ 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 8f8e26eca2ae..8e549ca0cbd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -515,9 +515,15 @@ impl From> for VisibleFromModule { } } +#[derive(Debug, Clone)] +pub enum AutorefOrPtrAdjustment { + Autoref(Mutability), + ToConstPtr, +} + #[derive(Debug, Clone, Default)] pub struct ReceiverAdjustments { - autoref: Option, + autoref: Option, autoderefs: usize, unsize_array: bool, } @@ -535,10 +541,15 @@ impl ReceiverAdjustments { } Some((kind, new_ty)) => { ty = new_ty.clone(); + let mutbl = match self.autoref { + Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m), + Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not), + // FIXME should we know the mutability here, when autoref is `None`? + None => None, + }; adjust.push(Adjustment { kind: Adjust::Deref(match kind { - // FIXME should we know the mutability here, when autoref is `None`? - AutoderefKind::Overloaded => Some(OverloadedDeref(self.autoref)), + AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)), AutoderefKind::Builtin => None, }), target: new_ty, @@ -546,11 +557,27 @@ impl ReceiverAdjustments { } } } - if let Some(m) = self.autoref { + if let Some(autoref) = &self.autoref { let lt = table.new_lifetime_var(); - let a = Adjustment::borrow(m, ty, lt); - ty = a.target.clone(); - adjust.push(a); + match autoref { + AutorefOrPtrAdjustment::Autoref(m) => { + let a = Adjustment::borrow(*m, ty, lt); + ty = a.target.clone(); + adjust.push(a); + } + AutorefOrPtrAdjustment::ToConstPtr => { + if let TyKind::Raw(Mutability::Mut, pointee) = ty.kind(Interner) { + let a = Adjustment { + kind: Adjust::Pointer(PointerCast::MutToConstPointer), + target: TyKind::Raw(Mutability::Not, pointee.clone()).intern(Interner), + }; + ty = a.target.clone(); + adjust.push(a); + } else { + never!("`ToConstPtr` target is not a raw mutable pointer"); + } + } + }; } if self.unsize_array { ty = 'it: { @@ -575,8 +602,8 @@ impl ReceiverAdjustments { (ty, adjust) } - fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments { - Self { autoref: Some(m), ..*self } + fn with_autoref(&self, a: AutorefOrPtrAdjustment) -> ReceiverAdjustments { + Self { autoref: Some(a), ..*self } } } @@ -1051,7 +1078,7 @@ fn iterate_method_candidates_with_autoref( let mut maybe_reborrowed = first_adjustment.clone(); if let Some((_, _, m)) = receiver_ty.value.as_reference() { // Prefer reborrow of references to move - maybe_reborrowed.autoref = Some(m); + maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m)); maybe_reborrowed.autoderefs += 1; } @@ -1063,15 +1090,34 @@ fn iterate_method_candidates_with_autoref( binders: receiver_ty.binders.clone(), }; - iterate_method_candidates_by_receiver(refed, first_adjustment.with_autoref(Mutability::Not))?; + iterate_method_candidates_by_receiver( + refed, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)), + )?; let ref_muted = Canonical { value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone()) .intern(Interner), - binders: receiver_ty.binders, + binders: receiver_ty.binders.clone(), }; - iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut)) + iterate_method_candidates_by_receiver( + ref_muted, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)), + )?; + + if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() { + let const_ptr_ty = Canonical { + value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner), + binders: receiver_ty.binders, + }; + iterate_method_candidates_by_receiver( + const_ptr_ty, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::ToConstPtr), + )?; + } + + ControlFlow::Continue(()) } pub trait MethodCandidateCallback { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 1f8b06fcc561..94826acca305 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -2170,3 +2170,26 @@ fn main() { "#, ); } + +#[test] +fn mut_to_const_pointer() { + check( + r#" +pub trait X { + fn perform(self) -> u64; +} + +impl X for *const u8 { + fn perform(self) -> u64 { + 42 + } +} + +fn test(x: *mut u8) { + let _v = x.perform(); + // ^ adjustments: Pointer(MutToConstPointer) + // ^^^^^^^^^^^ type: u64 +} +"#, + ); +} From 77876b5233a15e67a14ee1d22634357a3bca411f Mon Sep 17 00:00:00 2001 From: Erik Kaneda Date: Fri, 2 May 2025 11:45:09 -0700 Subject: [PATCH 171/302] zkvm: remove schmerik from maintainers list --- src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md index 09b42da26e74..1d02a7cfbc0b 100644 --- a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md +++ b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md @@ -8,7 +8,6 @@ RISC Zero's Zero Knowledge Virtual Machine (zkVM) implementing the RV32IM instru [@flaub](https://github.com/flaub) [@jbruestle](https://github.com/jbruestle) -[@SchmErik](https://github.com/SchmErik) ## Background From ffa7d1ee5dba9d0a9979d784a5c38e3a05a5ff9e Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 2 May 2025 16:24:28 +0000 Subject: [PATCH 172/302] borrowck nested items in dead code --- compiler/rustc_borrowck/src/lib.rs | 8 +++ compiler/rustc_borrowck/src/root_cx.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 10 ++-- compiler/rustc_ty_utils/src/lib.rs | 4 +- compiler/rustc_ty_utils/src/nested_bodies.rs | 34 ++++++++++++ .../rustc_ty_utils/src/stalled_generators.rs | 54 ------------------- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 2 +- tests/ui/nll/nested-bodies-in-dead-code.rs | 28 ++++++++++ .../ui/nll/nested-bodies-in-dead-code.stderr | 50 +++++++++++++++++ 11 files changed, 135 insertions(+), 64 deletions(-) create mode 100644 compiler/rustc_ty_utils/src/nested_bodies.rs delete mode 100644 compiler/rustc_ty_utils/src/stalled_generators.rs create mode 100644 tests/ui/nll/nested-bodies-in-dead-code.rs create mode 100644 tests/ui/nll/nested-bodies-in-dead-code.stderr diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 44af1b765399..f9d8d858f16c 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -127,6 +127,14 @@ fn mir_borrowck( Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def); + // We need to manually borrowck all nested bodies from the HIR as + // we do not generate MIR for dead code. Not doing so causes us to + // never check closures in dead code. + let nested_bodies = tcx.nested_bodies_within(def); + for def_id in nested_bodies { + root_cx.get_or_insert_nested(def_id); + } + let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } = do_mir_borrowck(&mut root_cx, def, None).0; debug_assert!(closure_requirements.is_none()); diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index 13daa5c72214..66b526fa02a5 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -62,7 +62,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.tainted_by_errors = Some(guar); } - fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> { + pub(super) fn get_or_insert_nested( + &mut self, + def_id: LocalDefId, + ) -> &PropagatedBorrowCheckResults<'tcx> { debug_assert_eq!( self.tcx.typeck_root_def_id(def_id.to_def_id()), self.root_def_id.to_def_id() diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 88f4c4ae4d36..2702aea96b54 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -387,7 +387,7 @@ rustc_queries! { } } - query stalled_generators_within( + query nested_bodies_within( key: LocalDefId ) -> &'tcx ty::List { desc { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3ea285d3d8eb..071cbe83e5db 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -684,15 +684,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.opaque_types_defined_by(defining_anchor) } - fn opaque_types_and_generators_defined_by( + fn opaque_types_and_coroutines_defined_by( self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds { if self.next_trait_solver_globally() { + let coroutines_defined_by = self + .nested_bodies_within(defining_anchor) + .iter() + .filter(|def_id| self.is_coroutine(def_id.to_def_id())); self.mk_local_def_ids_from_iter( - self.opaque_types_defined_by(defining_anchor) - .iter() - .chain(self.stalled_generators_within(defining_anchor)), + self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), ) } else { self.opaque_types_defined_by(defining_anchor) diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index ea0f6b8dfba7..f79b6d44bfdf 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -29,10 +29,10 @@ mod implied_bounds; mod instance; mod layout; mod needs_drop; +mod nested_bodies; mod opaque_types; mod representability; pub mod sig_types; -mod stalled_generators; mod structural_match; mod ty; @@ -51,5 +51,5 @@ pub fn provide(providers: &mut Providers) { ty::provide(providers); instance::provide(providers); structural_match::provide(providers); - stalled_generators::provide(providers); + nested_bodies::provide(providers); } diff --git a/compiler/rustc_ty_utils/src/nested_bodies.rs b/compiler/rustc_ty_utils/src/nested_bodies.rs new file mode 100644 index 000000000000..7c74d8eb6351 --- /dev/null +++ b/compiler/rustc_ty_utils/src/nested_bodies.rs @@ -0,0 +1,34 @@ +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Visitor; +use rustc_middle::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; + +fn nested_bodies_within<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx ty::List { + let body = tcx.hir_body_owned_by(item); + let mut collector = + NestedBodiesVisitor { tcx, root_def_id: item.to_def_id(), nested_bodies: vec![] }; + collector.visit_body(body); + tcx.mk_local_def_ids(&collector.nested_bodies) +} + +struct NestedBodiesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + root_def_id: DefId, + nested_bodies: Vec, +} + +impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> { + fn visit_nested_body(&mut self, id: hir::BodyId) { + let body_def_id = self.tcx.hir_body_owner_def_id(id); + if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id { + self.nested_bodies.push(body_def_id); + let body = self.tcx.hir_body(id); + self.visit_body(body); + } + } +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { nested_bodies_within, ..*providers }; +} diff --git a/compiler/rustc_ty_utils/src/stalled_generators.rs b/compiler/rustc_ty_utils/src/stalled_generators.rs deleted file mode 100644 index 8b45e8b0f6f9..000000000000 --- a/compiler/rustc_ty_utils/src/stalled_generators.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit; -use rustc_hir::intravisit::Visitor; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; - -fn stalled_generators_within<'tcx>( - tcx: TyCtxt<'tcx>, - item: LocalDefId, -) -> &'tcx ty::List { - if !tcx.next_trait_solver_globally() { - return ty::List::empty(); - } - - let body = tcx.hir_body_owned_by(item); - let mut collector = - StalledGeneratorVisitor { tcx, root_def_id: item.to_def_id(), stalled_coroutines: vec![] }; - collector.visit_body(body); - tcx.mk_local_def_ids(&collector.stalled_coroutines) -} - -struct StalledGeneratorVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - root_def_id: DefId, - stalled_coroutines: Vec, -} - -impl<'tcx> Visitor<'tcx> for StalledGeneratorVisitor<'tcx> { - fn visit_nested_body(&mut self, id: hir::BodyId) { - if self.tcx.typeck_root_def_id(self.tcx.hir_body_owner_def_id(id).to_def_id()) - == self.root_def_id - { - let body = self.tcx.hir_body(id); - self.visit_body(body); - } - } - - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure(&hir::Closure { - def_id, - kind: hir::ClosureKind::Coroutine(_), - .. - }) = ex.kind - { - self.stalled_coroutines.push(def_id); - } - intravisit::walk_expr(self, ex); - } -} - -pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { stalled_generators_within, ..*providers }; -} diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 8fa56c359996..7d2654de4409 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -100,7 +100,7 @@ impl TypingMode { pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { TypingMode::Analysis { defining_opaque_types_and_generators: cx - .opaque_types_and_generators_defined_by(body_def_id), + .opaque_types_and_coroutines_defined_by(body_def_id), } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6410da1f7409..0fd2d9f3ad38 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -341,7 +341,7 @@ pub trait Interner: fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; - fn opaque_types_and_generators_defined_by( + fn opaque_types_and_coroutines_defined_by( self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds; diff --git a/tests/ui/nll/nested-bodies-in-dead-code.rs b/tests/ui/nll/nested-bodies-in-dead-code.rs new file mode 100644 index 000000000000..6ac68f5adbce --- /dev/null +++ b/tests/ui/nll/nested-bodies-in-dead-code.rs @@ -0,0 +1,28 @@ +//@ edition: 2024 + +// Regression test for #140583. We want to borrowck nested +// bodies even if they are in dead code. While not necessary for +// soundness, it is desirable to error in such cases. + +fn main() { + return; + |x: &str| -> &'static str { x }; + //~^ ERROR lifetime may not live long enough + || { + || { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; + }; + const { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; + async { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; +} diff --git a/tests/ui/nll/nested-bodies-in-dead-code.stderr b/tests/ui/nll/nested-bodies-in-dead-code.stderr new file mode 100644 index 000000000000..da6ccff5777c --- /dev/null +++ b/tests/ui/nll/nested-bodies-in-dead-code.stderr @@ -0,0 +1,50 @@ +error: lifetime may not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:9:33 + | +LL | |x: &str| -> &'static str { x }; + | - ^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:14:35 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:20:31 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:25:31 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`. From dcee18b3b8cd23e6cd3ed20805d97515526852f7 Mon Sep 17 00:00:00 2001 From: moxian Date: Thu, 1 May 2025 14:34:04 -0700 Subject: [PATCH 173/302] Add a regression test for #140545 --- .../double-wrap-with-defining-use.rs | 12 ++++++++++++ .../double-wrap-with-defining-use.stderr | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs create mode 100644 tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs new file mode 100644 index 000000000000..339277fec37e --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs @@ -0,0 +1,12 @@ +// Regression test for ICE from issue #140545 +// The error message is confusing and wrong, but that's a different problem (#139350) +//@ edition:2018 + +trait Foo {} +fn a(x: impl Foo) -> impl Foo { + if true { x } else { a(a(x)) } + //~^ ERROR: expected generic type parameter, found `impl Foo` [E0792] + //~| ERROR: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias +} + +fn main(){} diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr new file mode 100644 index 000000000000..1b02811e31b7 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr @@ -0,0 +1,17 @@ +error[E0792]: expected generic type parameter, found `impl Foo` + --> $DIR/double-wrap-with-defining-use.rs:7:26 + | +LL | fn a(x: impl Foo) -> impl Foo { + | -------- this generic parameter must be used with a generic type parameter +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/double-wrap-with-defining-use.rs:7:26 + | +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0792`. From 4671081bdbc73d35a465a150937b6d0ecd26087f Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Fri, 2 May 2025 22:08:35 +0200 Subject: [PATCH 174/302] Refactor rustc_on_unimplemented's filter parser --- Cargo.lock | 1 - compiler/rustc_trait_selection/Cargo.toml | 1 - compiler/rustc_trait_selection/messages.ftl | 26 +- .../traits/on_unimplemented.rs | 52 ++- .../traits/on_unimplemented_condition.rs | 321 ++++++++++++++---- compiler/rustc_trait_selection/src/errors.rs | 56 ++- tests/ui/on-unimplemented/bad-annotation.rs | 64 +++- .../ui/on-unimplemented/bad-annotation.stderr | 110 +++--- 8 files changed, 457 insertions(+), 174 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97a90a44a398..a5b41b6edd5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4520,7 +4520,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1c61e23362a8..e6de2a3978d1 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 74e38f525c8e..cf6dd40718b3 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -148,9 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement -trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` - .label = empty on-clause here - trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type @@ -187,9 +184,6 @@ trait_selection_inherent_projection_normalization_overflow = overflow evaluating trait_selection_invalid_format_specifier = invalid format specifier .help = no format specifier are supported in this position -trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` - .label = invalid on-clause here - trait_selection_label_bad = {$bad_kind -> *[other] cannot infer type [more_info] cannot infer {$prefix_kind -> @@ -237,10 +231,6 @@ trait_selection_negative_positive_conflict = found both positive and negative im .positive_implementation_here = positive implementation here .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` -trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value - .label = expected value here - .note = eg `#[rustc_on_unimplemented(message="foo")]` - trait_selection_nothing = {""} trait_selection_oc_cant_coerce_force_inline = @@ -339,6 +329,22 @@ trait_selection_ril_introduced_by = requirement introduced by this return type trait_selection_ril_introduced_here = `'static` requirement introduced here trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type +trait_selection_rustc_on_unimplemented_empty_on_clause = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty `on`-clause here +trait_selection_rustc_on_unimplemented_expected_identifier = expected an identifier inside this `on`-clause + .label = expected an identifier here, not `{$path}` +trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected a single predicate in `not(..)` + .label = unexpected quantity of predicates here +trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause + .label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}` +trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid + .label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}` +trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value + .label = expected value here + .note = e.g. `#[rustc_on_unimplemented(message="foo")]` +trait_selection_rustc_on_unimplemented_unsupported_literal_in_on = literals inside `on`-clauses are not supported + .label = unexpected literal here + trait_selection_source_kind_closure_return = try giving this closure an explicit return type diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 4c4491269b75..d5ee6e2123a1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; use rustc_macros::LintDiagnostic; @@ -13,17 +14,16 @@ use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKin use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; -use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; -use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; +use crate::error_reporting::traits::on_unimplemented_condition::{ + ConditionOptions, OnUnimplementedCondition, +}; use crate::error_reporting::traits::on_unimplemented_format::{ Ctx, FormatArgs, FormatString, FormatWarning, }; -use crate::errors::{ - EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, -}; +use crate::errors::{InvalidOnClause, NoValueInOnUnimplemented}; use crate::infer::InferCtxtExt; impl<'tcx> TypeErrCtxt<'_, 'tcx> { @@ -306,21 +306,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString { /// Symbol of the format string, i.e. `"content"` - pub symbol: Symbol, + symbol: Symbol, ///The span of the format string, i.e. `"content"` - pub span: Span, - pub is_diagnostic_namespace_variant: bool, + span: Span, + is_diagnostic_namespace_variant: bool, } #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, - pub subcommands: Vec, - pub message: Option<(Span, OnUnimplementedFormatString)>, - pub label: Option<(Span, OnUnimplementedFormatString)>, - pub notes: Vec, - pub parent_label: Option, - pub append_const_msg: Option, + condition: Option, + subcommands: Vec, + message: Option<(Span, OnUnimplementedFormatString)>, + label: Option<(Span, OnUnimplementedFormatString)>, + notes: Vec, + parent_label: Option, + append_const_msg: Option, } /// For the `#[rustc_on_unimplemented]` attribute @@ -427,18 +427,12 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? - .meta_item_or_bool() - .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; - attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { - if let Some(value) = cfg.value - && let Err(guar) = parse_value(value, cfg.span) - { - errored = Some(guar); - } - true - }); - Some(Condition { inner: cond.clone() }) + .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?; + + match OnUnimplementedCondition::parse(cond) { + Ok(condition) => Some(condition), + Err(e) => return Err(tcx.dcx().emit_err(e)), + } }; let mut message = None; @@ -724,7 +718,7 @@ impl<'tcx> OnUnimplementedDirective { result } - pub fn evaluate( + pub(crate) fn evaluate( &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -744,7 +738,7 @@ impl<'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { debug!(?command); if let Some(ref condition) = command.condition - && !condition.matches_predicate(tcx, condition_options) + && !condition.matches_predicate(condition_options) { debug!("evaluate: skipping {:?} due to condition", command); continue; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 116cfb01cb63..13753761f092 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -1,52 +1,251 @@ -use rustc_ast::MetaItemInner; -use rustc_attr_parsing as attr; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_ast::{MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; -use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym}; -/// A predicate in an attribute using on, all, any, -/// similar to a cfg predicate. +use crate::errors::InvalidOnClause; + +/// Represents the `on` filter in `#[rustc_on_unimplemented]`. #[derive(Debug)] -pub struct Condition { - pub inner: MetaItemInner, +pub(crate) struct OnUnimplementedCondition { + span: Span, + pred: Predicate, } -impl Condition { - pub fn span(&self) -> Span { - self.inner.span() +impl OnUnimplementedCondition { + pub(crate) fn span(&self) -> Span { + self.span } - pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool { - attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { - let value = cfg.value.map(|v| { - // `with_no_visible_paths` is also used when generating the options, - // so we need to match it here. - ty::print::with_no_visible_paths!({ - Parser::new(v.as_str(), None, None, false, ParseMode::Format) - .map(|p| match p { - Piece::Lit(s) => s.to_owned(), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(arg) => { - let s = Symbol::intern(arg); - match options.generic_args.iter().find(|(k, _)| *k == s) { - Some((_, val)) => val.to_string(), - None => format!("{{{arg}}}"), - } - } - Position::ArgumentImplicitlyIs(_) => String::from("{}"), - Position::ArgumentIs(idx) => format!("{{{idx}}}"), - }, - }) - .collect() - }) - }); - - options.contains(cfg.name, &value) + pub(crate) fn matches_predicate(&self, options: &ConditionOptions) -> bool { + self.pred.eval(&mut |p| match p { + FlagOrNv::Flag(b) => options.has_flag(*b), + FlagOrNv::NameValue(NameValue { name, value }) => { + let value = value.format(&options.generic_args); + options.contains(*name, value) + } }) } + + pub(crate) fn parse(input: &MetaItemInner) -> Result { + let span = input.span(); + let pred = Predicate::parse(input)?; + Ok(OnUnimplementedCondition { span, pred }) + } } -/// Used with `Condition::matches_predicate` to test whether the condition applies +/// Predicate(s) in `#[rustc_on_unimplemented]`'s `on` filter. See [`OnUnimplementedCondition`]. +/// +/// It is similar to the predicate in the `cfg` attribute, +/// and may contain nested predicates. +#[derive(Debug)] +enum Predicate { + /// A condition like `on(crate_local)`. + Flag(Flag), + /// A match, like `on(Rhs = "Whatever")`. + Match(NameValue), + /// Negation, like `on(not($pred))`. + Not(Box), + /// True if all predicates are true, like `on(all($a, $b, $c))`. + All(Vec), + /// True if any predicate is true, like `on(any($a, $b, $c))`. + Any(Vec), +} + +impl Predicate { + fn parse(input: &MetaItemInner) -> Result { + let meta_item = match input { + MetaItemInner::MetaItem(meta_item) => meta_item, + MetaItemInner::Lit(lit) => { + return Err(InvalidOnClause::UnsupportedLiteral { span: lit.span }); + } + }; + + let Some(predicate) = meta_item.ident() else { + return Err(InvalidOnClause::ExpectedIdentifier { + span: meta_item.path.span, + path: meta_item.path.clone(), + }); + }; + + match meta_item.kind { + MetaItemKind::List(ref mis) => match predicate.name { + sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)), + sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)), + sym::not => match &**mis { + [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))), + [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot { + span: first.span().to(last.span()), + }), + [] => Err(InvalidOnClause::ExpectedOnePredInNot { span: meta_item.span }), + }, + invalid_pred => { + Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred }) + } + }, + MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => { + let name = Name::parse(predicate); + let value = FilterFormatString::parse(symbol); + let kv = NameValue { name, value }; + Ok(Predicate::Match(kv)) + } + MetaItemKind::Word => { + let flag = Flag::parse(predicate)?; + Ok(Predicate::Flag(flag)) + } + } + } + + fn parse_sequence(sequence: &[MetaItemInner]) -> Result, InvalidOnClause> { + sequence.iter().map(Predicate::parse).collect() + } + + fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool { + match self { + Predicate::Flag(flag) => eval(FlagOrNv::Flag(flag)), + Predicate::Match(nv) => eval(FlagOrNv::NameValue(nv)), + Predicate::Not(not) => !not.eval(eval), + Predicate::All(preds) => preds.into_iter().all(|pred| pred.eval(eval)), + Predicate::Any(preds) => preds.into_iter().any(|pred| pred.eval(eval)), + } + } +} + +/// Represents a `MetaWord` in an `on`-filter. +#[derive(Debug, Clone, Copy)] +enum Flag { + /// Whether the code causing the trait bound to not be fulfilled + /// is part of the user's crate. + CrateLocal, + /// Whether the obligation is user-specified rather than derived. + Direct, + /// Whether we are in some kind of desugaring like + /// `?` or `try { .. }`. + FromDesugaring, +} + +impl Flag { + fn parse(Ident { name, span }: Ident) -> Result { + match name { + sym::crate_local => Ok(Flag::CrateLocal), + sym::direct => Ok(Flag::Direct), + sym::from_desugaring => Ok(Flag::FromDesugaring), + invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }), + } + } +} + +/// A `MetaNameValueStr` in an `on`-filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +#[derive(Debug, Clone)] +struct NameValue { + name: Name, + /// Something like `"&str"` or `"alloc::string::String"`, + /// in which case it just contains a single string piece. + /// But if it is something like `"&[{A}]"` then it must be formatted later. + value: FilterFormatString, +} + +/// The valid names of the `on` filter. +#[derive(Debug, Clone, Copy)] +enum Name { + Cause, + FromDesugaring, + SelfUpper, + GenericArg(Symbol), +} + +impl Name { + fn parse(Ident { name, .. }: Ident) -> Self { + match name { + sym::_Self | kw::SelfUpper => Name::SelfUpper, + sym::from_desugaring => Name::FromDesugaring, + sym::cause => Name::Cause, + // FIXME(mejrs) Perhaps we should start checking that + // this actually is a valid generic parameter? + generic => Name::GenericArg(generic), + } + } +} + +#[derive(Debug, Clone)] +enum FlagOrNv<'p> { + Flag(&'p Flag), + NameValue(&'p NameValue), +} + +/// Represents a value inside an `on` filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +/// If it is a simple literal like this then `pieces` will be `[LitOrArg::Lit("value")]`. +/// The `Arg` variant is used when it contains formatting like +/// `#[rustc_on_unimplemented(on(Self = "&[{A}]", message = "hello"))]`. +#[derive(Debug, Clone)] +struct FilterFormatString { + pieces: Vec, +} + +#[derive(Debug, Clone)] +enum LitOrArg { + Lit(String), + Arg(String), +} + +impl FilterFormatString { + fn parse(input: Symbol) -> Self { + let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format) + .map(|p| match p { + Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), + // We just ignore formatspecs here + Piece::NextArgument(a) => match a.position { + // In `TypeErrCtxt::on_unimplemented_note` we substitute `"{integral}"` even + // if the integer type has been resolved, to allow targeting all integers. + // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet, + // from the `Display` impl of `InferTy` to be precise. + // + // Don't try to format these later! + Position::ArgumentNamed(arg @ "integer" | arg @ "integral" | arg @ "float") => { + LitOrArg::Lit(format!("{{{arg}}}")) + } + + // FIXME(mejrs) We should check if these correspond to a generic of the trait. + Position::ArgumentNamed(arg) => LitOrArg::Arg(arg.to_owned()), + + // FIXME(mejrs) These should really be warnings/errors + Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(String::from("{}")), + Position::ArgumentIs(idx) => LitOrArg::Lit(format!("{{{idx}}}")), + }, + }) + .collect(); + Self { pieces } + } + + fn format(&self, generic_args: &[(Symbol, String)]) -> String { + let mut ret = String::new(); + + for piece in &self.pieces { + match piece { + LitOrArg::Lit(s) => ret.push_str(s), + LitOrArg::Arg(arg) => { + let s = Symbol::intern(arg); + match generic_args.iter().find(|(k, _)| *k == s) { + Some((_, val)) => ret.push_str(val), + None => { + // FIXME(mejrs) If we start checking as mentioned in + // FilterFormatString::parse then this shouldn't happen + let _ = std::fmt::write(&mut ret, format_args!("{{{s}}}")); + } + } + } + } + } + + ret + } +} + +/// Used with `OnUnimplementedCondition::matches_predicate` to evaluate the +/// [`OnUnimplementedCondition`]. /// /// For example, given a /// ```rust,ignore (just an example) @@ -85,36 +284,34 @@ impl Condition { /// } /// ``` #[derive(Debug)] -pub struct ConditionOptions { +pub(crate) struct ConditionOptions { /// All the self types that may apply. - /// for example - pub self_types: Vec, + pub(crate) self_types: Vec, // The kind of compiler desugaring. - pub from_desugaring: Option, - /// Match on a variant of [rustc_infer::traits::ObligationCauseCode] - pub cause: Option, - pub crate_local: bool, + pub(crate) from_desugaring: Option, + /// Match on a variant of [rustc_infer::traits::ObligationCauseCode]. + pub(crate) cause: Option, + pub(crate) crate_local: bool, /// Is the obligation "directly" user-specified, rather than derived? - pub direct: bool, - // A list of the generic arguments and their reified types - pub generic_args: Vec<(Symbol, String)>, + pub(crate) direct: bool, + // A list of the generic arguments and their reified types. + pub(crate) generic_args: Vec<(Symbol, String)>, } impl ConditionOptions { - pub fn contains(&self, key: Symbol, value: &Option) -> bool { - match (key, value) { - (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value), - // from_desugaring as a flag - (sym::from_desugaring, None) => self.from_desugaring.is_some(), - // from_desugaring as key == value - (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v), - (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), - (sym::crate_local, None) => self.crate_local, - (sym::direct, None) => self.direct, - (other, Some(value)) => { - self.generic_args.iter().any(|(k, v)| *k == other && v == value) - } - _ => false, + fn has_flag(&self, name: Flag) -> bool { + match name { + Flag::CrateLocal => self.crate_local, + Flag::Direct => self.direct, + Flag::FromDesugaring => self.from_desugaring.is_some(), + } + } + fn contains(&self, name: Name, value: String) -> bool { + match name { + Name::SelfUpper => self.self_types.contains(&value), + Name::FromDesugaring => self.from_desugaring.is_some_and(|ds| ds.matches(&value)), + Name::Cause => self.cause == Some(value), + Name::GenericArg(arg) => self.generic_args.contains(&(arg, value)), } } } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 756d9a57b935..21d053124810 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use rustc_ast::Path; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -31,23 +32,50 @@ pub struct UnableToConstructConstantValue<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct EmptyOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, +pub enum InvalidOnClause { + #[diag(trait_selection_rustc_on_unimplemented_empty_on_clause, code = E0232)] + Empty { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not, code = E0232)] + ExpectedOnePredInNot { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_unsupported_literal_in_on, code = E0232)] + UnsupportedLiteral { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_identifier, code = E0232)] + ExpectedIdentifier { + #[primary_span] + #[label] + span: Span, + path: Path, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_predicate, code = E0232)] + InvalidPredicate { + #[primary_span] + #[label] + span: Span, + invalid_pred: Symbol, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_flag, code = E0232)] + InvalidFlag { + #[primary_span] + #[label] + span: Span, + invalid_flag: Symbol, + }, } #[derive(Diagnostic)] -#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct InvalidOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)] +#[diag(trait_selection_rustc_on_unimplemented_missing_value, code = E0232)] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 32b825ee3cc2..25de59781102 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -25,49 +25,85 @@ trait ParameterNotPresent {} trait NoPositionalArgs {} #[rustc_on_unimplemented(lorem = "")] -//~^ ERROR this attribute must have a valid +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here trait EmptyMessage {} #[rustc_on_unimplemented(lorem(ipsum(dolor)))] -//~^ ERROR this attribute must have a valid +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here trait Invalid {} #[rustc_on_unimplemented(message = "x", message = "y")] -//~^ ERROR this attribute must have a valid +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here trait DuplicateMessage {} #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] -//~^ ERROR this attribute must have a valid +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here trait OnInWrongPosition {} #[rustc_on_unimplemented(on(), message = "y")] //~^ ERROR empty `on`-clause -trait NoEmptyOn {} +//~^^ NOTE empty `on`-clause here +trait EmptyOn {} #[rustc_on_unimplemented(on = "x", message = "y")] -//~^ ERROR this attribute must have a valid +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here trait ExpectedPredicateInOn {} #[rustc_on_unimplemented(on(x = "y"), message = "y")] trait OnWithoutDirectives {} -#[rustc_on_unimplemented(on(desugared, on(desugared, message = "x")), message = "y")] -//~^ ERROR this attribute must have a valid -trait NoNestedOn {} +#[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait NestedOn {} -// caught by `OnUnimplementedDirective::parse`, *not* `eval_condition` #[rustc_on_unimplemented(on("y", message = "y"))] -//~^ ERROR invalid `on`-clause +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here trait UnsupportedLiteral {} +#[rustc_on_unimplemented(on(42, message = "y"))] +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here +trait UnsupportedLiteral2 {} + #[rustc_on_unimplemented(on(not(a, b), message = "y"))] -//~^ ERROR expected 1 cfg-pattern +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here trait ExpectedOnePattern {} +#[rustc_on_unimplemented(on(not(), message = "y"))] +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here +trait ExpectedOnePattern2 {} + #[rustc_on_unimplemented(on(thing::What, message = "y"))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` trait KeyMustBeIdentifier {} #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` trait KeyMustBeIdentifier2 {} + +#[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] +//~^ ERROR this predicate is invalid +//~^^ NOTE expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` +trait InvalidPredicate {} + +#[rustc_on_unimplemented(on(something, message = "y"))] +//~^ ERROR invalid flag in `on`-clause +//~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` +trait InvalidFlag {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 817d3c42cf69..35b919c7b785 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -23,85 +23,109 @@ error[E0231]: positional format arguments are not allowed here LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] | ^ -error[E0232]: this attribute must have a valid value +error[E0232]: this attribute must have a value --> $DIR/bad-annotation.rs:27:26 | LL | #[rustc_on_unimplemented(lorem = "")] | ^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:31:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:33:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:35:41 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:39:41 | LL | #[rustc_on_unimplemented(message = "x", message = "y")] | ^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:39:41 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:45:41 | LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:43:26 + --> $DIR/bad-annotation.rs:51:26 | LL | #[rustc_on_unimplemented(on(), message = "y")] - | ^^^^ empty on-clause here + | ^^^^ empty `on`-clause here -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:47:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:56:26 | LL | #[rustc_on_unimplemented(on = "x", message = "y")] | ^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:54:40 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:65:46 | -LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message = "x")), message = "y")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: invalid `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:59:26 - | -LL | #[rustc_on_unimplemented(on("y", message = "y"))] - | ^^^^^^^^^^^^^^^^^^^^^^ invalid on-clause here - -error[E0536]: expected 1 cfg-pattern - --> $DIR/bad-annotation.rs:63:29 - | -LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] - | ^^^^^^^^^ - -error: `cfg` predicate key must be an identifier - --> $DIR/bad-annotation.rs:67:29 - | -LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] - | ^^^^^^^^^^^ - -error: `cfg` predicate key must be an identifier +error[E0232]: literals inside `on`-clauses are not supported --> $DIR/bad-annotation.rs:71:29 | +LL | #[rustc_on_unimplemented(on("y", message = "y"))] + | ^^^ unexpected literal here + +error[E0232]: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:76:29 + | +LL | #[rustc_on_unimplemented(on(42, message = "y"))] + | ^^ unexpected literal here + +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:81:33 + | +LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] + | ^^^^ unexpected quantity of predicates here + +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:86:29 + | +LL | #[rustc_on_unimplemented(on(not(), message = "y"))] + | ^^^^^ unexpected quantity of predicates here + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:91:29 + | +LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:96:29 + | LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` -error: aborting due to 14 previous errors +error[E0232]: this predicate is invalid + --> $DIR/bad-annotation.rs:101:29 + | +LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] + | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` -Some errors have detailed explanations: E0230, E0231, E0232, E0536. +error[E0232]: invalid flag in `on`-clause + --> $DIR/bad-annotation.rs:106:29 + | +LL | #[rustc_on_unimplemented(on(something, message = "y"))] + | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0230, E0231, E0232. For more information about an error, try `rustc --explain E0230`. From 415a73e3eb4910bc40eaec8022e7bf8813523318 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Fri, 2 May 2025 23:41:52 +0200 Subject: [PATCH 175/302] docs: alias `limit` to `Iterator::take`, cite `[u8]::utf8_chunks` in `Utf8Chunks` --- library/core/src/iter/traits/iterator.rs | 1 + library/core/src/str/lossy.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c68fd2115d68..0d7d7860b030 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1358,6 +1358,7 @@ pub trait Iterator { /// ``` /// /// [`by_ref`]: Iterator::by_ref + #[doc(alias = "limit")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take(self, n: usize) -> Take diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index ed2cefc59a51..8d4210c80827 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -147,12 +147,14 @@ impl fmt::Debug for Debug<'_> { /// An iterator used to decode a slice of mostly UTF-8 bytes to string slices /// ([`&str`]) and byte slices ([`&[u8]`][byteslice]). /// +/// This struct is created by the [`utf8_chunks`] method on bytes slices. /// If you want a simple conversion from UTF-8 byte slices to string slices, /// [`from_utf8`] is easier to use. /// /// See the [`Utf8Chunk`] type for documentation of the items yielded by this iterator. /// /// [byteslice]: slice +/// [`utf8_chunks`]: slice::utf8_chunks /// [`from_utf8`]: super::from_utf8 /// /// # Examples From 882c74dfcf974d4129b268ca1aef4de28cd6cc4e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 16:52:17 +1000 Subject: [PATCH 176/302] Remove fake `BoxMarker`s. They don't appear to do anything -- no test output is affected -- and no other pretty-printing code looks like this. --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 11 +---------- compiler/rustc_hir_pretty/src/lib.rs | 9 --------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 38cadc77b777..abcbb88aab2d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -13,7 +13,7 @@ use rustc_ast::{ use crate::pp::Breaks::Inconsistent; use crate::pprust::state::fixup::FixupContext; -use crate::pprust::state::{AnnNode, BoxMarker, INDENT_UNIT, PrintState, State}; +use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State}; impl<'a> State<'a> { fn print_else(&mut self, els: Option<&ast::Expr>) { @@ -542,15 +542,6 @@ impl<'a> State<'a> { self.print_fn_params_and_ret(fn_decl, true); self.space(); self.print_expr(body, FixupContext::default()); - // FIXME(nnethercote): Bogus. Reduce visibility of `ended` once it's fixed. - let fake_ib = BoxMarker; - self.end(fake_ib); - - // A box will be closed by print_expr, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - // FIXME(nnethercote): Bogus. - let _ib = self.ibox(0); } ast::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 15e997aebcb8..4035de957158 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1572,15 +1572,6 @@ impl<'a> State<'a> { // This is a bare expression. self.ann.nested(self, Nested::Body(body)); - // FIXME(nnethercote): this is bogus - let fake_ib = BoxMarker; - self.end(fake_ib); - - // A box will be closed by `print_expr`, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - // FIXME(nnethercote): this is bogus, and `print_expr` is missing - let _ib = self.ibox(0); } hir::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { From 3896ad0acd53fa62cab711d20af8dec1f3e944a1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 19:59:36 +1000 Subject: [PATCH 177/302] Remove opaque type printing. As far as I can tell, this code is not actually reachable. --- compiler/rustc_hir_pretty/src/lib.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4035de957158..f4076e1114b3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -183,7 +183,7 @@ impl<'a> State<'a> { Node::Ty(a) => self.print_type(a), Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a), Node::TraitRef(a) => self.print_trait_ref(a), - Node::OpaqueTy(o) => self.print_opaque_ty(o), + Node::OpaqueTy(_) => panic!("cannot print Node::OpaqueTy"), Node::Pat(a) => self.print_pat(a), Node::TyPat(a) => self.print_ty_pat(a), Node::PatField(a) => self.print_patfield(a), @@ -764,14 +764,6 @@ impl<'a> State<'a> { self.print_path(t.path, false); } - fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { - // FIXME(nnethercote): `cb` and `ib` are unclosed - let (_cb, _ib) = self.head("opaque"); - self.word("{"); - self.print_bounds("impl", o.bounds); - self.word("}"); - } - fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) { if !generic_params.is_empty() { self.word("for"); From 760cf8d3afd446e9a5f3dc1af006548a0da5686c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 20:07:10 +1000 Subject: [PATCH 178/302] Fix hir pretty-printing of `global_asm!`. One of the boxes isn't closed, and this causes everything after it to be over-indented. --- compiler/rustc_hir_pretty/src/lib.rs | 7 ++++--- tests/ui/unpretty/exhaustive-asm.hir.stdout | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f4076e1114b3..d119402222bb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -654,10 +654,11 @@ impl<'a> State<'a> { self.bclose(item.span, cb); } hir::ItemKind::GlobalAsm { asm, .. } => { - // FIXME(nnethercote): `ib` is unclosed - let (cb, _ib) = self.head("global_asm!"); + let (cb, ib) = self.head("global_asm!"); self.print_inline_asm(asm); - self.end(cb) + self.word(";"); + self.end(cb); + self.end(ib); } hir::ItemKind::TyAlias(ident, ty, generics) => { let (cb, ib) = self.head("type"); diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout index 5a642dff6f2e..810db69bff16 100644 --- a/tests/ui/unpretty/exhaustive-asm.hir.stdout +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -27,5 +27,6 @@ mod expressions { mod items { /// ItemKind::GlobalAsm mod item_global_asm {/// ItemKind::GlobalAsm - global_asm! (".globl my_asm_func") } + global_asm! (".globl my_asm_func"); } +} From aa7bb1c2f5a8d8e8b709421189186e8e5e8b64f9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 20:17:29 +1000 Subject: [PATCH 179/302] Enable `BoxMarker` drop checking. All the box open/close issues have been fixed. --- compiler/rustc_ast_pretty/src/pp.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 142c80b8e39e..8a0dbadf18cd 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -244,9 +244,6 @@ struct BufEntry { // forgotten will trigger a panic in `drop`. (Closing a box more than once // isn't possible because `BoxMarker` doesn't implement `Copy` or `Clone`.) // -// FIXME(nnethercote): the panic in `drop` is currently disabled because a few -// places fail to close their boxes. It can be enabled once they are fixed. -// // Note: it would be better to make open/close mismatching impossible and avoid // the need for this marker type altogether by having functions like // `with_ibox` that open a box, call a closure, and then close the box. That @@ -261,8 +258,7 @@ impl !Copy for BoxMarker {} impl Drop for BoxMarker { fn drop(&mut self) { - // FIXME(nnethercote): enable once the bad cases are fixed - //panic!("BoxMarker not ended with `Printer::end()`"); + panic!("BoxMarker not ended with `Printer::end()`"); } } From e1a177bbba2b1297c33e2838f8b2b72ab5f62ecf Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Apr 2025 10:08:01 +1000 Subject: [PATCH 180/302] Improve hir pretty-printing of attributes. --- compiler/rustc_hir_pretty/src/lib.rs | 1 + tests/pretty/hir-delegation.pp | 3 +- .../attrs/automatically_derived.rs | 2 +- tests/rustdoc-json/attrs/export_name_2021.rs | 2 +- tests/rustdoc-json/attrs/export_name_2024.rs | 2 +- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/rustdoc-json/attrs/no_mangle_2021.rs | 2 +- tests/rustdoc-json/attrs/no_mangle_2024.rs | 2 +- tests/rustdoc-json/attrs/non_exhaustive.rs | 6 +-- tests/rustdoc-json/keyword_private.rs | 4 +- .../ui-fulldeps/stable-mir/check_attribute.rs | 4 +- tests/ui/unpretty/exhaustive.hir.stdout | 38 ++++++++++++++++--- 12 files changed, 49 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d119402222bb..1e260b2dda45 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -110,6 +110,7 @@ impl<'a> State<'a> { } self.print_attr_item(&unparsed, unparsed.span); self.word("]"); + self.hardbreak() } hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index 872a6a45aede..e452cee63659 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -2,7 +2,8 @@ //@ pretty-mode:hir //@ pp-exact:hir-delegation.pp -#![allow(incomplete_features)]#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![feature(fn_delegation)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs index 4e1ab3d145e5..6c90d6386499 100644 --- a/tests/rustdoc-json/attrs/automatically_derived.rs +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -9,5 +9,5 @@ impl Default for Manual { } } -//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]\n"]' //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index 254e9f6ef5bf..4e6526419bdb 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]\n"]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index 8129c109306c..f6a2a92b5bcd 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 // is still `#[export_name = ..]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]\n"]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 64df8e5f509f..20696dce7121 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]\n"]' #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]\n"]' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 588be7256db5..10a372572ae5 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]\n"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 0d500e20e6c5..8f3a14cbecbf 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]\n"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index b95f1a8171fd..3064b86422d1 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index fea546c9fb60..5e9a2c101636 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -5,7 +5,7 @@ //@ !has "$.index[?(@.name=='match')]" //@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]\n"]' //@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! @@ -13,7 +13,7 @@ pub mod foo {} //@ !has "$.index[?(@.name=='break')]" //@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]\n"]' //@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index 81d5399d88aa..e4cc7b104b60 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -35,12 +35,12 @@ fn test_stable_mir() -> ControlFlow<()> { fn test_tool(items: &CrateItems) { let rustfmt_fn = *get_item(&items, "do_not_format").unwrap(); let rustfmt_attrs = rustfmt_fn.tool_attrs(&["rustfmt".to_string(), "skip".to_string()]); - assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]"); + assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]\n"); let clippy_fn = *get_item(&items, "complex_fn").unwrap(); let clippy_attrs = clippy_fn.tool_attrs(&["clippy".to_string(), "cyclomatic_complexity".to_string()]); - assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]"); + assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]\n"); } fn get_item<'a>( diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index d2c379d43662..885135e590d2 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -8,7 +8,28 @@ // Note: the HIR revision includes a `.stderr` file because there are some // errors that only occur once we get past the AST. -#![feature(auto_traits)]#![feature(box_patterns)]#![feature(builtin_syntax)]#![feature(concat_idents)]#![feature(const_trait_impl)]#![feature(decl_macro)]#![feature(deref_patterns)]#![feature(dyn_star)]#![feature(explicit_tail_calls)]#![feature(gen_blocks)]#![feature(more_qualified_paths)]#![feature(never_patterns)]#![feature(never_type)]#![feature(pattern_types)]#![feature(pattern_type_macro)]#![feature(prelude_import)]#![feature(specialization)]#![feature(trace_macros)]#![feature(trait_alias)]#![feature(try_blocks)]#![feature(yeet_expr)]#![allow(incomplete_features)] +#![feature(auto_traits)] +#![feature(box_patterns)] +#![feature(builtin_syntax)] +#![feature(concat_idents)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deref_patterns)] +#![feature(dyn_star)] +#![feature(explicit_tail_calls)] +#![feature(gen_blocks)] +#![feature(more_qualified_paths)] +#![feature(never_patterns)] +#![feature(never_type)] +#![feature(pattern_types)] +#![feature(pattern_type_macro)] +#![feature(prelude_import)] +#![feature(specialization)] +#![feature(trace_macros)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(yeet_expr)] +#![allow(incomplete_features)] #[prelude_import] use std::prelude::rust_2024::*; #[macro_use] @@ -33,20 +54,25 @@ mod prelude { /*! * inner multi-line doc comment */ -#[doc = "inner doc attribute"]#[allow(dead_code, unused_variables)]#[no_std] +#[doc = "inner doc attribute"] +#[allow(dead_code, unused_variables)] +#[no_std] mod attributes {//! inner single-line doc comment /*! * inner multi-line doc comment */ - #![doc = - "inner doc attribute"]#![allow(dead_code, unused_variables)]#![no_std] + #![doc = "inner doc attribute"] + #![allow(dead_code, unused_variables)] + #![no_std] /// outer single-line doc comment /** * outer multi-line doc comment */ - #[doc = - "outer doc attribute"]#[doc = "macro"]#[allow()]#[attr = Repr([ReprC])] + #[doc = "outer doc attribute"] + #[doc = "macro"] + #[allow()] + #[attr = Repr([ReprC])] struct Struct; } From 809e5b5ed17f6cede5945939bb7f10c5282d9b53 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Apr 2025 16:05:47 +1000 Subject: [PATCH 181/302] Fix some hir pretty-printing over-indenting. --- compiler/rustc_hir_pretty/src/lib.rs | 10 ++-- tests/ui/unpretty/exhaustive.hir.stdout | 61 ++++++++++++------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1e260b2dda45..0916885cb170 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1503,7 +1503,7 @@ impl<'a> State<'a> { } hir::ExprKind::DropTemps(init) => { // Print `{`: - let cb = self.cbox(INDENT_UNIT); + let cb = self.cbox(0); let ib = self.ibox(0); self.bopen(ib); @@ -1530,12 +1530,14 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - let (cb, ib) = self.head("loop"); + let cb = self.cbox(0); + let ib = self.ibox(0); + self.word_nbsp("loop"); self.print_block(blk, cb, ib); } hir::ExprKind::Match(expr, arms, _) => { - let cb = self.cbox(INDENT_UNIT); - let ib = self.ibox(INDENT_UNIT); + let cb = self.cbox(0); + let ib = self.ibox(0); self.word_nbsp("match"); self.print_expr_as_cond(expr); self.space(); diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 885135e590d2..c1230e597ced 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -173,32 +173,32 @@ mod expressions { fn expr_for_loop() { let x; { - let _t = - match #[lang = "into_iter"](x) { - mut iter => - loop { - match #[lang = "next"](&mut iter) { - #[lang = "None"] {} => break, - #[lang = "Some"] { 0: _ } => { } - } - }, - }; - _t - }; + let _t = + match #[lang = "into_iter"](x) { + mut iter => + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + }; { - let _t = - match #[lang = "into_iter"](x) { - mut iter => - 'a: - loop { - match #[lang = "next"](&mut iter) { - #[lang = "None"] {} => break, - #[lang = "Some"] { 0: _ } => { } - } - }, - }; - _t - } + let _t = + match #[lang = "into_iter"](x) { + mut iter => + 'a: + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + } } /// ExprKind::Loop @@ -383,12 +383,11 @@ mod expressions { fn expr_try() { let expr; match #[lang = "branch"](expr) { - #[lang = "Break"] { 0: residual } => - #[allow(unreachable_code)] - return #[lang = "from_residual"](residual), - #[lang = "Continue"] { 0: val } => #[allow(unreachable_code)] - val, - }; + #[lang = "Break"] { 0: residual } => #[allow(unreachable_code)] + return #[lang = "from_residual"](residual), + #[lang = "Continue"] { 0: val } => #[allow(unreachable_code)] + val, + }; } /// ExprKind::Yield fn expr_yield() { yield (); yield true; } From 9af08429f13059fee07a6cb4b019e2bcda3a8093 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Apr 2025 16:23:29 +1000 Subject: [PATCH 182/302] Avoid an indent for labelled loops. --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 4 ++-- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- tests/ui/unpretty/exhaustive.hir.stdout | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index abcbb88aab2d..c9a7e2aebd01 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -485,12 +485,12 @@ impl<'a> State<'a> { self.print_block_with_attrs(body, attrs, cb, ib); } ast::ExprKind::Loop(blk, opt_label, _) => { + let cb = self.cbox(0); + let ib = self.ibox(0); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } - let cb = self.cbox(0); - let ib = self.ibox(0); self.word_nbsp("loop"); self.print_block_with_attrs(blk, attrs, cb, ib); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0916885cb170..09bf84ab64fb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1526,12 +1526,12 @@ impl<'a> State<'a> { self.print_if(test, blk, elseopt); } hir::ExprKind::Loop(blk, opt_label, _, _) => { + let cb = self.cbox(0); + let ib = self.ibox(0); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } - let cb = self.cbox(0); - let ib = self.ibox(0); self.word_nbsp("loop"); self.print_block(blk, cb, ib); } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index c1230e597ced..c20f123b16e8 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -189,8 +189,7 @@ mod expressions { let _t = match #[lang = "into_iter"](x) { mut iter => - 'a: - loop { + 'a: loop { match #[lang = "next"](&mut iter) { #[lang = "None"] {} => break, #[lang = "Some"] { 0: _ } => { } From ad3c35bea53793ff2b2f93853f688f29643db8bb Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 3 May 2025 02:47:14 +0000 Subject: [PATCH 183/302] add `ReverseSccGraph::compute` --- .../src/region_infer/reverse_sccs.rs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index b2ed8a358279..8e04791461b2 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -7,6 +7,8 @@ use rustc_middle::ty::RegionVid; use crate::RegionInferenceContext; use crate::constraints::ConstraintSccIndex; +use crate::region_infer::ConstraintSccs; +use crate::universal_regions::UniversalRegions; pub(crate) struct ReverseSccGraph { graph: VecGraph, @@ -19,6 +21,29 @@ pub(crate) struct ReverseSccGraph { } impl ReverseSccGraph { + pub(super) fn compute( + constraint_sccs: &ConstraintSccs, + universal_regions: &UniversalRegions<'_>, + ) -> Self { + let graph = constraint_sccs.reverse(); + let mut paired_scc_regions = universal_regions + .universal_regions_iter() + .map(|region| (constraint_sccs.scc(region), region)) + .collect::>(); + paired_scc_regions.sort(); + let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); + + let mut scc_regions = FxIndexMap::default(); + let mut start = 0; + for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { + let (scc, _) = chunk[0]; + + scc_regions.insert(scc, start..start + chunk.len()); + start += chunk.len(); + } + ReverseSccGraph { graph, scc_regions, universal_regions } + } + /// Find all universal regions that are required to outlive the given SCC. pub(super) fn upper_bounds(&self, scc0: ConstraintSccIndex) -> impl Iterator { let mut duplicates = FxIndexSet::default(); @@ -40,23 +65,7 @@ impl RegionInferenceContext<'_> { return; } - let graph = self.constraint_sccs.reverse(); - let mut paired_scc_regions = self - .universal_regions() - .universal_regions_iter() - .map(|region| (self.constraint_sccs.scc(region), region)) - .collect::>(); - paired_scc_regions.sort(); - let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); - - let mut scc_regions = FxIndexMap::default(); - let mut start = 0; - for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { - let (scc, _) = chunk[0]; - scc_regions.insert(scc, start..start + chunk.len()); - start += chunk.len(); - } - - self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions }); + self.rev_scc_graph = + Some(ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions())); } } From 27f83a5e056a1d6d24b18a4fd257298d2e97c21a Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 3 May 2025 02:49:15 +0000 Subject: [PATCH 184/302] TypeChecker take fields by ref --- compiler/rustc_borrowck/src/type_check/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 99a544279b96..8c5122571209 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -151,8 +151,8 @@ pub(crate) fn type_check<'a, 'tcx>( body, promoted, user_type_annotations: &body.user_type_annotations, - region_bound_pairs, - known_type_outlives_obligations, + region_bound_pairs: ®ion_bound_pairs, + known_type_outlives_obligations: &known_type_outlives_obligations, reported_errors: Default::default(), universal_regions: &universal_region_relations.universal_regions, location_table, @@ -216,8 +216,8 @@ struct TypeChecker<'a, 'tcx> { /// User type annotations are shared between the main MIR and the MIR of /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: RegionBoundPairs<'tcx>, - known_type_outlives_obligations: Vec>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a PoloniusLocationTable, @@ -412,9 +412,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - &self.region_bound_pairs, + self.region_bound_pairs, self.infcx.param_env, - &self.known_type_outlives_obligations, + self.known_type_outlives_obligations, locations, locations.span(self.body), category, @@ -2506,9 +2506,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - &self.region_bound_pairs, + self.region_bound_pairs, self.infcx.param_env, - &self.known_type_outlives_obligations, + self.known_type_outlives_obligations, locations, self.body.span, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. From 0be1ec1ccd2545785661b4beada019fcb84440f6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 3 May 2025 02:52:37 +0000 Subject: [PATCH 185/302] `CreateResult` wrap more fields in `Frozen` --- .../src/type_check/free_region_relations.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 536a27763d29..92732aba29ba 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -41,8 +41,8 @@ type NormalizedInputsAndOutput<'tcx> = Vec>; pub(crate) struct CreateResult<'tcx> { pub(crate) universal_region_relations: Frozen>, - pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, - pub(crate) known_type_outlives_obligations: Vec>, + pub(crate) region_bound_pairs: Frozen>, + pub(crate) known_type_outlives_obligations: Frozen>>, pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -333,8 +333,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { outlives: self.outlives.freeze(), inverse_outlives: self.inverse_outlives.freeze(), }), - known_type_outlives_obligations, - region_bound_pairs: self.region_bound_pairs, + known_type_outlives_obligations: Frozen::freeze(known_type_outlives_obligations), + region_bound_pairs: Frozen::freeze(self.region_bound_pairs), normalized_inputs_and_output, } } From cbdd7134ff72aaf3679f4df2b2e4a0fe847edd06 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 17:49:53 -0700 Subject: [PATCH 186/302] Implement Iterator::last for vec::IntoIter --- library/alloc/src/vec/into_iter.rs | 5 +++++ library/std/src/sys/args/common.rs | 4 ++-- .../tests/ui/double_ended_iterator_last.fixed | 15 ++++++++++++++- .../clippy/tests/ui/double_ended_iterator_last.rs | 15 ++++++++++++++- .../tests/ui/double_ended_iterator_last.stderr | 4 ++-- .../ui/double_ended_iterator_last_unfixable.rs | 15 ++++++++++++++- .../double_ended_iterator_last_unfixable.stderr | 4 ++-- 7 files changed, 53 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 1af110691ba6..37df928228d9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -258,6 +258,11 @@ impl Iterator for IntoIter { self.len() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + #[inline] fn next_chunk(&mut self) -> Result<[T; N], core::array::IntoIter> { let mut raw_ary = [const { MaybeUninit::uninit() }; N]; diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index 303b373ccf90..e787105a05a7 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -49,8 +49,8 @@ impl Iterator for Args { } #[inline] - fn last(mut self) -> Option { - self.iter.next_back() + fn last(self) -> Option { + self.iter.last() } #[inline] diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed index 2ce0c04c3017..be31ee5fb486 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed @@ -84,6 +84,19 @@ fn issue_14139() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -92,7 +105,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let mut v = v.into_iter(); + let mut v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.next_back().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` println!("Done"); diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs index a4eb9b3337b9..30864e15bce7 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs @@ -84,6 +84,19 @@ fn issue_14139() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -92,7 +105,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let v = v.into_iter(); + let v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.last().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` println!("Done"); diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr index fe8cf2dcb259..72a6ead47a93 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr @@ -18,7 +18,7 @@ LL | let _ = DeIterator.last(); | help: try: `next_back()` error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:96:36 + --> tests/ui/double_ended_iterator_last.rs:109:36 | LL | println!("Last element is {}", v.last().unwrap().0); | ^^^^^^^^ @@ -26,7 +26,7 @@ LL | println!("Last element is {}", v.last().unwrap().0); = note: this change will alter drop order which may be undesirable help: try | -LL ~ let mut v = v.into_iter(); +LL ~ let mut v = DropDeIterator(v.into_iter()); LL ~ println!("Last element is {}", v.next_back().unwrap().0); | diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs index 7c5de8832d69..e9218bbb4094 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs @@ -11,6 +11,19 @@ fn main() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -19,7 +32,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let v = (v.into_iter(), 42); + let v = (DropDeIterator(v.into_iter()), 42); println!("Last element is {}", v.0.last().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` println!("Done"); diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr index 845afc11f042..e330a22a3548 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr @@ -1,5 +1,5 @@ error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^^------ @@ -8,7 +8,7 @@ LL | println!("Last element is {}", v.0.last().unwrap().0); | = note: this change will alter drop order which may be undesirable note: this must be made mutable to use `.next_back()` - --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^ From 8a166dc1948f777b0fa626d051cea5fa2da70182 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 3 May 2025 04:53:15 +0000 Subject: [PATCH 187/302] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 66b4fe2bf3bf..97bc826b57a4 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0c33fe2c3d3eecadd17a84b110bb067288a64f1c +2ad5f8607d0e192b60b130e5cc416b477b351c18 From 1327f7034916dcfdf3038028d6a25726e0d52fef Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 3 May 2025 12:45:00 +0800 Subject: [PATCH 188/302] Improve the let code snippet --- .../ide-completion/src/completions/expr.rs | 11 ++- .../ide-completion/src/completions/keyword.rs | 96 ++++++++++++++++++- 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index ee1a21f9a1a6..2245f58bc620 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -363,9 +363,14 @@ pub(crate) fn complete_expr_path( add_keyword("true", "true"); add_keyword("false", "false"); - if in_condition || in_block_expr { - add_keyword("letm", "let mut $0"); - add_keyword("let", "let $0"); + if in_condition { + add_keyword("letm", "let mut $1 = $0"); + add_keyword("let", "let $1 = $0"); + } + + if in_block_expr { + add_keyword("letm", "let mut $1 = $2;"); + add_keyword("let", "let $1 = $2;"); } if after_if_expr { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 039742463c81..0becdf065aca 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -336,7 +336,7 @@ fn main() { } #[test] - fn completes_let_with_space() { + fn completes_let_in_block() { check_edit( "let", r#" @@ -346,7 +346,7 @@ fn main() { "#, r#" fn main() { - let $0 + let $1 = $2; } "#, ); @@ -359,7 +359,97 @@ fn main() { "#, r#" fn main() { - let mut $0 + let mut $1 = $2; +} +"#, + ); + } + + #[test] + fn completes_let_in_condition() { + check_edit( + "let", + r#" +fn main() { + if $0 {} +} +"#, + r#" +fn main() { + if let $1 = $0 {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if $0 {} +} +"#, + r#" +fn main() { + if let mut $1 = $0 {} +} +"#, + ); + } + + #[test] + fn completes_let_in_no_empty_condition() { + check_edit( + "let", + r#" +fn main() { + if $0x {} +} +"#, + r#" +fn main() { + if let $1 = $0x {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if $0x {} +} +"#, + r#" +fn main() { + if let mut $1 = $0x {} +} +"#, + ); + } + + #[test] + fn completes_let_in_condition_block() { + check_edit( + "let", + r#" +fn main() { + if { $0 } {} +} +"#, + r#" +fn main() { + if { let $1 = $2; } {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if { $0 } {} +} +"#, + r#" +fn main() { + if { let mut $1 = $2; } {} } "#, ); From 61488e5070b0af9697250af27df5d0aa36fe7c73 Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 28 Apr 2025 22:25:00 +0200 Subject: [PATCH 189/302] Fix test simd/extract-insert-dyn on s390x Fix the test for s390x by enabling s390x vector extension via `target_feature(enable = "vector")`(#127506). As this is is still gated by `#![feature(s390x_target_feature)]` we need that attribute also. --- tests/codegen/simd/extract-insert-dyn.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/codegen/simd/extract-insert-dyn.rs b/tests/codegen/simd/extract-insert-dyn.rs index 7d032c6bb3ef..729f0145314a 100644 --- a/tests/codegen/simd/extract-insert-dyn.rs +++ b/tests/codegen/simd/extract-insert-dyn.rs @@ -1,6 +1,12 @@ //@compile-flags: -C opt-level=3 -C no-prepopulate-passes -#![feature(core_intrinsics, repr_simd, arm_target_feature, mips_target_feature)] +#![feature( + core_intrinsics, + repr_simd, + arm_target_feature, + mips_target_feature, + s390x_target_feature +)] #![no_std] #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -25,6 +31,7 @@ pub struct i8x16([i8; 16]); #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { simd_extract_dyn(x, idx) } @@ -36,6 +43,7 @@ unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, 7) } @@ -47,6 +55,7 @@ unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, const { 3 + 4 }) } @@ -58,6 +67,7 @@ unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { simd_extract(x, const { 3 + 4 }) } @@ -69,6 +79,7 @@ unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { simd_insert_dyn(x, idx, e) } @@ -80,6 +91,7 @@ unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, 7, e) } @@ -91,6 +103,7 @@ unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, const { 3 + 4 }, e) } @@ -102,6 +115,7 @@ unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert(x, const { 3 + 4 }, e) } From 7768602f97489bb47bc544f4d005e7a0f4194314 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 3 May 2025 17:03:00 +0800 Subject: [PATCH 190/302] Improve let snippet --- .../crates/ide-completion/src/completions/expr.rs | 4 ++-- .../crates/ide-completion/src/completions/keyword.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 2245f58bc620..7fbd1fbc1af4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -369,8 +369,8 @@ pub(crate) fn complete_expr_path( } if in_block_expr { - add_keyword("letm", "let mut $1 = $2;"); - add_keyword("let", "let $1 = $2;"); + add_keyword("letm", "let mut $1 = $0;"); + add_keyword("let", "let $1 = $0;"); } if after_if_expr { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 0becdf065aca..64bb1fce6ba0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -346,7 +346,7 @@ fn main() { "#, r#" fn main() { - let $1 = $2; + let $1 = $0; } "#, ); @@ -359,7 +359,7 @@ fn main() { "#, r#" fn main() { - let mut $1 = $2; + let mut $1 = $0; } "#, ); @@ -436,7 +436,7 @@ fn main() { "#, r#" fn main() { - if { let $1 = $2; } {} + if { let $1 = $0; } {} } "#, ); @@ -449,7 +449,7 @@ fn main() { "#, r#" fn main() { - if { let mut $1 = $2; } {} + if { let mut $1 = $0; } {} } "#, ); From 265b10fe2e411a7af34f892aaa7635fba96cce2c Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sat, 3 May 2025 20:10:56 +0900 Subject: [PATCH 191/302] Correct warning message in restricted visibility --- compiler/rustc_middle/src/ty/mod.rs | 5 +++- tests/ui/imports/reexports.stderr | 2 +- tests/ui/pub/pub-restricted-warning.rs | 25 ++++++++++++++++++++ tests/ui/pub/pub-restricted-warning.stderr | 27 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/ui/pub/pub-restricted-warning.rs create mode 100644 tests/ui/pub/pub-restricted-warning.stderr diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index eba6d61ba7d3..112010b35082 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -297,7 +297,10 @@ impl Visibility { } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() { "pub(self)".to_string() } else { - format!("pub({})", tcx.item_name(restricted_id.to_def_id())) + format!( + "pub(in crate{})", + tcx.def_path(restricted_id.to_def_id()).to_string_no_crate_verbose() + ) } } ty::Visibility::Public => "pub".to_string(), diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index bf4ba474875b..fa05c0c0f8e8 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -62,7 +62,7 @@ warning: glob import doesn't reexport anything with visibility `pub` because no LL | pub use super::*; | ^^^^^^^^ | -note: the most public imported item is `pub(a)` +note: the most public imported item is `pub(in crate::a)` --> $DIR/reexports.rs:11:17 | LL | pub use super::*; diff --git a/tests/ui/pub/pub-restricted-warning.rs b/tests/ui/pub/pub-restricted-warning.rs new file mode 100644 index 000000000000..80384afbb008 --- /dev/null +++ b/tests/ui/pub/pub-restricted-warning.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![allow(dead_code)] + +mod outer { + pub mod inner { + pub(in crate::outer) struct Foo; + pub fn bar() -> Foo { + //~^ WARNING type `Foo` is more private than the item `outer::inner::bar` [private_interfaces] + Foo + } + } + + pub mod nested { + pub mod inner { + pub(in crate::outer::nested) struct NestedFoo; + pub fn bar() -> NestedFoo { + //~^ WARNING type `NestedFoo` is more private than the item `nested::inner::bar` [private_interfaces] + NestedFoo + } + } + } +} + +fn main() {} diff --git a/tests/ui/pub/pub-restricted-warning.stderr b/tests/ui/pub/pub-restricted-warning.stderr new file mode 100644 index 000000000000..74f32d3de3c2 --- /dev/null +++ b/tests/ui/pub/pub-restricted-warning.stderr @@ -0,0 +1,27 @@ +warning: type `Foo` is more private than the item `outer::inner::bar` + --> $DIR/pub-restricted-warning.rs:8:9 + | +LL | pub fn bar() -> Foo { + | ^^^^^^^^^^^^^^^^^^^ function `outer::inner::bar` is reachable at visibility `pub(crate)` + | +note: but type `Foo` is only usable at visibility `pub(in crate::outer)` + --> $DIR/pub-restricted-warning.rs:7:9 + | +LL | pub(in crate::outer) struct Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + +warning: type `NestedFoo` is more private than the item `nested::inner::bar` + --> $DIR/pub-restricted-warning.rs:17:13 + | +LL | pub fn bar() -> NestedFoo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ function `nested::inner::bar` is reachable at visibility `pub(crate)` + | +note: but type `NestedFoo` is only usable at visibility `pub(in crate::outer::nested)` + --> $DIR/pub-restricted-warning.rs:16:13 + | +LL | pub(in crate::outer::nested) struct NestedFoo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + From 74a17fd049885f8b2c9d1e570a3afea364415d84 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 3 May 2025 15:18:30 +0200 Subject: [PATCH 192/302] Have `AstValidation` track a linting node id --- compiler/rustc_ast_passes/src/ast_validation.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1feb3e9bf9b4..f57f06f37a7b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -82,6 +82,8 @@ struct AstValidator<'a> { /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option, + lint_node_id: NodeId, + lint_buffer: &'a mut LintBuffer, } @@ -839,6 +841,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } + let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id); + if let Some(ident) = item.kind.ident() && attr::contains_name(&item.attrs, sym::no_mangle) { @@ -1128,6 +1132,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } _ => visit::walk_item(self, item), } + + self.lint_node_id = previous_lint_node_id; } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { @@ -1694,6 +1700,7 @@ pub fn check_crate( outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), extern_mod_safety: None, + lint_node_id: CRATE_NODE_ID, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); From f4e1ec111c016f1dbbedb2628a30e9ce20d8e5f1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 3 May 2025 15:19:08 +0200 Subject: [PATCH 193/302] Report the `unsafe_attr_outside_unsafe` lint at the closest node --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_expand/src/config.rs | 7 ++++++- compiler/rustc_expand/src/expand.rs | 6 +++++- compiler/rustc_parse/src/validate_attr.rs | 16 +++++++++++----- .../unsafe-attributes/unsafe-attributes-allow.rs | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f57f06f37a7b..9b64bcc6df44 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -828,7 +828,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.sess.psess, attr); + validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id); } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2df3281568be..02af26b01567 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -274,7 +274,12 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { - validate_attr::check_attribute_safety(&self.sess.psess, AttributeSafety::Normal, &cfg_attr); + validate_attr::check_attribute_safety( + &self.sess.psess, + AttributeSafety::Normal, + &cfg_attr, + ast::CRATE_NODE_ID, + ); // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1f430b0018f5..d4853d1357f3 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1983,7 +1983,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut span: Option = None; while let Some(attr) = attrs.next() { rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); - validate_attr::check_attr(&self.cx.sess.psess, attr); + validate_attr::check_attr( + &self.cx.sess.psess, + attr, + self.cx.current_expansion.lint_node_id, + ); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; span = Some(current_span); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 6a1c2af48ed5..aa29b24fe910 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,7 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, + self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, + Safety, }; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -15,7 +16,7 @@ use rustc_span::{Span, Symbol, sym}; use crate::{errors, parse_in}; -pub fn check_attr(psess: &ParseSess, attr: &Attribute) { +pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) { return; @@ -26,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { // All non-builtin attributes are considered safe let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal); - check_attribute_safety(psess, safety, attr); + check_attribute_safety(psess, safety, attr, id); // Check input tokens for built-in and key-value attributes. match attr_info { @@ -154,7 +155,12 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) { +pub fn check_attribute_safety( + psess: &ParseSess, + safety: AttributeSafety, + attr: &Attribute, + id: NodeId, +) { let attr_item = attr.get_normal_item(); if let AttributeSafety::Unsafe { unsafe_since } = safety { @@ -185,7 +191,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: psess.buffer_lint( UNSAFE_ATTR_OUTSIDE_UNSAFE, path_span, - ast::CRATE_NODE_ID, + id, BuiltinLintDiag::UnsafeAttrOutsideUnsafe { attribute_name_span: path_span, sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs new file mode 100644 index 000000000000..76fdce7e5cff --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs @@ -0,0 +1,16 @@ +//@ check-pass +//@ edition: 2021 +// +// Anti-regression test for https://github.com/rust-lang/rust/issues/140602 +// where the generated warning couldn't be allowed due too being attached to +// the wrong AST node. + +#![deny(unsafe_attr_outside_unsafe)] + +#[allow(unsafe_attr_outside_unsafe)] +mod generated { + #[no_mangle] + fn _generated_foo() {} +} + +fn main() {} From 873ca5fa04b79da80ca779e0e577f06a07cea8d3 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 2 May 2025 22:34:30 +0800 Subject: [PATCH 194/302] Just suggest positional arg and adjust issue0139104 ui test Signed-off-by: xizheyin --- compiler/rustc_parse_format/src/lib.rs | 116 +++++++---------- .../invalid-parse-format-issue-139104.rs | 17 ++- .../invalid-parse-format-issue-139104.stderr | 122 ++++++++++++------ 3 files changed, 147 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index c356a97a55a2..999e71592745 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -918,73 +918,57 @@ impl<'a> Parser<'a> { } fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { - // If the argument is an identifier, it may be a field access. - if arg.is_identifier() { - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); - // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any - // deeper nesting, or another type of expression, like method calls, are not supported - if !self.consume('}') { - return; - } - if let ArgumentNamed(_) = arg.position { - match field.position { - ArgumentNamed(_) => { - self.errors.insert( - 0, - ParseError { - description: "field access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - ArgumentIs(_) => { - self.errors.insert( - 0, - ParseError { - description: "tuple index access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - _ => {} - }; - } - } - } else if matches!(arg.position, ArgumentNamed(_) | ArgumentIs(_)) { - let arg_name = match arg.position { - ArgumentNamed(arg_name) => &format!("`{arg_name}`"), - ArgumentIs(arg_index) => &format!("at index `{arg_index}`"), - _ => unreachable!(), - }; + // If the argument is not an identifier, it is not a field access. + if !arg.is_identifier() { + return; + } - self.errors.insert( - 0, - ParseError { - description: format!("invalid format string for argument {}", arg_name), - note: None, - label: format!("invalid format specifier for this argument"), - span: InnerSpan::new(arg.position_span.start, arg.position_span.end), - secondary_label: None, - suggestion: Suggestion::None, - }, - ); + if let Some(end) = self.consume_pos('.') { + let byte_pos = self.to_span_index(end); + let start = InnerOffset(byte_pos.0 + 1); + let field = self.argument(start); + // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any + // deeper nesting, or another type of expression, like method calls, are not supported + if !self.consume('}') { + return; + } + if let ArgumentNamed(_) = arg.position { + match field.position { + ArgumentNamed(_) => { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + ArgumentIs(_) => { + self.errors.insert( + 0, + ParseError { + description: "tuple index access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + _ => {} + }; + } } } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs index 0809235bb6dd..7644df8be49a 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -1,8 +1,13 @@ fn main() { - println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("xxx{0:_1.4}", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` - println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` - println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4}", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:1.4_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr index ceae8d051e5e..202aa450cab7 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -1,42 +1,92 @@ -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:2:16 +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:2:22 | LL | println!("{foo:_1.4}", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string - -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:3:16 - | -LL | println!("{foo:1.4_1.4}", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string - -error: invalid format string: invalid format string for argument at index `0` - --> $DIR/invalid-parse-format-issue-139104.rs:4:19 - | -LL | println!("xxx{0:_1.4}", 1.11); - | ^ invalid format specifier for this argument in format string - -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:5:16 - | -LL | println!("{foo:_1.4", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string - -error: invalid format string: invalid format string for argument at index `0` - --> $DIR/invalid-parse-format-issue-139104.rs:6:19 - | -LL | println!("xxx{0:_1.4", 1.11); - | ^ invalid format specifier for this argument in format string - -error: invalid format string: expected `}`, found `0` - --> $DIR/invalid-parse-format-issue-139104.rs:7:21 - | -LL | println!("xxx{ 0", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace + | - ^ expected `}` in format string + | | + | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` -error: aborting due to 6 previous errors +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:3:20 + | +LL | println!("{0:_1.4}", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:4:19 + | +LL | println!("{:_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:6:22 + | +LL | println!("{foo:_1.4", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:7:20 + | +LL | println!("{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:8:19 + | +LL | println!("{:_1.4", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `0` + --> $DIR/invalid-parse-format-issue-139104.rs:10:18 + | +LL | println!("{ 0", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:11:25 + | +LL | println!("{foo:1.4_1.4}", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:12:23 + | +LL | println!("{0:1.4_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: aborting due to 9 previous errors From a6cac47500a43ff872475801a83a70c414e756a1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 May 2025 23:29:00 +0800 Subject: [PATCH 195/302] tests: fix a panic strategy in `cfg_false_no_std-2.rs` To avoid having target-dependent "unwinding panics are not supported without std" errors, without regressing test intention. --- tests/ui/cfg/cfg_false_no_std-2.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 18b2c699fd7a..666c90deaf0f 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -1,7 +1,11 @@ // Error, the linked empty library is `no_std` and doesn't provide a panic handler. -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr + +// NOTE: fix a panic strategy to prevent differing errors subject to target's default panic strategy +// which changes between targets. The specific panic strategy doesn't matter for test intention. +//@ compile-flags: -Cpanic=abort + //@ aux-build: cfg_false_lib_no_std_before.rs #![no_std] @@ -11,6 +15,3 @@ extern crate cfg_false_lib_no_std_before as _; fn main() {} //~? ERROR `#[panic_handler]` function required, but not found -// FIXME: This error is target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR unwinding panics are not supported without std From cb73af3e2da60268e8f5f67871870a86b9fff23d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 May 2025 23:40:31 +0800 Subject: [PATCH 196/302] tests: explain why `two-panic-runtimes.rs` ignores target-dependent errors --- tests/ui/panic-runtime/two-panic-runtimes.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/ui/panic-runtime/two-panic-runtimes.rs b/tests/ui/panic-runtime/two-panic-runtimes.rs index 80591edd1077..de76578a267f 100644 --- a/tests/ui/panic-runtime/two-panic-runtimes.rs +++ b/tests/ui/panic-runtime/two-panic-runtimes.rs @@ -1,11 +1,19 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind2.rs //@ aux-build:panic-runtime-lang-items.rs +// NOTE: there can be additional errors regarding trying to mix this crate if the precompiled target +// (such as `wasm32-unknown-unknown` currently unconditionally defaulting to panic=abort) panic +// strategy differs to abort, then involving a potentially-unwinding `panic_runtime_unwind` that +// uses a different panic strategy. These errors are important but not to the test intention, which +// is to check that trying to bring two panic runtimes (`panic_runtime_unwind`) and +// (`panic_runtime_unwind2`) is prohibited. As such, the additional errors are not checked in this +// test. +//@ dont-require-annotations: ERROR + #![no_std] #![no_main] @@ -16,7 +24,3 @@ extern crate panic_runtime_lang_items; fn main() {} //~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind2` is not compiled with this crate's panic strategy `abort` -//FIXME~? ERROR the crate `panic_runtime_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` From 3ea420a697d4fe73c1348d40dac02718fcfccbd9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 May 2025 23:44:07 +0800 Subject: [PATCH 197/302] tests: justify why `want-abort-got-unwind{,2}.rs` ignore additional errors --- tests/ui/panic-runtime/want-abort-got-unwind.rs | 12 +++++++----- tests/ui/panic-runtime/want-abort-got-unwind2.rs | 16 +++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/ui/panic-runtime/want-abort-got-unwind.rs b/tests/ui/panic-runtime/want-abort-got-unwind.rs index 42cdf8bc6626..7a6bd011d9e4 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind.rs @@ -1,16 +1,18 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ compile-flags:-C panic=abort +// NOTE: depending on the target's default panic strategy, there can be additional errors that +// complain about linking two panic runtimes (e.g. precompiled `panic_unwind` if target default +// panic strategy is unwind, in addition to `panic_runtime_unwind`). These additional errors will +// not be observed on targets whose default panic strategy is abort, where `panic_abort` is linked +// in instead. +//@ dont-require-annotations: ERROR + extern crate panic_runtime_unwind; fn main() {} //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panic-runtime/want-abort-got-unwind2.rs b/tests/ui/panic-runtime/want-abort-got-unwind2.rs index ddf12cd2a9a5..da239a675e5b 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind2.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind2.rs @@ -1,17 +1,23 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs //@ compile-flags:-C panic=abort +// Like `want-abort-got-unwind.rs`, this version checks that if the root binary wants abort panic +// runtime, that the compiler rejects a setup where a dependency crate in the dependency DAG +// transitively provides an unwind panic runtime (which also is built with `-Cpanic=unwind`, making +// that potentially-unwinding). + +// NOTE: similar to `want-abort-got-unwind.rs`, there can be additional errors if the target default +// panic strategy is unwind, because then the precompiled `panic_unwind` would also be linked in, +// duplicating `panic_runtime_unwind` (transitively). But those additional errors are not important +// to test intention. +//@ dont-require-annotations: ERROR + extern crate wants_panic_runtime_unwind; fn main() {} //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` From 48b72c52f35be9d4d0c6ee4c42487354b73d931e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 May 2025 23:34:59 +0800 Subject: [PATCH 198/302] tests: add FIXME issue for `debuginfo-type-name-layout-ice-94961-2.rs` --- .../debuginfo/debuginfo-type-name-layout-ice-94961-2.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs index b79b5ff6fdb1..08f8ae391fdb 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs @@ -1,4 +1,6 @@ -//FIXME~ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +// ignore-tidy-linelength +// FIXME(#140620)~ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture + // Make sure the compiler does not ICE when trying to generate the debuginfo name of a type that // causes a layout error. // This version of the test already ICE'd before the commit that introduce the ICE described in @@ -18,5 +20,5 @@ pub fn foo() -> usize { std::mem::size_of::>() } -// FIXME: the error is reported on different lines on different targets -//FIXME~? ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +// FIXME(#140620): the error is reported on different lines on different targets +//FIXME(#140620)~? ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture From 9a574b0871746808d292f4f945b7854342118f35 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 3 May 2025 17:22:52 +0200 Subject: [PATCH 199/302] Move some tests out of tests/ui --- src/tools/tidy/src/issues.txt | 10 --- .../no_link/auxiliary/empty-crate-1.rs} | 2 - .../no_link/auxiliary/empty-crate-2.rs} | 0 .../no_link/auxiliary/no_link-crate.rs | 6 ++ .../no_link/multiple-crates-and-no_link.rs | 17 +++++ .../no_link/no-link-unknown-crate.rs | 19 +++++ .../no_link}/no-link-unknown-crate.stderr | 2 +- tests/ui/auxiliary/inner_static.rs | 51 -------------- tests/ui/auxiliary/issue-13560-3.rs | 6 -- .../auxiliary/inline-cross-crate.rs} | 0 .../llvm-miscompile-MarkValue-MaybeLive.rs} | 0 tests/ui/cross-crate/inline-cross-crate.rs | 12 ++++ .../llvm-miscompile-MarkValue-MaybeLive.rs | 22 ++++++ tests/ui/impl-privacy-xc-1.rs | 10 --- tests/ui/inner-static.rs | 14 ---- tests/ui/issue-13560.rs | 13 ---- tests/ui/issue-18502.rs | 8 --- tests/ui/issue-24106.rs | 8 --- tests/ui/issue-76387-llvm-miscompile.rs | 21 ------ .../ui/{ => macros}/auxiliary/fancy-panic.rs | 0 tests/ui/{ => macros}/non-fmt-panic.fixed | 6 ++ tests/ui/{ => macros}/non-fmt-panic.rs | 6 ++ tests/ui/{ => macros}/non-fmt-panic.stderr | 70 +++++++++---------- tests/ui/no-link-unknown-crate.rs | 4 -- .../auxiliary/cross-crate-enum-pattern.rs} | 0 tests/ui/pattern/cross-crate-enum-pattern.rs | 13 ++++ .../auxiliary/impl-privacy-cross-crate-1.rs} | 0 ..._xc_2.rs => impl-privacy-cross-crate-2.rs} | 0 .../ui/privacy/impl-privacy-cross-crate-1.rs | 10 +++ .../ui/privacy/impl-privacy-cross-crate-2.rs | 10 +++ tests/ui/privacy/impl-privacy-xc-2.rs | 10 --- tests/ui/statics/auxiliary/inner_static.rs | 67 ++++++++++++++++++ tests/ui/statics/inner-static.rs | 30 ++++++++ 33 files changed, 254 insertions(+), 193 deletions(-) rename tests/ui/{auxiliary/issue-13560-1.rs => attributes/no_link/auxiliary/empty-crate-1.rs} (52%) rename tests/ui/{auxiliary/issue-13560-2.rs => attributes/no_link/auxiliary/empty-crate-2.rs} (100%) create mode 100644 tests/ui/attributes/no_link/auxiliary/no_link-crate.rs create mode 100644 tests/ui/attributes/no_link/multiple-crates-and-no_link.rs create mode 100644 tests/ui/attributes/no_link/no-link-unknown-crate.rs rename tests/ui/{ => attributes/no_link}/no-link-unknown-crate.stderr (85%) delete mode 100644 tests/ui/auxiliary/inner_static.rs delete mode 100644 tests/ui/auxiliary/issue-13560-3.rs rename tests/ui/{auxiliary/issue-18502.rs => cross-crate/auxiliary/inline-cross-crate.rs} (100%) rename tests/ui/{auxiliary/issue-76387.rs => cross-crate/auxiliary/llvm-miscompile-MarkValue-MaybeLive.rs} (100%) create mode 100644 tests/ui/cross-crate/inline-cross-crate.rs create mode 100644 tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs delete mode 100644 tests/ui/impl-privacy-xc-1.rs delete mode 100644 tests/ui/inner-static.rs delete mode 100644 tests/ui/issue-13560.rs delete mode 100644 tests/ui/issue-18502.rs delete mode 100644 tests/ui/issue-24106.rs delete mode 100644 tests/ui/issue-76387-llvm-miscompile.rs rename tests/ui/{ => macros}/auxiliary/fancy-panic.rs (100%) rename tests/ui/{ => macros}/non-fmt-panic.fixed (94%) rename tests/ui/{ => macros}/non-fmt-panic.rs (94%) rename tests/ui/{ => macros}/non-fmt-panic.stderr (93%) delete mode 100644 tests/ui/no-link-unknown-crate.rs rename tests/ui/{auxiliary/issue-24106.rs => pattern/auxiliary/cross-crate-enum-pattern.rs} (100%) create mode 100644 tests/ui/pattern/cross-crate-enum-pattern.rs rename tests/ui/{auxiliary/impl_privacy_xc_1.rs => privacy/auxiliary/impl-privacy-cross-crate-1.rs} (100%) rename tests/ui/privacy/auxiliary/{impl_privacy_xc_2.rs => impl-privacy-cross-crate-2.rs} (100%) create mode 100644 tests/ui/privacy/impl-privacy-cross-crate-1.rs create mode 100644 tests/ui/privacy/impl-privacy-cross-crate-2.rs delete mode 100644 tests/ui/privacy/impl-privacy-xc-2.rs create mode 100644 tests/ui/statics/auxiliary/inner_static.rs create mode 100644 tests/ui/statics/inner-static.rs diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index e6b5aa59622d..2f0158609e08 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -276,13 +276,7 @@ ui/auto-traits/issue-23080-2.rs ui/auto-traits/issue-23080.rs ui/auto-traits/issue-83857-ub.rs ui/auto-traits/issue-84075.rs -ui/auxiliary/issue-13560-1.rs -ui/auxiliary/issue-13560-2.rs -ui/auxiliary/issue-13560-3.rs ui/auxiliary/issue-16822.rs -ui/auxiliary/issue-18502.rs -ui/auxiliary/issue-24106.rs -ui/auxiliary/issue-76387.rs ui/bench/issue-32062.rs ui/binding/issue-40402-1.rs ui/binding/issue-40402-2.rs @@ -1378,12 +1372,8 @@ ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs ui/issue-11881.rs -ui/issue-13560.rs ui/issue-15924.rs ui/issue-16822.rs -ui/issue-18502.rs -ui/issue-24106.rs -ui/issue-76387-llvm-miscompile.rs ui/issues-71798.rs ui/issues/auxiliary/issue-11224.rs ui/issues/auxiliary/issue-11508.rs diff --git a/tests/ui/auxiliary/issue-13560-1.rs b/tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs similarity index 52% rename from tests/ui/auxiliary/issue-13560-1.rs rename to tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs index baca1567e1b0..8bd2b3353b8f 100644 --- a/tests/ui/auxiliary/issue-13560-1.rs +++ b/tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs @@ -1,3 +1 @@ -//@ no-prefer-dynamic - #![crate_type = "dylib"] diff --git a/tests/ui/auxiliary/issue-13560-2.rs b/tests/ui/attributes/no_link/auxiliary/empty-crate-2.rs similarity index 100% rename from tests/ui/auxiliary/issue-13560-2.rs rename to tests/ui/attributes/no_link/auxiliary/empty-crate-2.rs diff --git a/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs b/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs new file mode 100644 index 000000000000..1c3af5431cc6 --- /dev/null +++ b/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic + +#![crate_type = "rlib"] + +#[macro_use] #[no_link] extern crate empty_crate_1 as t1; +#[macro_use] extern crate empty_crate_2 as t2; diff --git a/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs b/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs new file mode 100644 index 000000000000..0e6f1deb2172 --- /dev/null +++ b/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs @@ -0,0 +1,17 @@ +//! Regression test for #13560. Previously, it was possible to +//! trigger an assert in crate numbering if a series of crates +//! being loaded included a "syntax-only" extern crate. +//! But it appears we don't mess with crate numbering for +//! `#[no_link]` crates anymore, so this test doesn't seem +//! to test anything now. + +//@ run-pass +//@ needs-crate-type: dylib +//@ aux-build:empty-crate-1.rs +//@ aux-build:empty-crate-2.rs +//@ aux-build:no_link-crate.rs + +extern crate empty_crate_2 as t2; +extern crate no_link_crate as t3; + +fn main() {} diff --git a/tests/ui/attributes/no_link/no-link-unknown-crate.rs b/tests/ui/attributes/no_link/no-link-unknown-crate.rs new file mode 100644 index 000000000000..3a91fa27ee3b --- /dev/null +++ b/tests/ui/attributes/no_link/no-link-unknown-crate.rs @@ -0,0 +1,19 @@ +//! Unfortunately the development of `#[phase]` and `#[no_link]` +//! predates Zulip, and thus has been lost in the sands of time. +//! Understanding the true nature of this test has been left as +//! an exercise for the reader. +//! +//! But we guess from the git history that originally this +//! test was supposed to check that we error if we can't find +//! an extern crate annotated with `#[phase(syntax)]`, +//! see `macro-crate-unknown-crate.rs` in +//! . Later, we changed +//! `#[phase]` to `#![feature(plugin)]` and added a `#[no_link]`. +//! +//! I suppose that this now tests that we still error if we can't +//! find a `#[no_link]` extern crate? + +#[no_link] +extern crate doesnt_exist; //~ ERROR can't find crate + +fn main() {} diff --git a/tests/ui/no-link-unknown-crate.stderr b/tests/ui/attributes/no_link/no-link-unknown-crate.stderr similarity index 85% rename from tests/ui/no-link-unknown-crate.stderr rename to tests/ui/attributes/no_link/no-link-unknown-crate.stderr index edc248db09ea..999b013866cd 100644 --- a/tests/ui/no-link-unknown-crate.stderr +++ b/tests/ui/attributes/no_link/no-link-unknown-crate.stderr @@ -1,5 +1,5 @@ error[E0463]: can't find crate for `doesnt_exist` - --> $DIR/no-link-unknown-crate.rs:2:1 + --> $DIR/no-link-unknown-crate.rs:17:1 | LL | extern crate doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate diff --git a/tests/ui/auxiliary/inner_static.rs b/tests/ui/auxiliary/inner_static.rs deleted file mode 100644 index 42dcd379d41e..000000000000 --- a/tests/ui/auxiliary/inner_static.rs +++ /dev/null @@ -1,51 +0,0 @@ -pub struct A { pub v: T } -pub struct B { pub v: T } - -pub mod test { - pub struct A { pub v: T } - - impl A { - pub fn foo(&self) -> isize { - static a: isize = 5; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 6; - return a; - } - } -} - -impl A { - pub fn foo(&self) -> isize { - static a: isize = 1; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 2; - return a; - } -} - -impl B { - pub fn foo(&self) -> isize { - static a: isize = 3; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 4; - return a; - } -} - -pub fn foo() -> isize { - let a = A { v: () }; - let b = B { v: () }; - let c = test::A { v: () }; - return a.foo() + a.bar() + - b.foo() + b.bar() + - c.foo() + c.bar(); -} diff --git a/tests/ui/auxiliary/issue-13560-3.rs b/tests/ui/auxiliary/issue-13560-3.rs deleted file mode 100644 index 4aab2ddc73a0..000000000000 --- a/tests/ui/auxiliary/issue-13560-3.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ no-prefer-dynamic - -#![crate_type = "rlib"] - -#[macro_use] #[no_link] extern crate issue_13560_1 as t1; -#[macro_use] extern crate issue_13560_2 as t2; diff --git a/tests/ui/auxiliary/issue-18502.rs b/tests/ui/cross-crate/auxiliary/inline-cross-crate.rs similarity index 100% rename from tests/ui/auxiliary/issue-18502.rs rename to tests/ui/cross-crate/auxiliary/inline-cross-crate.rs diff --git a/tests/ui/auxiliary/issue-76387.rs b/tests/ui/cross-crate/auxiliary/llvm-miscompile-MarkValue-MaybeLive.rs similarity index 100% rename from tests/ui/auxiliary/issue-76387.rs rename to tests/ui/cross-crate/auxiliary/llvm-miscompile-MarkValue-MaybeLive.rs diff --git a/tests/ui/cross-crate/inline-cross-crate.rs b/tests/ui/cross-crate/inline-cross-crate.rs new file mode 100644 index 000000000000..273aa8f8f0d8 --- /dev/null +++ b/tests/ui/cross-crate/inline-cross-crate.rs @@ -0,0 +1,12 @@ +//! Dpn't ice on using an inlined function from another crate +//! See and +//! + +//@ run-pass +//@ aux-build:inline-cross-crate.rs + +extern crate inline_cross_crate as fmt; + +fn main() { + ::fmt::baz(); +} diff --git a/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs b/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs new file mode 100644 index 000000000000..95d022ddd96e --- /dev/null +++ b/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs @@ -0,0 +1,22 @@ +//! Regression test for +//! Tests that LLVM doesn't miscompile this +//! See upstream fix: . + +//@ compile-flags: -C opt-level=3 +//@ aux-build: llvm-miscompile-MarkValue-MaybeLive.rs +//@ run-pass + +extern crate llvm_miscompile_MarkValue_MaybeLive; + +use llvm_miscompile_MarkValue_MaybeLive::FatPtr; + +fn print(data: &[u8]) { + println!("{:#?}", data); +} + +fn main() { + let ptr = FatPtr::new(20); + let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), ptr.len()) }; + + print(data); +} diff --git a/tests/ui/impl-privacy-xc-1.rs b/tests/ui/impl-privacy-xc-1.rs deleted file mode 100644 index 6a10986739cd..000000000000 --- a/tests/ui/impl-privacy-xc-1.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ aux-build:impl_privacy_xc_1.rs - - -extern crate impl_privacy_xc_1; - -pub fn main() { - let fish = impl_privacy_xc_1::Fish { x: 1 }; - fish.swim(); -} diff --git a/tests/ui/inner-static.rs b/tests/ui/inner-static.rs deleted file mode 100644 index 9455ec5712fe..000000000000 --- a/tests/ui/inner-static.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -//@ aux-build:inner_static.rs - - -extern crate inner_static; - -pub fn main() { - let a = inner_static::A::<()> { v: () }; - let b = inner_static::B::<()> { v: () }; - let c = inner_static::test::A::<()> { v: () }; - assert_eq!(a.bar(), 2); - assert_eq!(b.bar(), 4); - assert_eq!(c.bar(), 6); -} diff --git a/tests/ui/issue-13560.rs b/tests/ui/issue-13560.rs deleted file mode 100644 index 6174fa9324b1..000000000000 --- a/tests/ui/issue-13560.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -//@ ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header) -//@ aux-build:issue-13560-1.rs -//@ aux-build:issue-13560-2.rs -//@ aux-build:issue-13560-3.rs - -// Regression test for issue #13560, the test itself is all in the dependent -// libraries. The fail which previously failed to compile is the one numbered 3. - -extern crate issue_13560_2 as t2; -extern crate issue_13560_3 as t3; - -fn main() {} diff --git a/tests/ui/issue-18502.rs b/tests/ui/issue-18502.rs deleted file mode 100644 index 3e2c37ee8aa9..000000000000 --- a/tests/ui/issue-18502.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -//@ aux-build:issue-18502.rs - -extern crate issue_18502 as fmt; - -fn main() { - ::fmt::baz(); -} diff --git a/tests/ui/issue-24106.rs b/tests/ui/issue-24106.rs deleted file mode 100644 index 4f7b299b12f5..000000000000 --- a/tests/ui/issue-24106.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -//@ aux-build:issue-24106.rs - -extern crate issue_24106; - -fn main() { - issue_24106::go::<()>(); -} diff --git a/tests/ui/issue-76387-llvm-miscompile.rs b/tests/ui/issue-76387-llvm-miscompile.rs deleted file mode 100644 index d674ebb5eaf1..000000000000 --- a/tests/ui/issue-76387-llvm-miscompile.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C opt-level=3 -//@ aux-build: issue-76387.rs -//@ run-pass - -// Regression test for issue #76387 -// Tests that LLVM doesn't miscompile this - -extern crate issue_76387; - -use issue_76387::FatPtr; - -fn print(data: &[u8]) { - println!("{:#?}", data); -} - -fn main() { - let ptr = FatPtr::new(20); - let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), ptr.len()) }; - - print(data); -} diff --git a/tests/ui/auxiliary/fancy-panic.rs b/tests/ui/macros/auxiliary/fancy-panic.rs similarity index 100% rename from tests/ui/auxiliary/fancy-panic.rs rename to tests/ui/macros/auxiliary/fancy-panic.rs diff --git a/tests/ui/non-fmt-panic.fixed b/tests/ui/macros/non-fmt-panic.fixed similarity index 94% rename from tests/ui/non-fmt-panic.fixed rename to tests/ui/macros/non-fmt-panic.fixed index fa9a1ad89bdd..b102dba17319 100644 --- a/tests/ui/non-fmt-panic.fixed +++ b/tests/ui/macros/non-fmt-panic.fixed @@ -1,3 +1,9 @@ +//! The non_fmt_panics lint detects panic!(..) invocations where +//! the first argument is not a formatting string. +//! +//! Also, this test checks that this is not emitted if it originates +//! in an external macro. + //@ run-rustfix //@ rustfix-only-machine-applicable //@ build-pass (FIXME(62277): should be check-pass) diff --git a/tests/ui/non-fmt-panic.rs b/tests/ui/macros/non-fmt-panic.rs similarity index 94% rename from tests/ui/non-fmt-panic.rs rename to tests/ui/macros/non-fmt-panic.rs index 451a0c76018c..9277529c6d42 100644 --- a/tests/ui/non-fmt-panic.rs +++ b/tests/ui/macros/non-fmt-panic.rs @@ -1,3 +1,9 @@ +//! The non_fmt_panics lint detects panic!(..) invocations where +//! the first argument is not a formatting string. +//! +//! Also, this test checks that this is not emitted if it originates +//! in an external macro. + //@ run-rustfix //@ rustfix-only-machine-applicable //@ build-pass (FIXME(62277): should be check-pass) diff --git a/tests/ui/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr similarity index 93% rename from tests/ui/non-fmt-panic.stderr rename to tests/ui/macros/non-fmt-panic.stderr index 0134a8ddf292..30b63cb46e22 100644 --- a/tests/ui/non-fmt-panic.stderr +++ b/tests/ui/macros/non-fmt-panic.stderr @@ -1,5 +1,5 @@ warning: panic message contains a brace - --> $DIR/non-fmt-panic.rs:13:29 + --> $DIR/non-fmt-panic.rs:19:29 | LL | panic!("here's a brace: {"); | ^ @@ -12,7 +12,7 @@ LL | panic!("{}", "here's a brace: {"); | +++++ warning: panic message contains a brace - --> $DIR/non-fmt-panic.rs:14:35 + --> $DIR/non-fmt-panic.rs:20:35 | LL | unreachable!("here's a brace: {"); | ^ @@ -24,7 +24,7 @@ LL | unreachable!("{}", "here's a brace: {"); | +++++ warning: panic message contains a brace - --> $DIR/non-fmt-panic.rs:15:31 + --> $DIR/non-fmt-panic.rs:21:31 | LL | std::panic!("another one: }"); | ^ @@ -36,7 +36,7 @@ LL | std::panic!("{}", "another one: }"); | +++++ warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:16:25 + --> $DIR/non-fmt-panic.rs:22:25 | LL | core::panic!("Hello {}"); | ^^ @@ -52,7 +52,7 @@ LL | core::panic!("{}", "Hello {}"); | +++++ warning: panic message contains unused formatting placeholders - --> $DIR/non-fmt-panic.rs:17:21 + --> $DIR/non-fmt-panic.rs:23:21 | LL | assert!(false, "{:03x} {test} bla"); | ^^^^^^ ^^^^^^ @@ -68,7 +68,7 @@ LL | assert!(false, "{}", "{:03x} {test} bla"); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:19:20 + --> $DIR/non-fmt-panic.rs:25:20 | LL | assert!(false, S); | ^ @@ -81,7 +81,7 @@ LL | assert!(false, "{}", S); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:21:20 + --> $DIR/non-fmt-panic.rs:27:20 | LL | assert!(false, 123); | ^^^ @@ -94,7 +94,7 @@ LL | assert!(false, "{}", 123); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:23:20 + --> $DIR/non-fmt-panic.rs:29:20 | LL | assert!(false, Some(123)); | ^^^^^^^^^ @@ -107,7 +107,7 @@ LL | assert!(false, "{:?}", Some(123)); | +++++++ warning: panic message contains braces - --> $DIR/non-fmt-panic.rs:25:27 + --> $DIR/non-fmt-panic.rs:31:27 | LL | debug_assert!(false, "{{}} bla"); | ^^^^ @@ -119,7 +119,7 @@ LL | debug_assert!(false, "{}", "{{}} bla"); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:26:12 + --> $DIR/non-fmt-panic.rs:32:12 | LL | panic!(C); | ^ @@ -132,7 +132,7 @@ LL | panic!("{}", C); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:27:12 + --> $DIR/non-fmt-panic.rs:33:12 | LL | panic!(S); | ^ @@ -145,7 +145,7 @@ LL | panic!("{}", S); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:28:18 + --> $DIR/non-fmt-panic.rs:34:18 | LL | unreachable!(S); | ^ @@ -158,7 +158,7 @@ LL | unreachable!("{}", S); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:29:18 + --> $DIR/non-fmt-panic.rs:35:18 | LL | unreachable!(S); | ^ @@ -171,7 +171,7 @@ LL | unreachable!("{}", S); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:30:17 + --> $DIR/non-fmt-panic.rs:36:17 | LL | std::panic!(123); | ^^^ @@ -189,7 +189,7 @@ LL + std::panic::panic_any(123); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:31:18 + --> $DIR/non-fmt-panic.rs:37:18 | LL | core::panic!(&*"abc"); | ^^^^^^^ @@ -202,7 +202,7 @@ LL | core::panic!("{}", &*"abc"); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:32:12 + --> $DIR/non-fmt-panic.rs:38:12 | LL | panic!(Some(123)); | ^^^^^^^^^ @@ -220,7 +220,7 @@ LL + std::panic::panic_any(Some(123)); | warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:33:12 + --> $DIR/non-fmt-panic.rs:39:12 | LL | panic!(concat!("{", "}")); | ^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | panic!("{}", concat!("{", "}")); | +++++ warning: panic message contains braces - --> $DIR/non-fmt-panic.rs:34:5 + --> $DIR/non-fmt-panic.rs:40:5 | LL | panic!(concat!("{", "{")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -248,7 +248,7 @@ LL | panic!("{}", concat!("{", "{")); | +++++ warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:36:37 + --> $DIR/non-fmt-panic.rs:42:37 | LL | fancy_panic::fancy_panic!("test {} 123"); | ^^ @@ -256,7 +256,7 @@ LL | fancy_panic::fancy_panic!("test {} 123"); = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:46:12 + --> $DIR/non-fmt-panic.rs:52:12 | LL | panic!(a!()); | ^^^^ @@ -274,7 +274,7 @@ LL + std::panic::panic_any(a!()); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:47:18 + --> $DIR/non-fmt-panic.rs:53:18 | LL | unreachable!(a!()); | ^^^^ @@ -287,7 +287,7 @@ LL | unreachable!("{}", a!()); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:49:12 + --> $DIR/non-fmt-panic.rs:55:12 | LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -302,7 +302,7 @@ LL + panic!("{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:50:18 + --> $DIR/non-fmt-panic.rs:56:18 | LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -317,7 +317,7 @@ LL + unreachable!("{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:51:20 + --> $DIR/non-fmt-panic.rs:57:20 | LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -332,7 +332,7 @@ LL + assert!(false, "{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:52:26 + --> $DIR/non-fmt-panic.rs:58:26 | LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -347,7 +347,7 @@ LL + debug_assert!(false, "{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:54:12 + --> $DIR/non-fmt-panic.rs:60:12 | LL | panic![123]; | ^^^ @@ -365,7 +365,7 @@ LL + std::panic::panic_any(123); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:55:12 + --> $DIR/non-fmt-panic.rs:61:12 | LL | panic!{123}; | ^^^ @@ -383,7 +383,7 @@ LL + std::panic::panic_any(123); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:72:12 + --> $DIR/non-fmt-panic.rs:78:12 | LL | panic!(v); | ------ ^ @@ -394,7 +394,7 @@ LL | panic!(v); = note: for more information, see warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:73:20 + --> $DIR/non-fmt-panic.rs:79:20 | LL | assert!(false, v); | ^ @@ -403,7 +403,7 @@ LL | assert!(false, v); = note: for more information, see warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:77:12 + --> $DIR/non-fmt-panic.rs:83:12 | LL | panic!(v); | ^ @@ -421,7 +421,7 @@ LL + std::panic::panic_any(v); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:78:20 + --> $DIR/non-fmt-panic.rs:84:20 | LL | assert!(false, v); | ^ @@ -434,7 +434,7 @@ LL | assert!(false, "{:?}", v); | +++++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:82:12 + --> $DIR/non-fmt-panic.rs:88:12 | LL | panic!(v); | ^ @@ -452,7 +452,7 @@ LL + std::panic::panic_any(v); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:83:20 + --> $DIR/non-fmt-panic.rs:89:20 | LL | assert!(false, v); | ^ @@ -465,7 +465,7 @@ LL | assert!(false, "{}", v); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:87:12 + --> $DIR/non-fmt-panic.rs:93:12 | LL | panic!(v); | ^ @@ -483,7 +483,7 @@ LL + std::panic::panic_any(v); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:88:20 + --> $DIR/non-fmt-panic.rs:94:20 | LL | assert!(false, v); | ^ diff --git a/tests/ui/no-link-unknown-crate.rs b/tests/ui/no-link-unknown-crate.rs deleted file mode 100644 index c7da2e41832f..000000000000 --- a/tests/ui/no-link-unknown-crate.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[no_link] -extern crate doesnt_exist; //~ ERROR can't find crate - -fn main() {} diff --git a/tests/ui/auxiliary/issue-24106.rs b/tests/ui/pattern/auxiliary/cross-crate-enum-pattern.rs similarity index 100% rename from tests/ui/auxiliary/issue-24106.rs rename to tests/ui/pattern/auxiliary/cross-crate-enum-pattern.rs diff --git a/tests/ui/pattern/cross-crate-enum-pattern.rs b/tests/ui/pattern/cross-crate-enum-pattern.rs new file mode 100644 index 000000000000..254caf99277c --- /dev/null +++ b/tests/ui/pattern/cross-crate-enum-pattern.rs @@ -0,0 +1,13 @@ +//! Test that we can match on enum constants across crates. +//! +//! Regression test for . + + +//@ run-pass +//@ aux-build:cross-crate-enum-pattern.rs + +extern crate cross_crate_enum_pattern; + +fn main() { + cross_crate_enum_pattern::go::<()>(); +} diff --git a/tests/ui/auxiliary/impl_privacy_xc_1.rs b/tests/ui/privacy/auxiliary/impl-privacy-cross-crate-1.rs similarity index 100% rename from tests/ui/auxiliary/impl_privacy_xc_1.rs rename to tests/ui/privacy/auxiliary/impl-privacy-cross-crate-1.rs diff --git a/tests/ui/privacy/auxiliary/impl_privacy_xc_2.rs b/tests/ui/privacy/auxiliary/impl-privacy-cross-crate-2.rs similarity index 100% rename from tests/ui/privacy/auxiliary/impl_privacy_xc_2.rs rename to tests/ui/privacy/auxiliary/impl-privacy-cross-crate-2.rs diff --git a/tests/ui/privacy/impl-privacy-cross-crate-1.rs b/tests/ui/privacy/impl-privacy-cross-crate-1.rs new file mode 100644 index 000000000000..6b2ef3ccc781 --- /dev/null +++ b/tests/ui/privacy/impl-privacy-cross-crate-1.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ aux-build:impl-privacy-cross-crate-1.rs + + +extern crate impl_privacy_cross_crate_1; + +pub fn main() { + let fish = impl_privacy_cross_crate_1::Fish { x: 1 }; + fish.swim(); +} diff --git a/tests/ui/privacy/impl-privacy-cross-crate-2.rs b/tests/ui/privacy/impl-privacy-cross-crate-2.rs new file mode 100644 index 000000000000..fa07e6e8ccea --- /dev/null +++ b/tests/ui/privacy/impl-privacy-cross-crate-2.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ aux-build:impl-privacy-cross-crate-2.rs + +extern crate impl_privacy_cross_crate_2; + +pub fn main() { + let fish1 = impl_privacy_cross_crate_2::Fish { x: 1 }; + let fish2 = impl_privacy_cross_crate_2::Fish { x: 2 }; + if fish1.eq(&fish2) { println!("yes") } else { println!("no") }; +} diff --git a/tests/ui/privacy/impl-privacy-xc-2.rs b/tests/ui/privacy/impl-privacy-xc-2.rs deleted file mode 100644 index da345ba20720..000000000000 --- a/tests/ui/privacy/impl-privacy-xc-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ aux-build:impl_privacy_xc_2.rs - -extern crate impl_privacy_xc_2; - -pub fn main() { - let fish1 = impl_privacy_xc_2::Fish { x: 1 }; - let fish2 = impl_privacy_xc_2::Fish { x: 2 }; - if fish1.eq(&fish2) { println!("yes") } else { println!("no") }; -} diff --git a/tests/ui/statics/auxiliary/inner_static.rs b/tests/ui/statics/auxiliary/inner_static.rs new file mode 100644 index 000000000000..1c62046438fc --- /dev/null +++ b/tests/ui/statics/auxiliary/inner_static.rs @@ -0,0 +1,67 @@ +//! Test for inner statics with the same name. +//! +//! Before, the path name for all items defined in methods of traits and impls never +//! took into account the name of the method. This meant that if you had two statics +//! of the same name in two different methods the statics would end up having the +//! same symbol named (even after mangling) because the path components leading to +//! the symbol were exactly the same (just __extensions__ and the static name). +//! +//! It turns out that if you add the symbol "A" twice to LLVM, it automatically +//! makes the second one "A1" instead of "A". What this meant is that in local crate +//! compilations we never found this bug. Even across crates, this was never a +//! problem. The problem arises when you have generic methods that don't get +//! generated at compile-time of a library. If the statics were re-added to LLVM by +//! a client crate of a library in a different order, you would reference different +//! constants (the integer suffixes wouldn't be guaranteed to be the same). + +pub struct A { pub v: T } +pub struct B { pub v: T } + +pub mod test { + pub struct A { pub v: T } + + impl A { + pub fn foo(&self) -> isize { + static a: isize = 5; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 6; + return a; + } + } +} + +impl A { + pub fn foo(&self) -> isize { + static a: isize = 1; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 2; + return a; + } +} + +impl B { + pub fn foo(&self) -> isize { + static a: isize = 3; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 4; + return a; + } +} + +pub fn foo() -> isize { + let a = A { v: () }; + let b = B { v: () }; + let c = test::A { v: () }; + return a.foo() + a.bar() + + b.foo() + b.bar() + + c.foo() + c.bar(); +} diff --git a/tests/ui/statics/inner-static.rs b/tests/ui/statics/inner-static.rs new file mode 100644 index 000000000000..1916435c46a1 --- /dev/null +++ b/tests/ui/statics/inner-static.rs @@ -0,0 +1,30 @@ +//! Test for inner statics with the same name. +//! +//! Before, the path name for all items defined in methods of traits and impls never +//! took into account the name of the method. This meant that if you had two statics +//! of the same name in two different methods the statics would end up having the +//! same symbol named (even after mangling) because the path components leading to +//! the symbol were exactly the same (just __extensions__ and the static name). +//! +//! It turns out that if you add the symbol "A" twice to LLVM, it automatically +//! makes the second one "A1" instead of "A". What this meant is that in local crate +//! compilations we never found this bug. Even across crates, this was never a +//! problem. The problem arises when you have generic methods that don't get +//! generated at compile-time of a library. If the statics were re-added to LLVM by +//! a client crate of a library in a different order, you would reference different +//! constants (the integer suffixes wouldn't be guaranteed to be the same). + +//@ run-pass +//@ aux-build:inner_static.rs + + +extern crate inner_static; + +pub fn main() { + let a = inner_static::A::<()> { v: () }; + let b = inner_static::B::<()> { v: () }; + let c = inner_static::test::A::<()> { v: () }; + assert_eq!(a.bar(), 2); + assert_eq!(b.bar(), 4); + assert_eq!(c.bar(), 6); +} From 5cbb27ff90b6685a27492dc2b1a23074e6194f9a Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sat, 3 May 2025 16:29:22 +0000 Subject: [PATCH 200/302] Suggest `retain_mut` over `retain` as `Vec::extract_if` alternative --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 65a83cb98ba6..72279e12192b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3659,9 +3659,9 @@ impl Vec { /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. - /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// Use [`retain_mut`] with a negated predicate if you do not need the returned iterator. /// - /// [`retain`]: Vec::retain + /// [`retain_mut`]: Vec::retain_mut /// /// Using this method is equivalent to the following code: /// From 9aee0aa453a83f8bee6dc32037e0389f3a9188fe Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 3 May 2025 19:10:43 +0200 Subject: [PATCH 201/302] allow `#[rustfmt::skip]` in combination with `#[naked]` --- compiler/rustc_passes/src/check_attr.rs | 4 +++- tests/ui/asm/naked-functions.rs | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f04b167889f1..e5b20901c0c2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -683,7 +683,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if !other_attr.has_any_name(ALLOW_LIST) { + if !other_attr.has_any_name(ALLOW_LIST) + && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) + { let path = other_attr.path(); let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); let other_attr_name = path.join("::"); diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index cb5fde9a80b8..a6f41698b411 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -231,3 +231,9 @@ pub extern "C" fn compatible_linkage() { pub extern "C" fn rustc_std_internal_symbol() { naked_asm!("", options(raw)); } + +#[rustfmt::skip] +#[unsafe(naked)] +pub extern "C" fn rustfmt_skip() { + naked_asm!("", options(raw)); +} From 00d3fdce7cb36a8c3fa090f797bdd093665cbe93 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 3 May 2025 09:57:20 -0700 Subject: [PATCH 202/302] Allow linking rustc and rustdoc against the same single tracing crate By consecutively initializing `tracing` and `rustc_log`, Rustdoc assumes that these involve 2 different tracing crates. I would like to be able to build rustdoc against the same tracing crate that rustc_log is also built against. Previously this arrangement would crash rustdoc: thread 'main' panicked at rust/compiler/rustc_log/src/lib.rs:142:65: called `Result::unwrap()` on an `Err` value: SetGlobalDefaultError("a global default trace dispatcher has already been set") stack backtrace: 0: rust_begin_unwind 1: core::panicking::panic_fmt 2: core::result::unwrap_failed 3: rustc_log::init_logger 4: rustc_driver_impl::init_logger 5: rustdoc::main note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md note: please make sure that you have updated to the latest nightly query stack during panic: end of query stack --- compiler/rustc_log/src/lib.rs | 13 +++++++++++-- src/librustdoc/lib.rs | 26 +++++++++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 49dd388f14cc..1bb502ca3d06 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -37,6 +37,7 @@ use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io::{self, IsTerminal}; +use tracing::dispatcher::SetGlobalDefaultError; use tracing_core::{Event, Subscriber}; use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; use tracing_subscriber::fmt::FmtContext; @@ -131,10 +132,10 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { .without_time() .event_format(BacktraceFormatter { backtrace_target }); let subscriber = subscriber.with(fmt_layer); - tracing::subscriber::set_global_default(subscriber).unwrap(); + tracing::subscriber::set_global_default(subscriber)?; } Err(_) => { - tracing::subscriber::set_global_default(subscriber).unwrap(); + tracing::subscriber::set_global_default(subscriber)?; } }; @@ -180,6 +181,7 @@ pub enum Error { InvalidColorValue(String), NonUnicodeColorValue, InvalidWraptree(String), + AlreadyInit(SetGlobalDefaultError), } impl std::error::Error for Error {} @@ -199,6 +201,13 @@ impl Display for Error { formatter, "invalid log WRAPTREE value '{value}': expected a non-negative integer", ), + Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter), } } } + +impl From for Error { + fn from(tracing_error: SetGlobalDefaultError) -> Self { + Error::AlreadyInit(tracing_error) + } +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 44bd96a7e450..bca40b8117bd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -170,12 +170,28 @@ pub fn main() { // NOTE: this compiles both versions of tracing unconditionally, because // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled - // NOTE: The reason this doesn't show double logging when `download-rustc = false` and - // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one - // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). - init_logging(&early_dcx); - rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")); + crate::init_logging(&early_dcx); + match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) { + Ok(()) => {} + // With `download-rustc = true` there are definitely 2 distinct tracing crates in the + // dependency graph: one in the downloaded sysroot and one built just now as a dependency of + // rustdoc. So the sysroot's tracing is definitely not yet initialized here. + // + // But otherwise, depending on link style, there may or may not be 2 tracing crates in play. + // The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency + // on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's + // tracing dependency is distinct from this one and also needs to be initialized (using the + // same RUSTDOC_LOG environment variable for both). Other build systems may use just a + // single tracing crate throughout the rustc and rustdoc build. + // + // The reason initializing 2 tracings does not show double logging when `download-rustc = + // false` and `debug_logging = true` is because all rustc logging goes only to its version + // of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version + // (the one in Cargo.toml). + Err(rustc_log::Error::AlreadyInit(_)) => {} + Err(error) => early_dcx.early_fatal(error.to_string()), + } let exit_code = rustc_driver::catch_with_exit_code(|| { let at_args = rustc_driver::args::raw_args(&early_dcx); From 879b12e2ce3dc14ca2bc40ac1311e8f2bac19048 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 3 May 2025 14:10:58 +0300 Subject: [PATCH 203/302] compiletest: Do not require annotations on empty labels and suggestions --- src/tools/compiletest/src/json.rs | 23 +-- tests/incremental/circular-dependencies.rs | 1 - .../const_in_pattern/reject_non_structural.rs | 1 - .../reject_non_structural.stderr | 8 +- tests/ui/fn/param-mismatch-foreign.rs | 1 - tests/ui/fn/param-mismatch-foreign.stderr | 2 +- ...signature-error-reporting-under-verbose.rs | 1 - ...ature-error-reporting-under-verbose.stderr | 2 +- tests/ui/issues/issue-48131.rs | 4 +- tests/ui/issues/issue-48131.stderr | 2 +- .../dont-point-return-on-E0308.rs | 1 - .../dont-point-return-on-E0308.stderr | 2 +- .../similar_paths_primitive.rs | 3 +- .../similar_paths_primitive.stderr | 6 +- .../numeric-suffix/numeric-suffix-i32.fixed | 11 -- .../numeric-suffix/numeric-suffix-i32.rs | 11 -- .../numeric-suffix/numeric-suffix-i32.stderr | 22 +-- .../numeric-suffix/numeric-suffix-i64.fixed | 11 -- .../numeric-suffix/numeric-suffix-i64.rs | 11 -- .../numeric-suffix/numeric-suffix-i64.stderr | 22 +-- .../numeric-suffix/numeric-suffix-isize.fixed | 11 -- .../numeric-suffix/numeric-suffix-isize.rs | 11 -- .../numeric-suffix-isize.stderr | 22 +-- .../numeric-suffix/numeric-suffix-u32.fixed | 11 -- .../numeric-suffix/numeric-suffix-u32.rs | 11 -- .../numeric-suffix/numeric-suffix-u32.stderr | 22 +-- .../numeric-suffix/numeric-suffix-u64.fixed | 11 -- .../numeric-suffix/numeric-suffix-u64.rs | 11 -- .../numeric-suffix/numeric-suffix-u64.stderr | 22 +-- .../numeric-suffix/numeric-suffix-usize.fixed | 11 -- .../numeric-suffix/numeric-suffix-usize.rs | 11 -- .../numeric-suffix-usize.stderr | 22 +-- .../numeric-suffix/numeric-suffix.fixed | 69 --------- .../numeric/numeric-suffix/numeric-suffix.rs | 69 --------- .../numeric-suffix/numeric-suffix.stderr | 136 +++++++++--------- tests/ui/parser/fn-arg-doc-comment.rs | 3 - tests/ui/parser/fn-arg-doc-comment.stderr | 10 +- .../const-async-const.rs | 1 - .../several-kw-jump.rs | 1 - .../issue-78123-non-exhaustive-reference.rs | 1 - ...ssue-78123-non-exhaustive-reference.stderr | 2 +- .../type/type-check/point-at-inference-4.rs | 1 - .../type-check/point-at-inference-4.stderr | 4 +- 43 files changed, 168 insertions(+), 450 deletions(-) diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 960f5ba58882..151ac345125e 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -181,8 +181,6 @@ fn push_actual_errors( .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name)) .collect(); - let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect(); - let primary_spans: Vec<_> = spans_info_in_this_file .iter() .filter(|(is_primary, _)| *is_primary) @@ -280,7 +278,9 @@ fn push_actual_errors( line_num: Some(span.line_start + index), kind: ErrorKind::Suggestion, msg: line.to_string(), - require_annotation: true, + // Empty suggestions (suggestions to remove something) are common + // and annotating them in source is not useful. + require_annotation: !line.is_empty(), }); } } @@ -294,13 +294,16 @@ fn push_actual_errors( } // Add notes for any labels that appear in the message. - for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { - errors.push(Error { - line_num: Some(span.line_start), - kind: ErrorKind::Note, - msg: span.label.clone().unwrap(), - require_annotation: true, - }); + for (_, span) in spans_info_in_this_file { + if let Some(label) = &span.label { + errors.push(Error { + line_num: Some(span.line_start), + kind: ErrorKind::Note, + msg: label.clone(), + // Empty labels (only underlining spans) are common and do not need annotations. + require_annotation: !label.is_empty(), + }); + } } // Flatten out the children. diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs index bd3b109b62c7..c7b5b931fbbe 100644 --- a/tests/incremental/circular-dependencies.rs +++ b/tests/incremental/circular-dependencies.rs @@ -15,7 +15,6 @@ pub struct Foo; pub fn consume_foo(_: Foo) {} //[cfail2]~^ NOTE function defined here -//[cfail2]~| NOTE pub fn produce_foo() -> Foo { Foo diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index 6478bf9c6ee1..39e5f732a898 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -93,7 +93,6 @@ fn main() { //~| NOTE constant of non-structural type trait Trait: Sized { const ASSOC: Option; } //~ NOTE constant defined here - //~^ NOTE impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR constant of non-structural type `NoDerive` in a pattern diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index bf54d3d76aed..fa16d0b06a7f 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -118,14 +118,14 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:98:28 + --> $DIR/reject_non_structural.rs:97:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns ... LL | trait Trait: Sized { const ASSOC: Option; } | ------------------ ------------------------- constant defined here -... +LL | impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ constant of non-structural type | @@ -136,7 +136,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:103:28 + --> $DIR/reject_non_structural.rs:102:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns @@ -153,7 +153,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:108:29 + --> $DIR/reject_non_structural.rs:107:29 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs index eebca29d6c93..2ab2bf95448a 100644 --- a/tests/ui/fn/param-mismatch-foreign.rs +++ b/tests/ui/fn/param-mismatch-foreign.rs @@ -1,7 +1,6 @@ extern "C" { fn foo(x: i32, y: u32, z: i32); //~^ NOTE function defined here - //~| NOTE } fn main() { diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr index fff3283cbb6c..835e0a3343e9 100644 --- a/tests/ui/fn/param-mismatch-foreign.stderr +++ b/tests/ui/fn/param-mismatch-foreign.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied - --> $DIR/param-mismatch-foreign.rs:8:5 + --> $DIR/param-mismatch-foreign.rs:7:5 | LL | foo(1i32, 2i32); | ^^^ ---- argument #2 of type `u32` is missing diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.rs b/tests/ui/fn/signature-error-reporting-under-verbose.rs index 4a72da789789..0047d452b7a6 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.rs +++ b/tests/ui/fn/signature-error-reporting-under-verbose.rs @@ -4,7 +4,6 @@ fn foo(_: i32, _: i32) {} fn needs_ptr(_: fn(i32, u32)) {} //~^ NOTE function defined here -//~| NOTE fn main() { needs_ptr(foo); diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.stderr b/tests/ui/fn/signature-error-reporting-under-verbose.stderr index 6c6a313c4df7..d9ccec23fcb6 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.stderr +++ b/tests/ui/fn/signature-error-reporting-under-verbose.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/signature-error-reporting-under-verbose.rs:10:15 + --> $DIR/signature-error-reporting-under-verbose.rs:9:15 | LL | needs_ptr(foo); | --------- ^^^ expected fn pointer, found fn item diff --git a/tests/ui/issues/issue-48131.rs b/tests/ui/issues/issue-48131.rs index 85664e62eade..a1084ea243b2 100644 --- a/tests/ui/issues/issue-48131.rs +++ b/tests/ui/issues/issue-48131.rs @@ -1,13 +1,12 @@ // This note is annotated because the purpose of the test // is to ensure that certain other notes are not generated. -#![deny(unused_unsafe)] //~ NOTE +#![deny(unused_unsafe)] // (test that no note is generated on this unsafe fn) pub unsafe fn a() { fn inner() { unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` - //~^ NOTE } inner() @@ -18,7 +17,6 @@ pub fn b() { unsafe { fn inner() { unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` - //~^ NOTE } // `()` is fine to zero-initialize as it is zero sized and inhabited. let () = ::std::mem::zeroed(); diff --git a/tests/ui/issues/issue-48131.stderr b/tests/ui/issues/issue-48131.stderr index 5acc4f16e9fc..fe0cd4efae89 100644 --- a/tests/ui/issues/issue-48131.stderr +++ b/tests/ui/issues/issue-48131.stderr @@ -11,7 +11,7 @@ LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/issue-48131.rs:20:13 + --> $DIR/issue-48131.rs:19:13 | LL | unsafe { /* unnecessary */ } | ^^^^^^ unnecessary `unsafe` block diff --git a/tests/ui/mismatched_types/dont-point-return-on-E0308.rs b/tests/ui/mismatched_types/dont-point-return-on-E0308.rs index dca917e3ba1e..750329d29c00 100644 --- a/tests/ui/mismatched_types/dont-point-return-on-E0308.rs +++ b/tests/ui/mismatched_types/dont-point-return-on-E0308.rs @@ -2,7 +2,6 @@ async fn f(_: &()) {} //~^ NOTE function defined here -//~| NOTE // Second note is the span of the underlined argument, I think... fn main() { diff --git a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr index 9d4852cff8c6..105dc5c2e798 100644 --- a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr +++ b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/dont-point-return-on-E0308.rs:11:11 + --> $DIR/dont-point-return-on-E0308.rs:10:11 | LL | f(()); | - ^^ expected `&()`, found `()` diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs index b20ca80ac071..a58fe68b8638 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.rs +++ b/tests/ui/mismatched_types/similar_paths_primitive.rs @@ -4,9 +4,8 @@ struct bool; //~ NOTE the other `bool` is defined in the current crate struct str; //~ NOTE the other `str` is defined in the current crate fn foo(_: bool) {} //~ NOTE function defined here - //~^ NOTE fn bar(_: &str) {} //~ NOTE function defined here - //~^ NOTE + fn main() { foo(true); //~^ ERROR mismatched types [E0308] diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr index 9c1aa0d7105b..cf26234dba85 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.stderr +++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:11:9 + --> $DIR/similar_paths_primitive.rs:10:9 | LL | foo(true); | --- ^^^^ expected `bool`, found a different `bool` @@ -20,7 +20,7 @@ LL | fn foo(_: bool) {} | ^^^ ------- error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:17:9 + --> $DIR/similar_paths_primitive.rs:16:9 | LL | bar("hello"); | --- ^^^^^^^ expected `str`, found a different `str` @@ -35,7 +35,7 @@ note: the other `str` is defined in the current crate LL | struct str; | ^^^^^^^^^^ note: function defined here - --> $DIR/similar_paths_primitive.rs:8:4 + --> $DIR/similar_paths_primitive.rs:7:4 | LL | fn bar(_: &str) {} | ^^^ ------- diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed index e3b613cc3f64..9f891afc313a 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_i32); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs index 3b384e763107..a735fade86ed 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr index 6c6b8b51c226..b3450b41d38c 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:28:16 + --> $DIR/numeric-suffix-i32.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i32`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:32:16 + --> $DIR/numeric-suffix-i32.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i32`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:36:16 + --> $DIR/numeric-suffix-i32.rs:25:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i32`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:40:16 + --> $DIR/numeric-suffix-i32.rs:29:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i32`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:44:16 + --> $DIR/numeric-suffix-i32.rs:33:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i32`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:48:16 + --> $DIR/numeric-suffix-i32.rs:37:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i32`, found `isize` @@ -113,7 +113,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:52:16 + --> $DIR/numeric-suffix-i32.rs:41:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `i32`, found `i64` @@ -132,7 +132,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:57:16 + --> $DIR/numeric-suffix-i32.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `i32`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:61:16 + --> $DIR/numeric-suffix-i32.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i32`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:65:16 + --> $DIR/numeric-suffix-i32.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i32`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:69:16 + --> $DIR/numeric-suffix-i32.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i32`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed index 0fcda6c1f806..6d1c585a5639 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_i64); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs index 9c912bc38dad..fd4862be3873 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr index 7c26dd7be1c6..63326f49a8f0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:28:16 + --> $DIR/numeric-suffix-i64.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i64`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:32:16 + --> $DIR/numeric-suffix-i64.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i64`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:36:16 + --> $DIR/numeric-suffix-i64.rs:25:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i64`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:40:16 + --> $DIR/numeric-suffix-i64.rs:29:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i64`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:44:16 + --> $DIR/numeric-suffix-i64.rs:33:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i64`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:48:16 + --> $DIR/numeric-suffix-i64.rs:37:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i64`, found `isize` @@ -113,7 +113,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:53:16 + --> $DIR/numeric-suffix-i64.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `i64`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:57:16 + --> $DIR/numeric-suffix-i64.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `i64`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:61:16 + --> $DIR/numeric-suffix-i64.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i64`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:65:16 + --> $DIR/numeric-suffix-i64.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i64`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:69:16 + --> $DIR/numeric-suffix-i64.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i64`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed index 23e7cf780e9a..f24fce3f1d67 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_isize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs index 5d6fd4d932ac..fdf86895ff23 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr index 8365350f2bfe..99561b19021a 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:28:18 + --> $DIR/numeric-suffix-isize.rs:17:18 | LL | foo::(42_usize); | ------------ ^^^^^^^^ expected `isize`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:32:18 + --> $DIR/numeric-suffix-isize.rs:21:18 | LL | foo::(42_u64); | ------------ ^^^^^^ expected `isize`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:36:18 + --> $DIR/numeric-suffix-isize.rs:25:18 | LL | foo::(42_u32); | ------------ ^^^^^^ expected `isize`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:40:18 + --> $DIR/numeric-suffix-isize.rs:29:18 | LL | foo::(42_u16); | ------------ ^^^^^^ expected `isize`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:44:18 + --> $DIR/numeric-suffix-isize.rs:33:18 | LL | foo::(42_u8); | ------------ ^^^^^ expected `isize`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:49:18 + --> $DIR/numeric-suffix-isize.rs:38:18 | LL | foo::(42_i64); | ------------ ^^^^^^ expected `isize`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:53:18 + --> $DIR/numeric-suffix-isize.rs:42:18 | LL | foo::(42_i32); | ------------ ^^^^^^ expected `isize`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:57:18 + --> $DIR/numeric-suffix-isize.rs:46:18 | LL | foo::(42_i16); | ------------ ^^^^^^ expected `isize`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:61:18 + --> $DIR/numeric-suffix-isize.rs:50:18 | LL | foo::(42_i8); | ------------ ^^^^^ expected `isize`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:65:18 + --> $DIR/numeric-suffix-isize.rs:54:18 | LL | foo::(42.0_f64); | ------------ ^^^^^^^^ expected `isize`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:69:18 + --> $DIR/numeric-suffix-isize.rs:58:18 | LL | foo::(42.0_f32); | ------------ ^^^^^^^^ expected `isize`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed index 2dd7d9aabdb5..eba5d7c1c266 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_u32); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs index 46bbb0331854..d127353e9754 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr index 610e6ece2769..95e913595e5e 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:28:16 + --> $DIR/numeric-suffix-u32.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u32`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:32:16 + --> $DIR/numeric-suffix-u32.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `u32`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:37:16 + --> $DIR/numeric-suffix-u32.rs:26:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `u32`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:41:16 + --> $DIR/numeric-suffix-u32.rs:30:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u32`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:45:16 + --> $DIR/numeric-suffix-u32.rs:34:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u32`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:49:16 + --> $DIR/numeric-suffix-u32.rs:38:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u32`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:53:16 + --> $DIR/numeric-suffix-u32.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u32`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:57:16 + --> $DIR/numeric-suffix-u32.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u32`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:61:16 + --> $DIR/numeric-suffix-u32.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u32`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:65:16 + --> $DIR/numeric-suffix-u32.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u32`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:69:16 + --> $DIR/numeric-suffix-u32.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u32`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed index 2dea195f0981..c8344211d3d0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_u64); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs index 6fca089b07d4..f9b35efbc4be 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr index 112dddccd6f4..0c92b4137614 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:28:16 + --> $DIR/numeric-suffix-u64.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u64`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:33:16 + --> $DIR/numeric-suffix-u64.rs:22:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `u64`, found `u32` @@ -37,7 +37,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:37:16 + --> $DIR/numeric-suffix-u64.rs:26:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `u64`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:41:16 + --> $DIR/numeric-suffix-u64.rs:30:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u64`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:45:16 + --> $DIR/numeric-suffix-u64.rs:34:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u64`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:49:16 + --> $DIR/numeric-suffix-u64.rs:38:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u64`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:53:16 + --> $DIR/numeric-suffix-u64.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u64`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:57:16 + --> $DIR/numeric-suffix-u64.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u64`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:61:16 + --> $DIR/numeric-suffix-u64.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u64`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:65:16 + --> $DIR/numeric-suffix-u64.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u64`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:69:16 + --> $DIR/numeric-suffix-u64.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u64`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed index 63422c305d35..4d5176fe7245 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs index 4d20e4fc8431..118d8ca219ec 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr index e7d6a04f18ef..86181d6714f5 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:29:18 + --> $DIR/numeric-suffix-usize.rs:18:18 | LL | foo::(42_u64); | ------------ ^^^^^^ expected `usize`, found `u64` @@ -18,7 +18,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:33:18 + --> $DIR/numeric-suffix-usize.rs:22:18 | LL | foo::(42_u32); | ------------ ^^^^^^ expected `usize`, found `u32` @@ -37,7 +37,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:37:18 + --> $DIR/numeric-suffix-usize.rs:26:18 | LL | foo::(42_u16); | ------------ ^^^^^^ expected `usize`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:41:18 + --> $DIR/numeric-suffix-usize.rs:30:18 | LL | foo::(42_u8); | ------------ ^^^^^ expected `usize`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:45:18 + --> $DIR/numeric-suffix-usize.rs:34:18 | LL | foo::(42_isize); | ------------ ^^^^^^^^ expected `usize`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:49:18 + --> $DIR/numeric-suffix-usize.rs:38:18 | LL | foo::(42_i64); | ------------ ^^^^^^ expected `usize`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:53:18 + --> $DIR/numeric-suffix-usize.rs:42:18 | LL | foo::(42_i32); | ------------ ^^^^^^ expected `usize`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:57:18 + --> $DIR/numeric-suffix-usize.rs:46:18 | LL | foo::(42_i16); | ------------ ^^^^^^ expected `usize`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:61:18 + --> $DIR/numeric-suffix-usize.rs:50:18 | LL | foo::(42_i8); | ------------ ^^^^^ expected `usize`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:65:18 + --> $DIR/numeric-suffix-usize.rs:54:18 | LL | foo::(42.0_f64); | ------------ ^^^^^^^^ expected `usize`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:69:18 + --> $DIR/numeric-suffix-usize.rs:58:18 | LL | foo::(42.0_f32); | ------------ ^^^^^^^^ expected `usize`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed index 270afb639575..b20b594dc2c3 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed @@ -69,75 +69,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE - fn main() { foo::(42_u16); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix.rs index 05be58e335bc..9272902f5190 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.rs @@ -69,75 +69,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE - fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr index d26639a76f0f..cae1268beec0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:143:16 + --> $DIR/numeric-suffix.rs:74:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u16`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:147:16 + --> $DIR/numeric-suffix.rs:78:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `u16`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:151:16 + --> $DIR/numeric-suffix.rs:82:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `u16`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:156:16 + --> $DIR/numeric-suffix.rs:87:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u16`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:160:16 + --> $DIR/numeric-suffix.rs:91:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u16`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:164:16 + --> $DIR/numeric-suffix.rs:95:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u16`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:168:16 + --> $DIR/numeric-suffix.rs:99:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u16`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:172:16 + --> $DIR/numeric-suffix.rs:103:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u16`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:176:16 + --> $DIR/numeric-suffix.rs:107:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u16`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:180:16 + --> $DIR/numeric-suffix.rs:111:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u16`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:184:16 + --> $DIR/numeric-suffix.rs:115:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u16`, found `f32` @@ -208,7 +208,7 @@ LL + foo::(42u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:189:16 + --> $DIR/numeric-suffix.rs:120:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i16`, found `usize` @@ -227,7 +227,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:193:16 + --> $DIR/numeric-suffix.rs:124:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i16`, found `u64` @@ -246,7 +246,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:197:16 + --> $DIR/numeric-suffix.rs:128:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i16`, found `u32` @@ -265,7 +265,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:201:16 + --> $DIR/numeric-suffix.rs:132:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i16`, found `u16` @@ -284,7 +284,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:205:16 + --> $DIR/numeric-suffix.rs:136:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i16`, found `u8` @@ -303,7 +303,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:209:16 + --> $DIR/numeric-suffix.rs:140:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i16`, found `isize` @@ -322,7 +322,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:213:16 + --> $DIR/numeric-suffix.rs:144:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `i16`, found `i64` @@ -341,7 +341,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:217:16 + --> $DIR/numeric-suffix.rs:148:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `i16`, found `i32` @@ -360,7 +360,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:222:16 + --> $DIR/numeric-suffix.rs:153:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i16`, found `i8` @@ -379,7 +379,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:226:16 + --> $DIR/numeric-suffix.rs:157:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i16`, found `f64` @@ -398,7 +398,7 @@ LL + foo::(42i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:230:16 + --> $DIR/numeric-suffix.rs:161:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i16`, found `f32` @@ -417,7 +417,7 @@ LL + foo::(42i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:235:15 + --> $DIR/numeric-suffix.rs:166:15 | LL | foo::(42_usize); | --------- ^^^^^^^^ expected `u8`, found `usize` @@ -436,7 +436,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:239:15 + --> $DIR/numeric-suffix.rs:170:15 | LL | foo::(42_u64); | --------- ^^^^^^ expected `u8`, found `u64` @@ -455,7 +455,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:243:15 + --> $DIR/numeric-suffix.rs:174:15 | LL | foo::(42_u32); | --------- ^^^^^^ expected `u8`, found `u32` @@ -474,7 +474,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:247:15 + --> $DIR/numeric-suffix.rs:178:15 | LL | foo::(42_u16); | --------- ^^^^^^ expected `u8`, found `u16` @@ -493,7 +493,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:252:15 + --> $DIR/numeric-suffix.rs:183:15 | LL | foo::(42_isize); | --------- ^^^^^^^^ expected `u8`, found `isize` @@ -512,7 +512,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:256:15 + --> $DIR/numeric-suffix.rs:187:15 | LL | foo::(42_i64); | --------- ^^^^^^ expected `u8`, found `i64` @@ -531,7 +531,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:260:15 + --> $DIR/numeric-suffix.rs:191:15 | LL | foo::(42_i32); | --------- ^^^^^^ expected `u8`, found `i32` @@ -550,7 +550,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:264:15 + --> $DIR/numeric-suffix.rs:195:15 | LL | foo::(42_i16); | --------- ^^^^^^ expected `u8`, found `i16` @@ -569,7 +569,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:268:15 + --> $DIR/numeric-suffix.rs:199:15 | LL | foo::(42_i8); | --------- ^^^^^ expected `u8`, found `i8` @@ -588,7 +588,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:272:15 + --> $DIR/numeric-suffix.rs:203:15 | LL | foo::(42.0_f64); | --------- ^^^^^^^^ expected `u8`, found `f64` @@ -607,7 +607,7 @@ LL + foo::(42u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:276:15 + --> $DIR/numeric-suffix.rs:207:15 | LL | foo::(42.0_f32); | --------- ^^^^^^^^ expected `u8`, found `f32` @@ -626,7 +626,7 @@ LL + foo::(42u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:281:15 + --> $DIR/numeric-suffix.rs:212:15 | LL | foo::(42_usize); | --------- ^^^^^^^^ expected `i8`, found `usize` @@ -645,7 +645,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:285:15 + --> $DIR/numeric-suffix.rs:216:15 | LL | foo::(42_u64); | --------- ^^^^^^ expected `i8`, found `u64` @@ -664,7 +664,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:289:15 + --> $DIR/numeric-suffix.rs:220:15 | LL | foo::(42_u32); | --------- ^^^^^^ expected `i8`, found `u32` @@ -683,7 +683,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:293:15 + --> $DIR/numeric-suffix.rs:224:15 | LL | foo::(42_u16); | --------- ^^^^^^ expected `i8`, found `u16` @@ -702,7 +702,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:297:15 + --> $DIR/numeric-suffix.rs:228:15 | LL | foo::(42_u8); | --------- ^^^^^ expected `i8`, found `u8` @@ -721,7 +721,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:301:15 + --> $DIR/numeric-suffix.rs:232:15 | LL | foo::(42_isize); | --------- ^^^^^^^^ expected `i8`, found `isize` @@ -740,7 +740,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:305:15 + --> $DIR/numeric-suffix.rs:236:15 | LL | foo::(42_i64); | --------- ^^^^^^ expected `i8`, found `i64` @@ -759,7 +759,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:309:15 + --> $DIR/numeric-suffix.rs:240:15 | LL | foo::(42_i32); | --------- ^^^^^^ expected `i8`, found `i32` @@ -778,7 +778,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:313:15 + --> $DIR/numeric-suffix.rs:244:15 | LL | foo::(42_i16); | --------- ^^^^^^ expected `i8`, found `i16` @@ -797,7 +797,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:318:15 + --> $DIR/numeric-suffix.rs:249:15 | LL | foo::(42.0_f64); | --------- ^^^^^^^^ expected `i8`, found `f64` @@ -816,7 +816,7 @@ LL + foo::(42i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:322:15 + --> $DIR/numeric-suffix.rs:253:15 | LL | foo::(42.0_f32); | --------- ^^^^^^^^ expected `i8`, found `f32` @@ -835,7 +835,7 @@ LL + foo::(42i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:327:16 + --> $DIR/numeric-suffix.rs:258:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `f64`, found `usize` @@ -854,7 +854,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:331:16 + --> $DIR/numeric-suffix.rs:262:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `f64`, found `u64` @@ -873,7 +873,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:335:16 + --> $DIR/numeric-suffix.rs:266:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `f64`, found `u32` @@ -891,7 +891,7 @@ LL | foo::(42_u32.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:339:16 + --> $DIR/numeric-suffix.rs:270:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `f64`, found `u16` @@ -909,7 +909,7 @@ LL | foo::(42_u16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:343:16 + --> $DIR/numeric-suffix.rs:274:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `f64`, found `u8` @@ -927,7 +927,7 @@ LL | foo::(42_u8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:347:16 + --> $DIR/numeric-suffix.rs:278:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `f64`, found `isize` @@ -946,7 +946,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:351:16 + --> $DIR/numeric-suffix.rs:282:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `f64`, found `i64` @@ -965,7 +965,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:355:16 + --> $DIR/numeric-suffix.rs:286:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `f64`, found `i32` @@ -983,7 +983,7 @@ LL | foo::(42_i32.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:359:16 + --> $DIR/numeric-suffix.rs:290:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `f64`, found `i16` @@ -1001,7 +1001,7 @@ LL | foo::(42_i16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:363:16 + --> $DIR/numeric-suffix.rs:294:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `f64`, found `i8` @@ -1019,7 +1019,7 @@ LL | foo::(42_i8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:368:16 + --> $DIR/numeric-suffix.rs:299:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `f64`, found `f32` @@ -1038,7 +1038,7 @@ LL + foo::(42.0_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:373:16 + --> $DIR/numeric-suffix.rs:304:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `f32`, found `usize` @@ -1057,7 +1057,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:377:16 + --> $DIR/numeric-suffix.rs:308:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `f32`, found `u64` @@ -1076,7 +1076,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:381:16 + --> $DIR/numeric-suffix.rs:312:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `f32`, found `u32` @@ -1095,7 +1095,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:385:16 + --> $DIR/numeric-suffix.rs:316:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `f32`, found `u16` @@ -1113,7 +1113,7 @@ LL | foo::(42_u16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:389:16 + --> $DIR/numeric-suffix.rs:320:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `f32`, found `u8` @@ -1131,7 +1131,7 @@ LL | foo::(42_u8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:393:16 + --> $DIR/numeric-suffix.rs:324:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `f32`, found `isize` @@ -1150,7 +1150,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:397:16 + --> $DIR/numeric-suffix.rs:328:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `f32`, found `i64` @@ -1169,7 +1169,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:401:16 + --> $DIR/numeric-suffix.rs:332:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `f32`, found `i32` @@ -1188,7 +1188,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:405:16 + --> $DIR/numeric-suffix.rs:336:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `f32`, found `i16` @@ -1206,7 +1206,7 @@ LL | foo::(42_i16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:409:16 + --> $DIR/numeric-suffix.rs:340:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `f32`, found `i8` @@ -1224,7 +1224,7 @@ LL | foo::(42_i8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:413:16 + --> $DIR/numeric-suffix.rs:344:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `f32`, found `f64` @@ -1243,7 +1243,7 @@ LL + foo::(42.0_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:419:16 + --> $DIR/numeric-suffix.rs:350:16 | LL | foo::(42_u8 as u16); | ---------- ^^^^^^^^^^^^ expected `u32`, found `u16` @@ -1261,7 +1261,7 @@ LL | foo::((42_u8 as u16).into()); | + ++++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:423:16 + --> $DIR/numeric-suffix.rs:354:16 | LL | foo::(-42_i8); | ---------- ^^^^^^ expected `i32`, found `i8` diff --git a/tests/ui/parser/fn-arg-doc-comment.rs b/tests/ui/parser/fn-arg-doc-comment.rs index 21d753ad0372..57a4d15fa256 100644 --- a/tests/ui/parser/fn-arg-doc-comment.rs +++ b/tests/ui/parser/fn-arg-doc-comment.rs @@ -2,12 +2,10 @@ pub fn f( //~ NOTE function defined here /// Comment //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here - //~| NOTE id: u8, /// Other //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here - //~| NOTE a: u8, ) {} @@ -15,7 +13,6 @@ fn bar(id: #[allow(dead_code)] i32) {} //~^ ERROR attributes cannot be applied to a function parameter's type //~| NOTE attributes are not allowed here //~| NOTE function defined here -//~| NOTE fn main() { // verify that the parser recovered and properly typechecked the args diff --git a/tests/ui/parser/fn-arg-doc-comment.stderr b/tests/ui/parser/fn-arg-doc-comment.stderr index 1891c7089034..84c8bb3c2d09 100644 --- a/tests/ui/parser/fn-arg-doc-comment.stderr +++ b/tests/ui/parser/fn-arg-doc-comment.stderr @@ -1,5 +1,5 @@ error: attributes cannot be applied to a function parameter's type - --> $DIR/fn-arg-doc-comment.rs:14:12 + --> $DIR/fn-arg-doc-comment.rs:12:12 | LL | fn bar(id: #[allow(dead_code)] i32) {} | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here @@ -11,13 +11,13 @@ LL | /// Comment | ^^^^^^^^^^^ doc comments are not allowed here error: documentation comments cannot be applied to function parameters - --> $DIR/fn-arg-doc-comment.rs:7:5 + --> $DIR/fn-arg-doc-comment.rs:6:5 | LL | /// Other | ^^^^^^^^^ doc comments are not allowed here error[E0308]: arguments to this function are incorrect - --> $DIR/fn-arg-doc-comment.rs:22:5 + --> $DIR/fn-arg-doc-comment.rs:19:5 | LL | f("", ""); | ^ -- -- expected `u8`, found `&str` @@ -39,7 +39,7 @@ LL | | a: u8, | |_________- error[E0308]: mismatched types - --> $DIR/fn-arg-doc-comment.rs:26:9 + --> $DIR/fn-arg-doc-comment.rs:23:9 | LL | bar(""); | --- ^^ expected `i32`, found `&str` @@ -47,7 +47,7 @@ LL | bar(""); | arguments to this function are incorrect | note: function defined here - --> $DIR/fn-arg-doc-comment.rs:14:4 + --> $DIR/fn-arg-doc-comment.rs:12:4 | LL | fn bar(id: #[allow(dead_code)] i32) {} | ^^^ --------------------------- diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index c137e1363359..e6235b1e8923 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -10,6 +10,5 @@ const async const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this -//~| NOTE fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs index 49a49d337c47..40f993eafbb1 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs @@ -15,6 +15,5 @@ async unsafe const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this -//~| NOTE fn main() {} diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs index cbfcf0eafd49..6c5a331b4b56 100644 --- a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs +++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs @@ -1,6 +1,5 @@ enum A {} //~^ NOTE `A` defined here - //~| NOTE fn f(a: &A) { match a {} diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr index c37a9a515790..67ee38eed60c 100644 --- a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr +++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `&A` is non-empty - --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11 + --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11 | LL | match a {} | ^ diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 258374f299e2..504e6aa6db08 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -3,7 +3,6 @@ struct S(Option<(A, B)>); impl S { fn infer(&self, a: A, b: B) {} //~^ NOTE method defined here - //~| NOTE } fn main() { diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index adfb0cebf26e..8630f75d1190 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -1,5 +1,5 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied - --> $DIR/point-at-inference-4.rs:11:7 + --> $DIR/point-at-inference-4.rs:10:7 | LL | s.infer(0i32); | ^^^^^------ argument #2 is missing @@ -15,7 +15,7 @@ LL | s.infer(0i32, /* b */); | +++++++++ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:18:24 + --> $DIR/point-at-inference-4.rs:17:24 | LL | s.infer(0i32); | - ---- this argument has type `i32`... From a82b7a63b7843b703d9ad41e52a215aaa2fa86ef Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Sun, 4 May 2025 01:24:39 +0700 Subject: [PATCH 204/302] Async drop source info fix for proxy-drop-coroutine - fixes crash at debug info generation --- compiler/rustc_middle/src/ty/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2f4c03f0953d..b13e33718b29 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1929,13 +1929,17 @@ impl<'tcx> TyCtxt<'tcx> { if arg_cor_ty.is_coroutine() { let span = self.def_span(def_id); let source_info = SourceInfo::outermost(span); + // Even minimal, empty coroutine has 3 states (RESERVED_VARIANTS), + // so variant_fields and variant_source_info should have 3 elements. let variant_fields: IndexVec> = iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect(); + let variant_source_info: IndexVec = + iter::repeat(source_info).take(CoroutineArgs::RESERVED_VARIANTS).collect(); let proxy_layout = CoroutineLayout { field_tys: [].into(), field_names: [].into(), variant_fields, - variant_source_info: [source_info].into(), + variant_source_info, storage_conflicts: BitMatrix::new(0, 0), }; return Some(self.arena.alloc(proxy_layout)); From 4ba683ee529ed87cc52d4983492dbf89b495ca0f Mon Sep 17 00:00:00 2001 From: Skgland Date: Sat, 3 May 2025 22:36:17 +0200 Subject: [PATCH 205/302] add a test for issue rust-lang/rust#81317 --- .../type-inference/regression-issue-81317.rs | 40 +++++++++++++++++++ .../regression-issue-81317.stderr | 17 ++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/ui/type-inference/regression-issue-81317.rs create mode 100644 tests/ui/type-inference/regression-issue-81317.stderr diff --git a/tests/ui/type-inference/regression-issue-81317.rs b/tests/ui/type-inference/regression-issue-81317.rs new file mode 100644 index 000000000000..50deb013d4b1 --- /dev/null +++ b/tests/ui/type-inference/regression-issue-81317.rs @@ -0,0 +1,40 @@ +// Regression test for #81317: type can no longer be infered as of 1.49 +//@ check-fail + +use std::ops::BitXor; + +pub struct S; + +pub trait P { + type I: Into + Into; +} + +pub fn decrypt_portion(index: T::I) { + let iv = S ^ index.into(); + //~^ ERROR type annotations needed + &iv.to_bytes_be(); +} + +impl S { + fn to_bytes_be(&self) -> &[u8] { + &[] + } +} + +impl BitXor for S { + type Output = S; + + fn bitxor(self, _rhs: Self) -> Self::Output { + S + } +} + +impl<'a> BitXor<&'a S> for S { + type Output = S; + + fn bitxor(self, _rhs: &'a S) -> Self::Output { + S + } +} + +fn main() {} diff --git a/tests/ui/type-inference/regression-issue-81317.stderr b/tests/ui/type-inference/regression-issue-81317.stderr new file mode 100644 index 000000000000..d018a2c48545 --- /dev/null +++ b/tests/ui/type-inference/regression-issue-81317.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/regression-issue-81317.rs:13:9 + | +LL | let iv = S ^ index.into(); + | ^^ +LL | +LL | &iv.to_bytes_be(); + | -- type must be known at this point + | +help: consider giving `iv` an explicit type + | +LL | let iv: /* Type */ = S ^ index.into(); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. From d0216b5386016c1cc3b2d1125c6716cfe19a218e Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 3 May 2025 03:01:24 +0000 Subject: [PATCH 206/302] `fn check_opaque_type_parameter_valid` defer error --- .../src/region_infer/opaque_types.rs | 4 +- compiler/rustc_hir_typeck/src/writeback.rs | 9 +- .../rustc_trait_selection/src/opaque_types.rs | 83 ++++++++++++------- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 550c57338d30..25cbd579ea1c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -267,13 +267,13 @@ impl<'tcx> InferCtxt<'tcx> { return Ty::new_error(self.tcx, e); } - if let Err(guar) = check_opaque_type_parameter_valid( + if let Err(err) = check_opaque_type_parameter_valid( self, opaque_type_key, instantiated_ty.span, DefiningScopeKind::MirBorrowck, ) { - return Ty::new_error(self.tcx, guar); + return Ty::new_error(self.tcx, err.report(self)); } let definition_ty = instantiated_ty diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 4a171a08ef72..8e7ce83044cd 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -555,15 +555,16 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - if let Err(guar) = check_opaque_type_parameter_valid( + if let Err(err) = check_opaque_type_parameter_valid( &self.fcx, opaque_type_key, hidden_type.span, DefiningScopeKind::HirTypeck, ) { - self.typeck_results - .concrete_opaque_types - .insert(opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, guar)); + self.typeck_results.concrete_opaque_types.insert( + opaque_type_key.def_id, + ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)), + ); } let hidden_type = hidden_type.remap_generic_params_to_declaration_params( diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index cce67b066dde..332204a0c5f0 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -13,6 +13,49 @@ use crate::errors::NonGenericOpaqueTypeParam; use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::ObligationCtxt; +pub enum InvalidOpaqueTypeArgs<'tcx> { + AlreadyReported(ErrorGuaranteed), + NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span }, + DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec, span: Span }, +} +impl From for InvalidOpaqueTypeArgs<'_> { + fn from(guar: ErrorGuaranteed) -> Self { + InvalidOpaqueTypeArgs::AlreadyReported(guar) + } +} +impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { + pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed { + let tcx = infcx.tcx; + match self { + InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar, + InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => { + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let opaque_param = opaque_generics.param_at(param_index, tcx); + let kind = opaque_param.kind.descr(); + infcx.dcx().emit_err(NonGenericOpaqueTypeParam { + arg: opaque_type_key.args[param_index], + kind, + span, + param_span: tcx.def_span(opaque_param.def_id), + }) + } + InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => { + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr(); + let spans: Vec<_> = param_indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + infcx + .dcx() + .struct_span_err(span, "non-defining opaque type use in defining scope") + .with_span_note(spans, format!("{descr} used multiple times")) + .emit() + } + } + } +} + /// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. /// /// [rustc-dev-guide chapter]: @@ -22,23 +65,19 @@ pub fn check_opaque_type_parameter_valid<'tcx>( opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, defining_scope_kind: DefiningScopeKind, -) -> Result<(), ErrorGuaranteed> { +) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> { let tcx = infcx.tcx; - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); // Avoid duplicate errors in case the opaque has already been malformed in // HIR typeck. if let DefiningScopeKind::MirBorrowck = defining_scope_kind { - if let Err(guar) = infcx + infcx .tcx .type_of_opaque_hir_typeck(opaque_type_key.def_id) .instantiate_identity() - .error_reported() - { - return Err(guar); - } + .error_reported()?; } for (i, arg) in opaque_type_key.iter_captured_args(tcx) { @@ -64,32 +103,18 @@ pub fn check_opaque_type_parameter_valid<'tcx>( } } else { // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - let kind = opaque_param.kind.descr(); - opaque_env.param_is_error(i)?; - - return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam { - arg, - kind, - span, - param_span: tcx.def_span(opaque_param.def_id), - })); + return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span }); } } - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - return Err(infcx - .dcx() - .struct_span_err(span, "non-defining opaque type use in defining scope") - .with_span_note(spans, format!("{descr} used multiple times")) - .emit()); + for (_, param_indices) in seen_params { + if param_indices.len() > 1 { + return Err(InvalidOpaqueTypeArgs::DuplicateParam { + opaque_type_key, + param_indices, + span, + }); } } From 78823fea217056f00d37943f837ccc715462b110 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 May 2025 00:25:46 +0000 Subject: [PATCH 207/302] cargo update compiler & tools dependencies: Locking 36 packages to latest compatible versions Updating addr2line v0.21.0 -> v0.24.2 Updating anyhow v1.0.97 -> v1.0.98 Updating askama v0.13.0 -> v0.13.1 (available: v0.14.0) Updating askama_derive v0.13.0 -> v0.13.1 Updating backtrace v0.3.71 -> v0.3.74 Updating blake3 v1.8.1 -> v1.8.2 Updating chrono v0.4.40 -> v0.4.41 Updating clap v4.5.36 -> v4.5.37 Updating clap_builder v4.5.36 -> v4.5.37 Updating color-eyre v0.6.3 -> v0.6.4 Updating color-spantrace v0.2.1 -> v0.2.2 Updating derive-where v1.2.7 -> v1.4.0 Updating getrandom v0.2.15 -> v0.2.16 Removing gimli v0.28.1 Updating hashbrown v0.15.2 -> v0.15.3 Updating jiff v0.2.6 -> v0.2.12 Updating jiff-static v0.2.6 -> v0.2.12 Updating libm v0.2.11 -> v0.2.13 Removing object v0.32.2 Updating openssl-sys v0.9.107 -> v0.9.108 Adding owo-colors v4.2.0 Updating proc-macro2 v1.0.94 -> v1.0.95 Updating psm v0.1.25 -> v0.1.26 Updating rand v0.9.0 -> v0.9.1 Updating redox_syscall v0.5.11 -> v0.5.12 Updating rustix v1.0.5 -> v1.0.7 Updating sha2 v0.10.8 -> v0.10.9 Updating stacker v0.1.20 -> v0.1.21 Updating syn v2.0.100 -> v2.0.101 Updating synstructure v0.13.1 -> v0.13.2 Updating toml_datetime v0.6.8 -> v0.6.9 Adding windows v0.61.1 Adding windows-collections v0.2.0 Adding windows-future v0.2.0 Adding windows-numerics v0.2.0 Updating winnow v0.7.6 -> v0.7.9 Updating zerocopy v0.8.24 -> v0.8.25 Updating zerocopy-derive v0.8.24 -> v0.8.25 note: pass `--verbose` to see 33 unchanged dependencies behind latest library dependencies: Locking 2 packages to latest compatible versions Removing allocator-api2 v0.2.21 Updating hashbrown v0.15.2 -> v0.15.3 Removing proc-macro2 v1.0.94 Removing quote v1.0.40 Updating rand v0.9.0 -> v0.9.1 Removing syn v2.0.100 Removing unicode-ident v1.0.18 Removing zerocopy v0.8.24 Removing zerocopy-derive v0.8.24 note: pass `--verbose` to see 3 unchanged dependencies behind latest rustbook dependencies: Locking 31 packages to latest compatible versions Updating ammonia v4.0.0 -> v4.1.0 Updating anyhow v1.0.97 -> v1.0.98 Updating cc v1.2.19 -> v1.2.21 Updating chrono v0.4.40 -> v0.4.41 Updating clap v4.5.36 -> v4.5.37 Updating clap_builder v4.5.36 -> v4.5.37 Updating clap_complete v4.5.47 -> v4.5.48 Adding cssparser v0.35.0 Adding cssparser-macros v0.6.1 Adding dtoa v1.0.10 Adding dtoa-short v0.3.5 Updating hashbrown v0.15.2 -> v0.15.3 Updating html5ever v0.27.0 -> v0.31.0 Updating jiff v0.2.6 -> v0.2.12 Updating jiff-static v0.2.6 -> v0.2.12 Updating libc v0.2.171 -> v0.2.172 Updating markup5ever v0.12.1 -> v0.16.1 Adding match_token v0.1.0 Adding phf_macros v0.11.3 Updating proc-macro2 v1.0.94 -> v1.0.95 Updating redox_syscall v0.5.11 -> v0.5.12 Updating rustix v1.0.5 -> v1.0.7 Updating sha2 v0.10.8 -> v0.10.9 Updating syn v2.0.100 -> v2.0.101 Updating synstructure v0.13.1 -> v0.13.2 Updating toml v0.8.20 -> v0.8.22 Updating toml_datetime v0.6.8 -> v0.6.9 Updating toml_edit v0.22.24 -> v0.22.26 Adding toml_write v0.1.1 Adding web_atoms v0.1.1 Updating winnow v0.7.6 -> v0.7.9 --- Cargo.lock | 324 +++++++++++++++++++--------------- library/Cargo.lock | 71 +------- src/tools/rustbook/Cargo.lock | 187 ++++++++++++++------ 3 files changed, 314 insertions(+), 268 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4097c0cc0a91..967da170476e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,11 +4,11 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.28.1", + "gimli", ] [[package]] @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "ar_archive_writer" @@ -168,7 +168,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ - "object 0.36.7", + "object", ] [[package]] @@ -185,9 +185,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" dependencies = [ "askama_derive", "itoa", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" dependencies = [ "askama_parser", "basic-toml", @@ -210,7 +210,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -222,7 +222,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.6", + "winnow 0.7.9", ] [[package]] @@ -233,17 +233,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", - "object 0.32.2", + "miniz_oxide 0.8.8", + "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -278,9 +278,9 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake3" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec", @@ -449,9 +449,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -493,9 +493,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -513,9 +513,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -532,7 +532,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -564,7 +564,7 @@ dependencies = [ "rustc_tools_util 0.4.2", "serde", "serde_json", - "syn 2.0.100", + "syn 2.0.101", "tempfile", "termize", "tokio", @@ -650,16 +650,16 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors", + "owo-colors 4.2.0", "tracing-error", ] @@ -681,17 +681,17 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" dependencies = [ "once_cell", - "owo-colors", + "owo-colors 4.2.0", "tracing-core", "tracing-error", ] @@ -744,7 +744,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows", + "windows 0.59.0", ] [[package]] @@ -907,7 +907,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -918,7 +918,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -940,13 +940,13 @@ dependencies = [ [[package]] name = "derive-where" -version = "1.2.7" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -967,7 +967,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -977,7 +977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -989,7 +989,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1079,7 +1079,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1358,7 +1358,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1431,9 +1431,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1452,12 +1452,6 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "gimli" version = "0.31.1" @@ -1499,9 +1493,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1758,7 +1752,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1916,9 +1910,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" dependencies = [ "jiff-static", "log", @@ -1929,13 +1923,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2073,9 +2067,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -2199,7 +2193,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2304,7 +2298,7 @@ dependencies = [ "libffi", "libloading", "measureme", - "rand 0.9.0", + "rand 0.9.1", "regex", "rustc_version", "smallvec", @@ -2482,15 +2476,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.36.7" @@ -2541,9 +2526,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", @@ -2593,6 +2578,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + [[package]] name = "pad" version = "0.1.6" @@ -2697,7 +2688,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2814,7 +2805,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors", + "owo-colors 3.5.0", "pad", ] @@ -2826,18 +2817,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" dependencies = [ "cc", ] @@ -2911,13 +2902,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy", ] [[package]] @@ -2946,7 +2936,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2989,9 +2979,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] @@ -3002,7 +2992,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -3013,7 +3003,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -3099,9 +3089,9 @@ version = "0.2.0" dependencies = [ "bstr", "build_helper", - "gimli 0.31.1", + "gimli", "libc", - "object 0.36.7", + "object", "regex", "serde_json", "similar", @@ -3195,7 +3185,7 @@ name = "rustc_abi" version = "0.0.0" dependencies = [ "bitflags", - "rand 0.9.0", + "rand 0.9.1", "rand_xoshiro", "rustc_data_structures", "rustc_hashes", @@ -3408,11 +3398,11 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags", - "gimli 0.31.1", + "gimli", "itertools", "libc", "measureme", - "object 0.36.7", + "object", "rustc-demangle", "rustc_abi", "rustc_ast", @@ -3453,7 +3443,7 @@ dependencies = [ "either", "itertools", "libc", - "object 0.36.7", + "object", "pathdiff", "regex", "rustc_abi", @@ -3485,7 +3475,7 @@ dependencies = [ "thorin-dwp", "tracing", "wasm-encoder 0.219.2", - "windows", + "windows 0.59.0", ] [[package]] @@ -3544,7 +3534,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3607,7 +3597,7 @@ dependencies = [ "serde_json", "shlex", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3662,7 +3652,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3709,7 +3699,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "unic-langid", ] @@ -3821,7 +3811,7 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand 0.9.0", + "rand 0.9.1", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3855,7 +3845,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4001,7 +3991,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -4387,7 +4377,7 @@ dependencies = [ "bitflags", "getopts", "libc", - "rand 0.9.0", + "rand 0.9.1", "rustc_abi", "rustc_ast", "rustc_data_structures", @@ -4405,7 +4395,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -4469,7 +4459,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags", - "object 0.36.7", + "object", "rustc_abi", "rustc_data_structures", "rustc_fs_util", @@ -4591,7 +4581,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -4682,7 +4672,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4716,9 +4706,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -4819,7 +4809,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4856,9 +4846,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -4977,9 +4967,9 @@ dependencies = [ [[package]] name = "stacker" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" dependencies = [ "cc", "cfg-if", @@ -5065,9 +5055,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -5076,13 +5066,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5094,7 +5084,7 @@ dependencies = [ "libc", "objc2-core-foundation", "objc2-io-kit", - "windows", + "windows 0.61.1", ] [[package]] @@ -5178,7 +5168,7 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand 0.9.0", + "rand 0.9.1", "rand_chacha 0.9.0", "rayon", ] @@ -5215,7 +5205,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5226,7 +5216,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5235,9 +5225,9 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ - "gimli 0.31.1", + "gimli", "hashbrown", - "object 0.36.7", + "object", "tracing", ] @@ -5352,9 +5342,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] @@ -5392,7 +5382,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5563,7 +5553,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.100", + "syn 2.0.101", "unic-langid-impl", ] @@ -5779,7 +5769,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -5801,7 +5791,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5979,6 +5969,19 @@ dependencies = [ "windows-targets 0.53.0", ] +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + [[package]] name = "windows-bindgen" version = "0.61.0" @@ -5990,6 +5993,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.0", +] + [[package]] name = "windows-core" version = "0.59.0" @@ -6016,6 +6028,16 @@ dependencies = [ "windows-strings 0.4.0", ] +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-implement" version = "0.59.0" @@ -6024,7 +6046,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6035,7 +6057,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6046,7 +6068,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6055,6 +6077,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-result" version = "0.3.2" @@ -6305,9 +6337,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] @@ -6428,28 +6460,28 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6469,7 +6501,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -6492,5 +6524,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] diff --git a/library/Cargo.lock b/library/Cargo.lock index f5c04a3bf48c..f766e8bc39c7 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -32,12 +32,6 @@ dependencies = [ "core", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alloctests" version = "0.0.0" @@ -134,11 +128,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ - "allocator-api2", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -221,15 +214,6 @@ dependencies = [ "unwind", ] -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - [[package]] name = "proc_macro" version = "0.0.0" @@ -246,15 +230,6 @@ dependencies = [ "cc", ] -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - [[package]] name = "r-efi" version = "5.2.0" @@ -278,12 +253,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_core", - "zerocopy", ] [[package]] @@ -387,17 +361,6 @@ dependencies = [ "rustc-std-workspace-core", ] -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "sysroot" version = "0.0.0" @@ -418,12 +381,6 @@ dependencies = [ "std", ] -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - [[package]] name = "unicode-width" version = "0.1.14" @@ -544,23 +501,3 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index fb584103df5d..81e0f6d572be 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -19,13 +19,13 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364" dependencies = [ + "cssparser", "html5ever", "maplit", - "once_cell", "tendril", "url", ] @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" @@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" dependencies = [ "shlex", ] @@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" +checksum = "be8c97f3a6f02b9e24cadc12aaba75201d18754b53ea0a9d99642f806ccdb4c9" dependencies = [ "clap", ] @@ -273,6 +273,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.11" @@ -389,6 +412,21 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "elasticlunr-rs" version = "3.0.2" @@ -537,9 +575,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -555,16 +593,14 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.27.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn", + "match_token", ] [[package]] @@ -775,9 +811,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" dependencies = [ "jiff-static", "log", @@ -788,9 +824,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" dependencies = [ "proc-macro2", "quote", @@ -815,9 +851,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libdbus-sys" @@ -880,16 +916,24 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -971,7 +1015,7 @@ dependencies = [ "pulldown-cmark-to-cmark 19.0.1", "serde_json", "thiserror 1.0.69", - "toml 0.8.20", + "toml 0.8.22", ] [[package]] @@ -1154,6 +1198,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ + "phf_macros", "phf_shared", ] @@ -1177,6 +1222,19 @@ dependencies = [ "rand", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "phf_shared" version = "0.11.3" @@ -1224,9 +1282,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -1327,9 +1385,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.0", ] @@ -1377,9 +1435,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.9.0", "errno", @@ -1464,9 +1522,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -1530,9 +1588,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -1541,9 +1599,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -1671,9 +1729,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -1683,26 +1741,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "topological-sort" version = "0.2.2" @@ -1857,6 +1922,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web_atoms" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2022,9 +2099,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] From d6183aa9d70e59eaa52ee7938d331a84f24942e9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 4 May 2025 06:09:34 +0200 Subject: [PATCH 208/302] Disable fixpoint for variance computation temporarily --- .../rust-analyzer/crates/hir-ty/src/db.rs | 5 +++-- .../crates/hir-ty/src/variance.rs | 19 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index c24ef16b4969..980ee264b027 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -283,8 +283,9 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::variance::variances_of)] #[salsa::cycle( - cycle_fn = crate::variance::variances_of_cycle_fn, - cycle_initial = crate::variance::variances_of_cycle_initial, + // cycle_fn = crate::variance::variances_of_cycle_fn, + // cycle_initial = crate::variance::variances_of_cycle_initial, + cycle_result = crate::variance::variances_of_cycle_initial, )] fn variances_of(&self, def: GenericDefId) -> Option>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 4e9aa5610a52..6e1cd9a310f1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -22,7 +22,6 @@ use crate::{ use chalk_ir::Mutability; use hir_def::signatures::StructFlags; use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId}; -use salsa::CycleRecoveryAction; use std::fmt; use std::ops::Not; use stdx::never; @@ -55,14 +54,14 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option>, - _count: u32, - _def: GenericDefId, -) -> CycleRecoveryAction>> { - CycleRecoveryAction::Iterate -} +// pub(crate) fn variances_of_cycle_fn( +// _db: &dyn HirDatabase, +// _result: &Option>, +// _count: u32, +// _def: GenericDefId, +// ) -> salsa::CycleRecoveryAction>> { +// salsa::CycleRecoveryAction::Iterate +// } pub(crate) fn variances_of_cycle_initial( db: &dyn HirDatabase, @@ -966,7 +965,7 @@ struct S3(S); struct FixedPoint(&'static FixedPoint<(), T, U>, V); "#, expect![[r#" - FixedPoint[T: covariant, U: covariant, V: covariant] + FixedPoint[T: bivariant, U: bivariant, V: bivariant] "#]], ); } From eb3a8e5b81db989764a2e8a7568318c6bc8aa986 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 3 May 2025 21:57:19 +0800 Subject: [PATCH 209/302] Make attribute safety validation logic more obvious --- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_parse/src/validate_attr.rs | 61 ++++++++++++++----- .../unsafe-attributes/auxiliary/safe_attr.rs | 7 +++ .../safe-proc-macro-attribute.rs | 22 +++++++ ...e-proc-macro-attribute.unknown_attr.stderr | 14 +++++ 5 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs create mode 100644 tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs create mode 100644 tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 02af26b01567..0994813ecb9c 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -276,7 +276,7 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { validate_attr::check_attribute_safety( &self.sess.psess, - AttributeSafety::Normal, + Some(AttributeSafety::Normal), &cfg_attr, ast::CRATE_NODE_ID, ); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index aa29b24fe910..378cbb846379 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { return; } - let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - let attr_item = attr.get_normal_item(); + let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - // All non-builtin attributes are considered safe - let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal); - check_attribute_safety(psess, safety, attr, id); + let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); + check_attribute_safety(psess, builtin_attr_safety, attr, id); // Check input tokens for built-in and key-value attributes. - match attr_info { + match builtin_attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { match parse_meta(psess, attr) { @@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { } } _ => { + let attr_item = attr.get_normal_item(); if let AttrArgs::Eq { .. } = attr_item.args { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { @@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte pub fn check_attribute_safety( psess: &ParseSess, - safety: AttributeSafety, + builtin_attr_safety: Option, attr: &Attribute, id: NodeId, ) { let attr_item = attr.get_normal_item(); + match (builtin_attr_safety, attr_item.unsafety) { + // - Unsafe builtin attribute + // - User wrote `#[unsafe(..)]`, which is permitted on any edition + (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { + // OK + } - if let AttributeSafety::Unsafe { unsafe_since } = safety { - if let ast::Safety::Default = attr_item.unsafety { + // - Unsafe builtin attribute + // - User did not write `#[unsafe(..)]` + (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { let path_span = attr_item.path.span; // If the `attr_item`'s span is not from a macro, then just suggest @@ -199,11 +205,38 @@ pub fn check_attribute_safety( ); } } - } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); + + // - Normal builtin attribute, or any non-builtin attribute + // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is + // not permitted on non-builtin attributes or normal builtin attributes + (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + + // - Normal builtin attribute + // - No explicit `#[unsafe(..)]` written. + (Some(AttributeSafety::Normal), Safety::Default) => { + // OK + } + + // - Non-builtin attribute + // - No explicit `#[unsafe(..)]` written. + (None, Safety::Default) => { + // OK + } + + ( + Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, + Safety::Safe(..), + ) => { + psess.dcx().span_delayed_bug( + attr_item.span(), + "`check_attribute_safety` does not expect `Safety::Safe` on attributes", + ); + } } } diff --git a/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs b/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs new file mode 100644 index 000000000000..161b71b9737b --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs @@ -0,0 +1,7 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} diff --git a/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs new file mode 100644 index 000000000000..56b7001bdbf0 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs @@ -0,0 +1,22 @@ +//! Anti-regression test for `#[safe]` proc-macro attribute. + +//@ revisions: unknown_attr proc_macro_attr +//@[proc_macro_attr] proc-macro: safe_attr.rs +//@[proc_macro_attr] check-pass + +#![warn(unsafe_attr_outside_unsafe)] + +#[cfg(proc_macro_attr)] +extern crate safe_attr; +#[cfg(proc_macro_attr)] +use safe_attr::safe; + +#[safe] +//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope +fn foo() {} + +#[safe(no_mangle)] +//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope +fn bar() {} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr new file mode 100644 index 000000000000..93c6d75e52ff --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr @@ -0,0 +1,14 @@ +error: cannot find attribute `safe` in this scope + --> $DIR/safe-proc-macro-attribute.rs:18:3 + | +LL | #[safe(no_mangle)] + | ^^^^ + +error: cannot find attribute `safe` in this scope + --> $DIR/safe-proc-macro-attribute.rs:14:3 + | +LL | #[safe] + | ^^^^ + +error: aborting due to 2 previous errors + From de44231d22eea1d1d27fab8d020557323996bb52 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 4 May 2025 16:41:42 +0300 Subject: [PATCH 210/302] implement `PanicTracker` to track `t` panics Trying to understand panics triggered by `t` macro calls is very exhausting (especially on CI failures) because it doesn't provide any information about where the macro was originally invoked. This change adds that missing information when an inner call inside the `t` macro panics. Signed-off-by: onur-ozkan --- src/bootstrap/src/lib.rs | 1 + src/bootstrap/src/utils/helpers.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 88d181532a7f..1e6acad5c0fc 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -53,6 +53,7 @@ use tracing::{instrument, span}; pub use utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; +pub use utils::helpers::PanicTracker; use crate::core::build_steps::vendor::VENDOR_DIR; diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 1299fbb7d629..b31b2757767c 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -7,8 +7,9 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::OnceLock; +use std::thread::panicking; use std::time::{Instant, SystemTime, UNIX_EPOCH}; -use std::{env, fs, io, str}; +use std::{env, fs, io, panic, str}; use build_helper::util::fail; use object::read::archive::ArchiveFile; @@ -22,6 +23,23 @@ pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var}; #[cfg(test)] mod tests; +/// A wrapper around `std::panic::Location` used to track the location of panics +/// triggered by `t` macro usage. +pub struct PanicTracker<'a>(pub &'a panic::Location<'a>); + +impl Drop for PanicTracker<'_> { + fn drop(&mut self) { + if panicking() { + eprintln!( + "Panic was initiated from {}:{}:{}", + self.0.file(), + self.0.line(), + self.0.column() + ); + } + } +} + /// A helper macro to `unwrap` a result except also print out details like: /// /// * The file/line of the panic @@ -32,19 +50,21 @@ mod tests; /// using a `Result` with `try!`, but this may change one day... #[macro_export] macro_rules! t { - ($e:expr) => { + ($e:expr) => {{ + let _panic_guard = $crate::PanicTracker(std::panic::Location::caller()); match $e { Ok(e) => e, Err(e) => panic!("{} failed with {}", stringify!($e), e), } - }; + }}; // it can show extra info in the second parameter - ($e:expr, $extra:expr) => { + ($e:expr, $extra:expr) => {{ + let _panic_guard = $crate::PanicTracker(std::panic::Location::caller()); match $e { Ok(e) => e, Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra), } - }; + }}; } pub use t; From 56d6b4e427c271e8f069500f6fac4e209e946144 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 May 2025 17:56:07 +0300 Subject: [PATCH 211/302] compiletest: Support matching on non-json lines in compiler output and migrate most of remaining `error-pattern`s to it. --- src/doc/rustc-dev-guide/src/tests/ui.md | 6 ++- src/tools/compiletest/src/errors.rs | 3 ++ src/tools/compiletest/src/json.rs | 32 +++++-------- src/tools/compiletest/src/runtest.rs | 43 ++++++++--------- .../compiletest/src/runtest/incremental.rs | 14 ++---- src/tools/compiletest/src/runtest/ui.rs | 47 ++++--------------- tests/incremental/ich_nested_items.rs | 1 + tests/incremental/incremental_proc_macro.rs | 2 +- tests/incremental/issue-49595/issue-49595.rs | 2 +- tests/incremental/issue-84252-global-alloc.rs | 1 + .../issue-85360-eval-obligation-ice.rs | 2 + tests/incremental/no_mangle.rs | 1 + .../thinlto/cgu_keeps_identical_fn.rs | 4 +- tests/incremental/unrecoverable_query.rs | 2 + tests/rustdoc-ui/ice-bug-report-url.rs | 5 +- tests/rustdoc-ui/ice-bug-report-url.stderr | 2 +- .../issues/issue-81662-shortness.rs | 3 +- .../issues/issue-81662-shortness.stdout | 8 ++-- .../issues/issue-83883-describe-lints.rs | 5 +- tests/ui/annotate-snippet/missing-type.rs | 3 +- tests/ui/annotate-snippet/missing-type.stderr | 2 +- tests/ui/annotate-snippet/multispan.rs | 3 +- tests/ui/annotate-snippet/multispan.stderr | 14 +++--- tests/ui/bootstrap/rustc_bootstrap.rs | 3 +- .../compile-flags-last.rs | 3 +- .../cfg-arg-invalid-7.rs | 5 +- .../debuginfo-type-name-layout-ice-94961-2.rs | 6 +-- tests/ui/diagnostic-width/flag-json.rs | 5 +- tests/ui/diagnostic-width/flag-json.stderr | 6 +-- tests/ui/error-emitter/highlighting.rs | 3 +- tests/ui/error-emitter/highlighting.svg | 4 +- .../ui/error-emitter/highlighting.windows.svg | 4 +- .../multiline-multipart-suggestion.rs | 3 +- .../multiline-multipart-suggestion.svg | 6 +-- ...multiline-multipart-suggestion.windows.svg | 6 +-- ...-between-expected-trait-and-found-trait.rs | 3 +- ...between-expected-trait-and-found-trait.svg | 6 +-- .../emit-output-types-without-args.rs | 3 +- tests/ui/json/json-bom-plus-crlf-multifile.rs | 5 ++ tests/ui/json/json-bom-plus-crlf.rs | 4 ++ tests/ui/json/json-bom-plus-crlf.stderr | 6 +-- tests/ui/json/json-short.rs | 1 + tests/ui/json/json-short.stderr | 2 +- .../lint/unused_parens_json_suggestion.fixed | 2 +- .../ui/lint/unused_parens_json_suggestion.rs | 2 +- .../lint/unused_parens_json_suggestion.stderr | 6 +-- ...unused_parens_remove_json_suggestion.fixed | 10 +++- .../unused_parens_remove_json_suggestion.rs | 10 +++- ...nused_parens_remove_json_suggestion.stderr | 36 +++++++------- tests/ui/mir/lint/assignment-overlap.rs | 3 +- tests/ui/mir/lint/call-overlap.rs | 3 +- tests/ui/mir/lint/storage-live.rs | 3 +- tests/ui/mir/lint/storage-live.stderr | 4 +- tests/ui/mir/lint/storage-return.rs | 3 +- tests/ui/mir/validate/critical-edge.rs | 4 +- tests/ui/panics/default-backtrace-ice.rs | 7 +-- tests/ui/panics/default-backtrace-ice.stderr | 2 +- tests/ui/treat-err-as-bug/err.rs | 5 +- tests/ui/treat-err-as-bug/err.stderr | 2 +- .../panic-causes-oom-112708.rs | 3 +- tests/ui/treat-err-as-bug/span_delayed_bug.rs | 5 +- .../treat-err-as-bug/span_delayed_bug.stderr | 2 +- tests/ui/unpretty/hir-tree.rs | 3 +- 63 files changed, 208 insertions(+), 196 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index b31c861c947a..721d20b65c5a 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -344,8 +344,7 @@ For checking runtime output, `//@ check-run-results` may be preferable. Only use `error-pattern` if none of the above works. -Line annotations `//~` are still checked in tests using `error-pattern`. -In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks. +Line annotations `//~` and `error-pattern` are compatible and can be used in the same test. ### Diagnostic kinds (error levels) @@ -356,9 +355,12 @@ The diagnostic kinds that you can have are: - `NOTE` - `HELP` - `SUGGESTION` +- `RAW` The `SUGGESTION` kind is used for specifying what the expected replacement text should be for a diagnostic suggestion. +The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted +by the compiler instead of or in addition to structured json. `ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations `//~` by default. diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index a45f39b036cc..b5a2b7feac9d 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -15,6 +15,7 @@ pub enum ErrorKind { Note, Suggestion, Warning, + Raw, } impl ErrorKind { @@ -39,6 +40,7 @@ impl ErrorKind { "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, + "RAW" => ErrorKind::Raw, _ => panic!( "unexpected diagnostic kind `{s}`, expected \ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" @@ -55,6 +57,7 @@ impl fmt::Display for ErrorKind { ErrorKind::Note => write!(f, "NOTE"), ErrorKind::Suggestion => write!(f, "SUGGESTION"), ErrorKind::Warning => write!(f, "WARN"), + ErrorKind::Raw => write!(f, "RAW"), } } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 151ac345125e..6ed2b52c66d2 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -7,7 +7,6 @@ use regex::Regex; use serde::Deserialize; use crate::errors::{Error, ErrorKind}; -use crate::runtest::ProcRes; #[derive(Deserialize)] struct Diagnostic { @@ -140,28 +139,19 @@ pub fn extract_rendered(output: &str) -> String { .collect() } -pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec { +pub fn parse_output(file_name: &str, output: &str) -> Vec { let mut errors = Vec::new(); for line in output.lines() { - // The compiler sometimes intermingles non-JSON stuff into the - // output. This hack just skips over such lines. Yuck. - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), - Err(error) => { - // Ignore the future compat report message - this is handled - // by `extract_rendered` - if serde_json::from_str::(line).is_err() { - proc_res.fatal( - Some(&format!( - "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}", - error, line, output - )), - || (), - ); - } - } - } + // Compiler can emit non-json lines in non-`--error-format=json` modes, + // and in some situations even in json mode. + match serde_json::from_str::(line) { + Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), + Err(_) => errors.push(Error { + line_num: None, + kind: ErrorKind::Raw, + msg: line.to_string(), + require_annotation: false, + }), } } errors diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 97cb82c9e363..40c9f29375b2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -23,7 +23,7 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; -use crate::errors::{Error, ErrorKind}; +use crate::errors::{Error, ErrorKind, load_errors}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; @@ -577,23 +577,9 @@ impl<'test> TestCx<'test> { } } - fn check_all_error_patterns( - &self, - output_to_check: &str, - proc_res: &ProcRes, - pm: Option, - ) { - if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() { - if pm.is_some() { - // FIXME(#65865) - return; - } else { - self.fatal(&format!("no error pattern specified in {}", self.testpaths.file)); - } - } - + /// Check `error-pattern` and `regex-error-pattern` directives. + fn check_all_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) { let mut missing_patterns: Vec = Vec::new(); - self.check_error_patterns(output_to_check, &mut missing_patterns); self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns); @@ -670,7 +656,9 @@ impl<'test> TestCx<'test> { } } - fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { + /// Check `//~ KIND message` annotations. + fn check_expected_errors(&self, proc_res: &ProcRes) { + let expected_errors = load_errors(&self.testpaths.file, self.revision); debug!( "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status @@ -711,11 +699,24 @@ impl<'test> TestCx<'test> { .collect(); // Parse the JSON output from the compiler and extract out the messages. - let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); + let actual_errors = json::parse_output(&diagnostic_file_name, &self.get_output(proc_res)) + .into_iter() + .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e }); + let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; - for mut actual_error in actual_errors { - actual_error.msg = self.normalize_output(&actual_error.msg, &[]); + for actual_error in actual_errors { + for pattern in &self.props.error_patterns { + let pattern = pattern.trim(); + if actual_error.msg.contains(pattern) { + let q = if actual_error.line_num.is_none() { "?" } else { "" }; + self.fatal(&format!( + "error pattern '{pattern}' is found in structured \ + diagnostics, use `//~{q} {} {pattern}` instead", + actual_error.kind, + )); + } + } let opt_index = expected_errors.iter().enumerate().position(|(index, expected_error)| { diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index ea985866a052..90cff6bab4dc 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -100,16 +100,8 @@ impl TestCx<'_> { self.check_no_compiler_crash(&proc_res, self.props.should_ice); let output_to_check = self.get_output(&proc_res); - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - if !expected_errors.is_empty() { - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - self.fatal("both error pattern and expected errors specified"); - } - self.check_expected_errors(expected_errors, &proc_res); - } else { - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } + self.check_expected_errors(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res); if self.props.should_ice { match proc_res.status.code() { Some(101) => (), @@ -137,6 +129,6 @@ impl TestCx<'_> { let output_to_check = self.get_output(&proc_res); self.check_correct_failure_status(&proc_res); - self.check_all_error_patterns(&output_to_check, &proc_res, pm); + self.check_all_error_patterns(&output_to_check, &proc_res); } } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index cf0ae14f81bf..cc50a918f757 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -9,7 +9,7 @@ use super::{ AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput, Truncated, UI_FIXED, WillExecute, }; -use crate::{errors, json}; +use crate::json; impl TestCx<'_> { pub(super) fn run_ui_test(&self) { @@ -127,9 +127,7 @@ impl TestCx<'_> { ); } - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - - if let WillExecute::Yes = should_run { + let output_to_check = if let WillExecute::Yes = should_run { let proc_res = self.exec_compiled_test(); let run_output_errors = if self.props.check_run_results { self.load_compare_outputs(&proc_res, TestOutput::Run, explicit) @@ -150,44 +148,19 @@ impl TestCx<'_> { self.fatal_proc_rec("test run succeeded!", &proc_res); } - let output_to_check = self.get_output(&proc_res); - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - // "// error-pattern" comments - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } - self.check_forbid_output(&output_to_check, &proc_res) - } + self.get_output(&proc_res) + } else { + self.get_output(&proc_res) + }; debug!( - "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \ + "run_ui_test: explicit={:?} config.compare_mode={:?} \ proc_res.status={:?} props.error_patterns={:?}", - explicit, - self.config.compare_mode, - expected_errors, - proc_res.status, - self.props.error_patterns + explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns ); - if !explicit && self.config.compare_mode.is_none() { - // "//~ERROR comments" - self.check_expected_errors(expected_errors, &proc_res); - } else if explicit && !expected_errors.is_empty() { - let msg = format!( - "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", - expected_errors[0].line_num_str(), - expected_errors[0].kind, - ); - self.fatal(&msg); - } - let output_to_check = self.get_output(&proc_res); - if should_run == WillExecute::No - && (!self.props.error_patterns.is_empty() - || !self.props.regex_error_patterns.is_empty()) - { - // "// error-pattern" comments - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } + self.check_expected_errors(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res); self.check_forbid_output(&output_to_check, &proc_res); if self.props.run_rustfix && self.config.compare_mode.is_none() { diff --git a/tests/incremental/ich_nested_items.rs b/tests/incremental/ich_nested_items.rs index 19628e0bce1b..c2a041ba268c 100644 --- a/tests/incremental/ich_nested_items.rs +++ b/tests/incremental/ich_nested_items.rs @@ -7,6 +7,7 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] +#![allow(dead_code)] #[rustc_clean(except = "opt_hir_owner_nodes", cfg = "cfail2")] pub fn foo() { diff --git a/tests/incremental/incremental_proc_macro.rs b/tests/incremental/incremental_proc_macro.rs index 3cf89cae6528..fc32aad5645c 100644 --- a/tests/incremental/incremental_proc_macro.rs +++ b/tests/incremental/incremental_proc_macro.rs @@ -12,5 +12,5 @@ extern crate incremental_proc_macro_aux; #[derive(IncrementalMacro)] pub struct Foo { - x: u32 + _x: u32 } diff --git a/tests/incremental/issue-49595/issue-49595.rs b/tests/incremental/issue-49595/issue-49595.rs index a291188f746e..7fe843135dfe 100644 --- a/tests/incremental/issue-49595/issue-49595.rs +++ b/tests/incremental/issue-49595/issue-49595.rs @@ -10,7 +10,7 @@ mod tests { #[cfg_attr(not(cfail1), test)] - fn test() { + fn _test() { } } diff --git a/tests/incremental/issue-84252-global-alloc.rs b/tests/incremental/issue-84252-global-alloc.rs index 8dc611df9d87..cd2cb2313bd3 100644 --- a/tests/incremental/issue-84252-global-alloc.rs +++ b/tests/incremental/issue-84252-global-alloc.rs @@ -1,5 +1,6 @@ //@ revisions: cfail1 cfail2 //@ build-pass +//@ needs-crate-type: cdylib #![crate_type="lib"] #![crate_type="cdylib"] diff --git a/tests/incremental/issue-85360-eval-obligation-ice.rs b/tests/incremental/issue-85360-eval-obligation-ice.rs index 70bb43f39ecf..2148e45bb387 100644 --- a/tests/incremental/issue-85360-eval-obligation-ice.rs +++ b/tests/incremental/issue-85360-eval-obligation-ice.rs @@ -4,6 +4,8 @@ //@ edition: 2021 //@ build-pass +#![allow(dead_code)] + use core::any::Any; use core::marker::PhantomData; diff --git a/tests/incremental/no_mangle.rs b/tests/incremental/no_mangle.rs index 1a01a40113a2..36b82a7b863c 100644 --- a/tests/incremental/no_mangle.rs +++ b/tests/incremental/no_mangle.rs @@ -1,6 +1,7 @@ //@ revisions:cfail1 cfail2 //@ check-pass //@ compile-flags: --crate-type cdylib +//@ needs-crate-type: cdylib #![deny(unused_attributes)] diff --git a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs index 5751759223b9..d124a3498c4a 100644 --- a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs +++ b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs @@ -33,12 +33,12 @@ mod foo { // Trivial functions like this one are imported very reliably by ThinLTO. - #[cfg(any(cfail1, cfail4))] + #[cfg(cfail1)] pub fn inlined_fn() -> u32 { 1234 } - #[cfg(not(any(cfail1, cfail4)))] + #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { 1234 } diff --git a/tests/incremental/unrecoverable_query.rs b/tests/incremental/unrecoverable_query.rs index e17236bebd25..798a418f7990 100644 --- a/tests/incremental/unrecoverable_query.rs +++ b/tests/incremental/unrecoverable_query.rs @@ -8,6 +8,8 @@ //@ compile-flags: --crate-type=lib //@ build-pass +#![allow(dead_code)] + pub trait P { type A; } diff --git a/tests/rustdoc-ui/ice-bug-report-url.rs b/tests/rustdoc-ui/ice-bug-report-url.rs index 9260644e44f1..2e384fa1be62 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.rs +++ b/tests/rustdoc-ui/ice-bug-report-url.rs @@ -1,8 +1,6 @@ //@ compile-flags: -Ztreat-err-as-bug //@ rustc-env:RUSTC_ICE=0 //@ failure-status: 101 -//@ error-pattern: aborting due to -//@ error-pattern: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md //@ normalize-stderr: "note: compiler flags.*\n\n" -> "" //@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}" @@ -13,3 +11,6 @@ fn wrong() //~^ ERROR expected one of + +//~? RAW aborting due to +//~? RAW we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr index 14a961c2ce01..b6eb8a1792df 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.stderr +++ b/tests/rustdoc-ui/ice-bug-report-url.stderr @@ -1,5 +1,5 @@ error: internal compiler error: expected one of `->`, `where`, or `{`, found `` - --> $DIR/ice-bug-report-url.rs:14:10 + --> $DIR/ice-bug-report-url.rs:12:10 | LL | fn wrong() | ^ expected one of `->`, `where`, or `{` diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.rs b/tests/rustdoc-ui/issues/issue-81662-shortness.rs index 8719442c34f9..5d1951dbe3ee 100644 --- a/tests/rustdoc-ui/issues/issue-81662-shortness.rs +++ b/tests/rustdoc-ui/issues/issue-81662-shortness.rs @@ -1,6 +1,5 @@ //@ compile-flags:--test --error-format=short //@ check-stdout -//@ error-pattern:cannot find function `foo` //@ normalize-stdout: "tests/rustdoc-ui/issues" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ failure-status: 101 @@ -11,3 +10,5 @@ fn foo() { println!("Hello, world!"); } + +//~? RAW cannot find function `foo` diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout index 8fcc7ed272f0..94a82cf0afc4 100644 --- a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout +++ b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout @@ -1,16 +1,16 @@ running 1 test -test $DIR/issue-81662-shortness.rs - foo (line 8) ... FAILED +test $DIR/issue-81662-shortness.rs - foo (line 7) ... FAILED failures: ----- $DIR/issue-81662-shortness.rs - foo (line 8) stdout ---- -$DIR/issue-81662-shortness.rs:9:1: error[E0425]: cannot find function `foo` in this scope: not found in this scope +---- $DIR/issue-81662-shortness.rs - foo (line 7) stdout ---- +$DIR/issue-81662-shortness.rs:8:1: error[E0425]: cannot find function `foo` in this scope: not found in this scope error: aborting due to 1 previous error Couldn't compile the test. failures: - $DIR/issue-81662-shortness.rs - foo (line 8) + $DIR/issue-81662-shortness.rs - foo (line 7) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs b/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs index 35d2fda45850..62a0942df1b1 100644 --- a/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs +++ b/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs @@ -1,10 +1,11 @@ //@ compile-flags: -W help //@ check-pass //@ check-stdout -//@ error-pattern:Lint checks provided -//@ error-pattern:rustdoc::broken-intra-doc-links // // ignore-tidy-linelength // //@ normalize-stdout: "( +name default meaning\n +---- ------- -------\n)?( *[[:word:]:-]+ (allow |warn |deny |forbid ) [^\n]+\n)+" -> " $$NAMES $$LEVELS $$MEANINGS" //@ normalize-stdout: " +name sub-lints\n +---- ---------\n( *[[:word:]:-]+ [^\n]+\n)+" -> " $$NAMES $$SUB_LINTS" + +//~? RAW Lint checks provided +//~? RAW rustdoc::broken-intra-doc-links diff --git a/tests/ui/annotate-snippet/missing-type.rs b/tests/ui/annotate-snippet/missing-type.rs index ea1c2521103e..bfe8ab2f5ffe 100644 --- a/tests/ui/annotate-snippet/missing-type.rs +++ b/tests/ui/annotate-snippet/missing-type.rs @@ -1,6 +1,7 @@ //@ compile-flags: --error-format human-annotate-rs -Z unstable-options -//@ error-pattern:cannot find type `Iter` in this scope pub fn main() { let x: Iter; } + +//~? RAW cannot find type `Iter` in this scope diff --git a/tests/ui/annotate-snippet/missing-type.stderr b/tests/ui/annotate-snippet/missing-type.stderr index 89ce19c182f5..c16f022a77fa 100644 --- a/tests/ui/annotate-snippet/missing-type.stderr +++ b/tests/ui/annotate-snippet/missing-type.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Iter` in this scope - --> $DIR/missing-type.rs:5:12 + --> $DIR/missing-type.rs:4:12 | LL | let x: Iter; | ^^^^ not found in this scope diff --git a/tests/ui/annotate-snippet/multispan.rs b/tests/ui/annotate-snippet/multispan.rs index b7cf22eebcbf..c2054f62d24c 100644 --- a/tests/ui/annotate-snippet/multispan.rs +++ b/tests/ui/annotate-snippet/multispan.rs @@ -1,5 +1,4 @@ //@ proc-macro: multispan.rs -//@ error-pattern:hello to you, too! //@ compile-flags: --error-format human-annotate-rs -Z unstable-options #![feature(proc_macro_hygiene)] @@ -27,3 +26,5 @@ fn main() { hello!(whoah. hi di hi di ho); hello!(hi good hi and good bye); } + +//~? RAW hello to you, too! diff --git a/tests/ui/annotate-snippet/multispan.stderr b/tests/ui/annotate-snippet/multispan.stderr index 833b67730325..baed54c59a4e 100644 --- a/tests/ui/annotate-snippet/multispan.stderr +++ b/tests/ui/annotate-snippet/multispan.stderr @@ -1,41 +1,41 @@ error: hello to you, too! - --> $DIR/multispan.rs:16:5 + --> $DIR/multispan.rs:15:5 | LL | hello!(hi); | ^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:19:5 + --> $DIR/multispan.rs:18:5 | LL | hello!(hi hi); | ^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:22:5 + --> $DIR/multispan.rs:21:5 | LL | hello!(hi hi hi); | ^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:25:5 + --> $DIR/multispan.rs:24:5 | LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:26:5 + --> $DIR/multispan.rs:25:5 | LL | hello!(hi there, hi how are you? hi... hi.); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:27:5 + --> $DIR/multispan.rs:26:5 | LL | hello!(whoah. hi di hi di ho); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:28:5 + --> $DIR/multispan.rs:27:5 | LL | hello!(hi good hi and good bye); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/bootstrap/rustc_bootstrap.rs b/tests/ui/bootstrap/rustc_bootstrap.rs index daa28e0cdf29..fb72bba95a15 100644 --- a/tests/ui/bootstrap/rustc_bootstrap.rs +++ b/tests/ui/bootstrap/rustc_bootstrap.rs @@ -38,10 +38,11 @@ // also affected by `RUSTC_BOOTSTRAP`. //@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1 //@[force_stable] compile-flags: -Z unstable-options -//@[force_stable] regex-error-pattern: error: the option `Z` is only accepted on the nightly compiler #![crate_type = "lib"] // Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is // used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic. #![feature(rustc_attrs)] + +//[force_stable]~? RAW the option `Z` is only accepted on the nightly compiler diff --git a/tests/ui/compiletest-self-test/compile-flags-last.rs b/tests/ui/compiletest-self-test/compile-flags-last.rs index b78a64394b87..e0743d2aea58 100644 --- a/tests/ui/compiletest-self-test/compile-flags-last.rs +++ b/tests/ui/compiletest-self-test/compile-flags-last.rs @@ -4,4 +4,5 @@ // next flag as the argument of this flag. // //@ compile-flags: --cap-lints -//@ error-pattern: Argument to option 'cap-lints' missing + +//~? RAW Argument to option 'cap-lints' missing diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs index b4344f1bca5c..f05adc7bf7aa 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs @@ -1,5 +1,6 @@ // Regression test for issue #89358. //@ compile-flags: --cfg a" -//@ error-pattern: unterminated double quote string -//@ error-pattern: this error occurred on the command line + +//~? RAW unterminated double quote string +//~? RAW this error occurred on the command line diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs index 08f8ae391fdb..35210e78dcd9 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs @@ -1,6 +1,3 @@ -// ignore-tidy-linelength -// FIXME(#140620)~ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture - // Make sure the compiler does not ICE when trying to generate the debuginfo name of a type that // causes a layout error. // This version of the test already ICE'd before the commit that introduce the ICE described in @@ -8,7 +5,6 @@ //@ compile-flags:-C debuginfo=2 --error-format=human //@ build-fail -//@ error-pattern: values of the type `[u8; usize::MAX]` are too big for the target architecture #![crate_type = "rlib"] @@ -21,4 +17,4 @@ pub fn foo() -> usize { } // FIXME(#140620): the error is reported on different lines on different targets -//FIXME(#140620)~? ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +//~? RAW values of the type `[u8; usize::MAX]` are too big for the target architecture diff --git a/tests/ui/diagnostic-width/flag-json.rs b/tests/ui/diagnostic-width/flag-json.rs index 00778872727b..edc7d2e2a425 100644 --- a/tests/ui/diagnostic-width/flag-json.rs +++ b/tests/ui/diagnostic-width/flag-json.rs @@ -1,9 +1,10 @@ //@ compile-flags: --diagnostic-width=20 --error-format=json -//@ error-pattern:expected `()`, found integer // This test checks that `-Z output-width` effects the JSON error output by restricting it to an // arbitrarily low value so that the effect is visible. fn main() { - let _: () = 42; + let _: () = 42; //~ ERROR mismatched types + //~| NOTE expected `()`, found integer + //~| NOTE expected due to this } diff --git a/tests/ui/diagnostic-width/flag-json.stderr b/tests/ui/diagnostic-width/flag-json.stderr index 6a54f86dcee5..cfc0364be76d 100644 --- a/tests/ui/diagnostic-width/flag-json.stderr +++ b/tests/ui/diagnostic-width/flag-json.stderr @@ -24,10 +24,10 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":291,"byte_end":293,"line_start":8,"line_end":8,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":286,"byte_end":288,"line_start":8,"line_end":8,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types - --> $DIR/flag-json.rs:8:17 +"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42; + --> $DIR/flag-json.rs:7:17 | -LL | ..._: () = 42; +LL | ..._: () = 42; /... | -- ^^ expected `()`, found integer | | | expected due to this diff --git a/tests/ui/error-emitter/highlighting.rs b/tests/ui/error-emitter/highlighting.rs index b3c1acbd342c..d7a0c9d22466 100644 --- a/tests/ui/error-emitter/highlighting.rs +++ b/tests/ui/error-emitter/highlighting.rs @@ -1,7 +1,6 @@ // Make sure "highlighted" code is colored purple //@ compile-flags: --error-format=human --color=always -//@ error-pattern:for<'a>  //@ edition:2018 use core::pin::Pin; @@ -21,3 +20,5 @@ fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin  diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index 68fc118f1a6e..19818ab6146c 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -23,7 +23,7 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:22:11 + --> $DIR/highlighting.rs:21:11 | @@ -43,7 +43,7 @@ note: function defined here - --> $DIR/highlighting.rs:11:4 + --> $DIR/highlighting.rs:10:4 | diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index c7dd001434ee..f891bc1d2a68 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -24,7 +24,7 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:22:11 + --> $DIR/highlighting.rs:21:11 | @@ -44,7 +44,7 @@ note: function defined here - --> $DIR/highlighting.rs:11:4 + --> $DIR/highlighting.rs:10:4 | diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.rs b/tests/ui/error-emitter/multiline-multipart-suggestion.rs index a938b280ca2e..92dede1b5d83 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.rs +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.rs @@ -1,5 +1,4 @@ //@ compile-flags: --error-format=human --color=always -//@ error-pattern: missing lifetime specifier fn short(foo_bar: &Vec<&i32>) -> &i32 { &12 @@ -17,3 +16,5 @@ fn long2( &12 } fn main() {} + +//~? RAW missing lifetime specifier diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.svg index c0fb98555ad8..dd84234236d7 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.svg @@ -23,7 +23,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:4:34 + --> $DIR/multiline-multipart-suggestion.rs:3:34 | @@ -47,7 +47,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:11:6 + --> $DIR/multiline-multipart-suggestion.rs:10:6 | @@ -83,7 +83,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:16:29 + --> $DIR/multiline-multipart-suggestion.rs:15:29 | diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg index 61b544001f08..144e57165da7 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg @@ -23,7 +23,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:4:34 + --> $DIR/multiline-multipart-suggestion.rs:3:34 | @@ -47,7 +47,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:11:6 + --> $DIR/multiline-multipart-suggestion.rs:10:6 | @@ -83,7 +83,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:16:29 + --> $DIR/multiline-multipart-suggestion.rs:15:29 | diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs index f1c196a154d5..ffb7a1008e0f 100644 --- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs @@ -1,6 +1,5 @@ //@ only-linux //@ compile-flags: --error-format=human --color=always -//@ error-pattern: the trait bound trait Foo: Bar {} @@ -18,3 +17,5 @@ fn foo() -> impl Foo { } fn main() {} + +//~? RAW the trait bound diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg index 1a79a9d7efa2..9832e28e008b 100644 --- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg @@ -1,4 +1,4 @@ - + ) -> i32 { 0 } + //~^ ERROR function with `#[export_stable]` attribute uses type `Box`, which is not exportable +} + +pub mod impl_item { + pub struct S; + + impl S { + #[export_stable] + pub extern "C" fn foo1(&self) -> i32 { 0 } + //~^ ERROR method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable + + #[export_stable] + pub extern "C" fn foo2(self) -> i32 { 0 } + //~^ ERROR method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable + } + + pub struct S2(T); + + impl S2 { + #[export_stable] + pub extern "C" fn foo1(&self) {} + //~^ ERROR generic functions are not exportable + } +} + +pub mod tys { + pub trait Trait { + type Type; + } + pub struct S; + + impl Trait for S { + type Type = (u32,); + } + + #[export_stable] + pub extern "C" fn foo1(x: ::Type) -> u32 { x.0 } + //~^ ERROR function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable + + #[export_stable] + pub type Type = [i32; 4]; + + #[export_stable] + pub extern "C" fn foo2(_x: Type) {} + //~^ ERROR function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable + + impl S { + #[export_stable] + pub type Type = extern "C" fn(); + } + + #[export_stable] + pub extern "C" fn foo3(_x: S::Type) {} + //~^ ERROR function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable + + #[export_stable] + pub extern "C" fn foo4() -> impl Copy { + //~^ ERROR function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable + 0 + } +} + +pub mod privacy { + #[export_stable] + #[repr(C)] + pub struct S1 { + pub x: i32 + } + + #[export_stable] + #[repr(C)] + pub struct S2 { + //~^ ERROR ADT types with private fields are not exportable + x: i32 + } + + #[export_stable] + #[repr(i32)] + enum E { + //~^ ERROR private items are not exportable + Variant1 { x: i32 } + } +} + +pub mod use_site { + #[export_stable] + pub trait Trait {} + //~^ ERROR trait's are not exportable + + #[export_stable] + pub const C: i32 = 0; + //~^ ERROR constant's are not exportable +} + +fn main() {} diff --git a/tests/ui/attributes/export/exportable.stderr b/tests/ui/attributes/export/exportable.stderr new file mode 100644 index 000000000000..0f6469d35c3b --- /dev/null +++ b/tests/ui/attributes/export/exportable.stderr @@ -0,0 +1,130 @@ +error: private items are not exportable + --> $DIR/exportable.rs:10:5 + | +LL | pub struct S; + | ^^^^^^^^^^^^ + | +note: is only usable at visibility `pub(crate)` + --> $DIR/exportable.rs:10:5 + | +LL | pub struct S; + | ^^^^^^^^^^^^ + +error: private items are not exportable + --> $DIR/exportable.rs:123:5 + | +LL | enum E { + | ^^^^^^ + | +note: is only usable at visibility `pub(self)` + --> $DIR/exportable.rs:123:5 + | +LL | enum E { + | ^^^^^^ + +error: trait's are not exportable + --> $DIR/exportable.rs:131:5 + | +LL | pub trait Trait {} + | ^^^^^^^^^^^^^^^ + +error: constant's are not exportable + --> $DIR/exportable.rs:135:5 + | +LL | pub const C: i32 = 0; + | ^^^^^^^^^^^^^^^^ + +error: only functions with "C" ABI are exportable + --> $DIR/exportable.rs:13:5 + | +LL | pub fn foo() -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^ + +error: types with unstable layout are not exportable + --> $DIR/exportable.rs:27:5 + | +LL | pub struct S3; + | ^^^^^^^^^^^^^ + +error: only functions with "C" ABI are exportable + --> $DIR/exportable.rs:33:5 + | +LL | pub fn foo1() {} + | ^^^^^^^^^^^^^ + +error: function with `#[export_stable]` attribute uses type `Box`, which is not exportable + --> $DIR/exportable.rs:44:5 + | +LL | pub extern "C" fn foo3(x: Box) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^^ + | | + | not exportable + +error: method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable + --> $DIR/exportable.rs:53:9 + | +LL | pub extern "C" fn foo1(&self) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^ + | | + | not exportable + +error: method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable + --> $DIR/exportable.rs:57:9 + | +LL | pub extern "C" fn foo2(self) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^^ + | | + | not exportable + +error: generic functions are not exportable + --> $DIR/exportable.rs:65:9 + | +LL | pub extern "C" fn foo1(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable + --> $DIR/exportable.rs:81:5 + | +LL | pub extern "C" fn foo1(x: ::Type) -> u32 { x.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^^^^^^^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable + --> $DIR/exportable.rs:88:5 + | +LL | pub extern "C" fn foo2(_x: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable + --> $DIR/exportable.rs:97:5 + | +LL | pub extern "C" fn foo3(_x: S::Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable + --> $DIR/exportable.rs:101:5 + | +LL | pub extern "C" fn foo4() -> impl Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- + | | + | not exportable + +error: ADT types with private fields are not exportable + --> $DIR/exportable.rs:116:5 + | +LL | pub struct S2 { + | ^^^^^^^^^^^^^ + | +note: `x` is private + --> $DIR/exportable.rs:118:9 + | +LL | x: i32 + | ^^^^^^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/attributes/export/lang-item.rs b/tests/ui/attributes/export/lang-item.rs new file mode 100644 index 000000000000..b923b41a9575 --- /dev/null +++ b/tests/ui/attributes/export/lang-item.rs @@ -0,0 +1,8 @@ +#![feature(no_core, lang_items, export_stable)] +#![allow(incomplete_features)] +#![crate_type = "sdylib"] +#![no_core] + +#[lang = "sized"] +//~^ ERROR lang items are not allowed in stable dylibs +trait Sized {} diff --git a/tests/ui/attributes/export/lang-item.stderr b/tests/ui/attributes/export/lang-item.stderr new file mode 100644 index 000000000000..8c0741bdb6f2 --- /dev/null +++ b/tests/ui/attributes/export/lang-item.stderr @@ -0,0 +1,8 @@ +error: lang items are not allowed in stable dylibs + --> $DIR/lang-item.rs:6:1 + | +LL | #[lang = "sized"] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/feature-gate-export_stable.rs b/tests/ui/feature-gates/feature-gate-export_stable.rs new file mode 100644 index 000000000000..5d05fee059b8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export_stable.rs @@ -0,0 +1,5 @@ +#![crate_type="lib"] + +#[export_stable] +//~^ ERROR the `#[export_stable]` attribute is an experimental feature +pub mod a {} diff --git a/tests/ui/feature-gates/feature-gate-export_stable.stderr b/tests/ui/feature-gates/feature-gate-export_stable.stderr new file mode 100644 index 000000000000..6beb52a77e5c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export_stable.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[export_stable]` attribute is an experimental feature + --> $DIR/feature-gate-export_stable.rs:3:1 + | +LL | #[export_stable] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #139939 for more information + = help: add `#![feature(export_stable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From e6030468dd10ec8ef93b6a50afaceafce0d6d81b Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 4 May 2025 22:29:57 +0200 Subject: [PATCH 217/302] Revert "Avoid unused clones in Cloned and Copied" This reverts commit ed5f31ab01d41a01b7206eafdf97b458dc41141a. --- library/core/src/iter/adapters/cloned.rs | 88 +--------------------- library/core/src/iter/adapters/copied.rs | 95 +++++------------------- 2 files changed, 20 insertions(+), 163 deletions(-) diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 72d746289711..aea6d64281ae 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,6 +1,5 @@ use core::num::NonZero; -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -42,31 +41,13 @@ where self.it.next().cloned() } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().cloned() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).cloned() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -80,58 +61,6 @@ where self.it.map(T::clone).fold(init, f) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).cloned() - } - - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).cloned() - } - - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).cloned() - } - - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) - } - - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) - } - - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) - } - - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) - } - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -152,13 +81,9 @@ where self.it.next_back().cloned() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -171,13 +96,6 @@ where { self.it.map(T::clone).rfold(init, f) } - - fn rfind

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).cloned() - } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -186,12 +104,10 @@ where I: ExactSizeIterator, T: Clone, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 73913aa34a9e..23e4e25ab538 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,4 +1,3 @@ -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -49,35 +48,20 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> { + ) -> Result<[Self::Item; N], array::IntoIter> + where + Self: Sized, + { >::spec_next_chunk(&mut self.it) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().copied() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -91,56 +75,21 @@ where self.it.fold(init, copy_fold(f)) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).copied() + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() } - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).copied() + fn last(self) -> Option { + self.it.last().copied() } - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).copied() + fn count(self) -> usize { + self.it.count() } - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) - } - - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) - } - - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) - } - - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -163,13 +112,9 @@ where self.it.next_back().copied() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -183,11 +128,9 @@ where self.it.rfold(init, copy_fold(f)) } - fn rfind

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).copied() + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) } } @@ -197,12 +140,10 @@ where I: ExactSizeIterator, T: Copy, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } From 52d806a7c0b8523af013e7f3fd67480884a396c8 Mon Sep 17 00:00:00 2001 From: Nick Kocharhook Date: Sun, 19 Jan 2025 15:35:49 +0000 Subject: [PATCH 218/302] extract_if's sample equivalent now really equivalent. Simpler predicate. Compare sample code output to that of the library function. --- library/alloc/src/vec/mod.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 65a83cb98ba6..788cb1ae8947 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3666,21 +3666,27 @@ impl Vec { /// Using this method is equivalent to the following code: /// /// ``` - /// # use std::cmp::min; - /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; - /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// # let range = 1..4; + /// # let some_predicate = |x: &mut i32| { *x % 2 == 1 }; + /// # let mut vec = vec![0, 1, 2, 3, 4, 5, 6]; + /// # let mut vec2 = vec.clone(); + /// # let range = 1..5; /// let mut i = range.start; - /// while i < min(vec.len(), range.end) { + /// let end_items = vec.len() - range.end; + /// # let mut extracted = vec![]; + /// + /// while i < vec.len() - end_items { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); + /// # extracted.push(val); /// // your code here /// } else { /// i += 1; /// } /// } /// - /// # assert_eq!(vec, vec![1, 4, 5]); + /// # let extracted2: Vec<_> = vec2.extract_if(range, some_predicate).collect(); + /// # assert_eq!(vec, vec2); + /// # assert_eq!(extracted, extracted2); /// ``` /// /// But `extract_if` is easier to use. `extract_if` is also more efficient, From 435fc7d685115cf5bbd986ade8d2327ee6441759 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 4 May 2025 22:54:55 +0000 Subject: [PATCH 219/302] Update `compiler-builtins` to 0.1.157 Includes the following changes: * Use runtime feature detection for fma routines on x86 [1] Fixes: https://github.com/rust-lang/rust/issues/140452 [1]: https://github.com/rust-lang/compiler-builtins/pull/896 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index f5c04a3bf48c..3df15316d985 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.156" +version = "0.1.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" +checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 994221de8663..ebfcf8759fa1 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.157", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d7bd28b5279d..06bec74523bb 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156" } +compiler_builtins = { version = "=0.1.157" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 07d38eec30d21e1e63a76583cdd23cbd89036ad5 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 4 May 2025 19:57:12 -0400 Subject: [PATCH 220/302] Temporarily downgrade backtrace to 0.3.71 --- Cargo.lock | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 967da170476e..a95d66b6ca87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,11 +4,11 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli", + "gimli 0.28.1", ] [[package]] @@ -168,7 +168,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ - "object", + "object 0.36.7", ] [[package]] @@ -233,17 +233,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", + "cc", "cfg-if", "libc", - "miniz_oxide 0.8.8", - "object", + "miniz_oxide 0.7.4", + "object 0.32.2", "rustc-demangle", - "windows-targets 0.52.6", ] [[package]] @@ -1452,6 +1452,12 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "gimli" version = "0.31.1" @@ -2062,7 +2068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -2476,6 +2482,15 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "object" version = "0.36.7" @@ -3089,9 +3104,9 @@ version = "0.2.0" dependencies = [ "bstr", "build_helper", - "gimli", + "gimli 0.31.1", "libc", - "object", + "object 0.36.7", "regex", "serde_json", "similar", @@ -3398,11 +3413,11 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags", - "gimli", + "gimli 0.31.1", "itertools", "libc", "measureme", - "object", + "object 0.36.7", "rustc-demangle", "rustc_abi", "rustc_ast", @@ -3443,7 +3458,7 @@ dependencies = [ "either", "itertools", "libc", - "object", + "object 0.36.7", "pathdiff", "regex", "rustc_abi", @@ -4459,7 +4474,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags", - "object", + "object 0.36.7", "rustc_abi", "rustc_data_structures", "rustc_fs_util", @@ -5225,9 +5240,9 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ - "gimli", + "gimli 0.31.1", "hashbrown", - "object", + "object 0.36.7", "tracing", ] From e5879018ef648e990f8af9d638db456a9fac07e3 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 4 May 2025 19:55:09 -0700 Subject: [PATCH 221/302] move logic for telling whether to peel smart pointers into a helper The new logic for determining whether to peel references will depend on whether smart pointers need to be peeled before matching. --- compiler/rustc_hir_typeck/src/pat.rs | 44 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7520782930a2..ea335c7a4a7b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -531,24 +531,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the // examples in `tests/ui/pattern/deref_patterns/`. _ if self.tcx.features().deref_patterns() - && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode + && let AdjustMode::Peel { kind: peel_kind } = adjust_mode && pat.default_binding_modes - // For simplicity, only apply overloaded derefs if `expected` is a known ADT. - // FIXME(deref_patterns): we'll get better diagnostics for users trying to - // implicitly deref generics if we allow them here, but primitives, tuples, and - // inference vars definitely should be stopped. Figure out what makes most sense. - && let ty::Adt(scrutinee_adt, _) = *expected.kind() - // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if - // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. - && until_adt != Some(scrutinee_adt.did()) - // At this point, the pattern isn't able to match `expected` without peeling. Check - // that it implements `Deref` before assuming it's a smart pointer, to get a normal - // type error instead of a missing impl error if not. This only checks for `Deref`, - // not `DerefPure`: we require that too, but we want a trait error if it's missing. - && let Some(deref_trait) = self.tcx.lang_items().deref_trait() - && self - .type_implements_trait(deref_trait, [expected], self.param_env) - .may_apply() => + && self.should_peel_smart_pointer(peel_kind, expected) => { debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); // The scrutinee is a smart pointer; implicitly dereference it. This adds a @@ -720,6 +705,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Determine whether `expected` is a smart pointer type that should be peeled before matching. + fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool { + // Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case. + if let PeelKind::Implicit { until_adt, .. } = peel_kind + // For simplicity, only apply overloaded derefs if `expected` is a known ADT. + // FIXME(deref_patterns): we'll get better diagnostics for users trying to + // implicitly deref generics if we allow them here, but primitives, tuples, and + // inference vars definitely should be stopped. Figure out what makes most sense. + && let ty::Adt(scrutinee_adt, _) = *expected.kind() + // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if + // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. + && until_adt != Some(scrutinee_adt.did()) + // At this point, the pattern isn't able to match `expected` without peeling. Check + // that it implements `Deref` before assuming it's a smart pointer, to get a normal + // type error instead of a missing impl error if not. This only checks for `Deref`, + // not `DerefPure`: we require that too, but we want a trait error if it's missing. + && let Some(deref_trait) = self.tcx.lang_items().deref_trait() + && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply() + { + true + } else { + false + } + } + fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { let ty = match <.kind { rustc_hir::PatExprKind::Lit { lit, negated } => { From e4272d12f29dc425679749a1fb7569bd25464e88 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Wed, 9 Apr 2025 16:40:50 +0530 Subject: [PATCH 222/302] feat: Added capability to add multiple dependencies for an LLVMFeature --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 37 +++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 264510285a59..f8706c5ee2fa 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -19,6 +19,7 @@ use rustc_session::config::{PrintKind, PrintRequest}; use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; +use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; use crate::errors::{ @@ -180,27 +181,27 @@ impl<'a> TargetFeatureFoldStrength<'a> { pub(crate) struct LLVMFeature<'a> { llvm_feature_name: &'a str, - dependency: Option>, + dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>, } impl<'a> LLVMFeature<'a> { fn new(llvm_feature_name: &'a str) -> Self { - Self { llvm_feature_name, dependency: None } + Self { llvm_feature_name, dependencies: SmallVec::new() } } - fn with_dependency( + fn with_dependencies( llvm_feature_name: &'a str, - dependency: TargetFeatureFoldStrength<'a>, + dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>, ) -> Self { - Self { llvm_feature_name, dependency: Some(dependency) } + Self { llvm_feature_name, dependencies } } - fn contains(&self, feat: &str) -> bool { + fn contains(&'a self, feat: &str) -> bool { self.iter().any(|dep| dep == feat) } fn iter(&'a self) -> impl Iterator { - let dependencies = self.dependency.iter().map(|feat| feat.as_str()); + let dependencies = self.dependencies.iter().map(|feat| feat.as_str()); std::iter::once(self.llvm_feature_name).chain(dependencies) } } @@ -210,7 +211,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> { type IntoIter = impl Iterator; fn into_iter(self) -> Self::IntoIter { - let dependencies = self.dependency.into_iter().map(|feat| feat.as_str()); + let dependencies = self.dependencies.into_iter().map(|feat| feat.as_str()); std::iter::once(self.llvm_feature_name).chain(dependencies) } } @@ -240,9 +241,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::with_dependency( + ("x86", "sse4.2") => Some(LLVMFeature::with_dependencies( "sse4.2", - TargetFeatureFoldStrength::EnableOnly("crc32"), + smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")], )), ("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")), ("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")), @@ -262,9 +263,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("b16b16")), ("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")), // Rust ties fp and neon together. - ("aarch64", "neon") => { - Some(LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8"))) - } + ("aarch64", "neon") => Some(LLVMFeature::with_dependencies( + "neon", + smallvec![TargetFeatureFoldStrength::Both("fp-armv8")], + )), // In LLVM neon implicitly enables fp, but we manually enable // neon when a feature only implicitly enables fp ("aarch64", "fhm") => Some(LLVMFeature::new("fp16fml")), @@ -281,9 +283,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // Enable the evex512 target feature if an avx512 target feature is enabled. - ("x86", s) if s.starts_with("avx512") => { - Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) - } + ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( + s, + smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")], + )), // Support for `wide-arithmetic` will first land in LLVM 20 as part of // llvm/llvm-project#111598 ("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None, @@ -853,7 +856,7 @@ pub(crate) fn global_llvm_features( "{}{}", enable_disable, llvm_feature.llvm_feature_name )) - .chain(llvm_feature.dependency.into_iter().filter_map( + .chain(llvm_feature.dependencies.into_iter().filter_map( move |feat| match (enable, feat) { (_, TargetFeatureFoldStrength::Both(f)) | (true, TargetFeatureFoldStrength::EnableOnly(f)) => { From 7845c011dd3bdfb5eaa461476f5f7d0f3aa16dfc Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 5 May 2025 12:16:40 +0200 Subject: [PATCH 223/302] collect all Fuchsia bindings into the `fuchsia` module The Fuchsia bindings are currently spread out across multiple modules in `sys/pal/unix` leading to unnecessary duplication. This PR moves all of these definitions into `sys::pal::unix::fuchsia` and additionally: * deduplicates the definitions * makes the error names consistent * marks some extern functions as safe * removes unused items (there's no need to maintain these bindings if we're not going to use them) * removes the documentation for the definitions (contributors should always consult the platform documentation, duplicating that here is just an extra maintenance burden) --- library/std/src/sys/pal/unix/fuchsia.rs | 323 +++++++------------- library/std/src/sys/pal/unix/futex.rs | 54 +--- library/std/src/sys/pal/unix/thread.rs | 19 +- library/std/src/sys/process/unix/fuchsia.rs | 4 +- library/std/src/sys/sync/mutex/fuchsia.rs | 6 +- 5 files changed, 123 insertions(+), 283 deletions(-) diff --git a/library/std/src/sys/pal/unix/fuchsia.rs b/library/std/src/sys/pal/unix/fuchsia.rs index 7932bd26d76c..c118dee62476 100644 --- a/library/std/src/sys/pal/unix/fuchsia.rs +++ b/library/std/src/sys/pal/unix/fuchsia.rs @@ -1,48 +1,35 @@ -#![allow(non_camel_case_types, unused)] +#![expect(non_camel_case_types)] -use libc::{c_int, c_void, size_t}; +use libc::size_t; +use crate::ffi::{c_char, c_int, c_void}; use crate::io; -use crate::mem::MaybeUninit; -use crate::os::raw::c_char; + +////////// +// Time // +////////// + +pub type zx_time_t = i64; + +pub const ZX_TIME_INFINITE: zx_time_t = i64::MAX; + +unsafe extern "C" { + pub safe fn zx_clock_get_monotonic() -> zx_time_t; +} + +///////////// +// Handles // +///////////// pub type zx_handle_t = u32; -pub type zx_vaddr_t = usize; -pub type zx_rights_t = u32; -pub type zx_status_t = i32; pub const ZX_HANDLE_INVALID: zx_handle_t = 0; -pub type zx_time_t = i64; -pub const ZX_TIME_INFINITE: zx_time_t = i64::MAX; - -pub type zx_signals_t = u32; - -pub const ZX_OBJECT_SIGNAL_3: zx_signals_t = 1 << 3; - -pub const ZX_TASK_TERMINATED: zx_signals_t = ZX_OBJECT_SIGNAL_3; - -pub const ZX_RIGHT_SAME_RIGHTS: zx_rights_t = 1 << 31; - -// The upper four bits gives the minor version. -pub type zx_object_info_topic_t = u32; - -pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); - -pub type zx_info_process_flags_t = u32; - -pub fn zx_cvt(t: T) -> io::Result -where - T: TryInto + Copy, -{ - if let Ok(status) = TryInto::try_into(t) { - if status < 0 { Err(io::Error::from_raw_os_error(status)) } else { Ok(t) } - } else { - Err(io::Error::last_os_error()) - } +unsafe extern "C" { + pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t; } -// Safe wrapper around zx_handle_t +/// A safe wrapper around `zx_handle_t`. pub struct Handle { raw: zx_handle_t, } @@ -65,6 +52,66 @@ impl Drop for Handle { } } +/////////// +// Futex // +/////////// + +pub type zx_futex_t = crate::sync::atomic::Atomic; + +unsafe extern "C" { + pub fn zx_object_wait_one( + handle: zx_handle_t, + signals: zx_signals_t, + timeout: zx_time_t, + pending: *mut zx_signals_t, + ) -> zx_status_t; + + pub fn zx_futex_wait( + value_ptr: *const zx_futex_t, + current_value: zx_futex_t, + new_futex_owner: zx_handle_t, + deadline: zx_time_t, + ) -> zx_status_t; + pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; + pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; + pub safe fn zx_thread_self() -> zx_handle_t; +} + +//////////////// +// Properties // +//////////////// + +pub const ZX_PROP_NAME: u32 = 3; + +unsafe extern "C" { + pub fn zx_object_set_property( + handle: zx_handle_t, + property: u32, + value: *const libc::c_void, + value_size: libc::size_t, + ) -> zx_status_t; +} + +///////////// +// Signals // +///////////// + +pub type zx_signals_t = u32; + +pub const ZX_OBJECT_SIGNAL_3: zx_signals_t = 1 << 3; +pub const ZX_TASK_TERMINATED: zx_signals_t = ZX_OBJECT_SIGNAL_3; + +///////////////// +// Object info // +///////////////// + +// The upper four bits gives the minor version. +pub type zx_object_info_topic_t = u32; + +pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); + +pub type zx_info_process_flags_t = u32; + // Returned for topic ZX_INFO_PROCESS #[derive(Default)] #[repr(C)] @@ -76,25 +123,6 @@ pub struct zx_info_process_t { } unsafe extern "C" { - pub fn zx_job_default() -> zx_handle_t; - - pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_duplicate( - handle: zx_handle_t, - rights: zx_rights_t, - out: *const zx_handle_t, - ) -> zx_handle_t; - - pub fn zx_object_wait_one( - handle: zx_handle_t, - signals: zx_signals_t, - timeout: zx_time_t, - pending: *mut zx_signals_t, - ) -> zx_status_t; - pub fn zx_object_get_info( handle: zx_handle_t, topic: u32, @@ -105,6 +133,10 @@ unsafe extern "C" { ) -> zx_status_t; } +/////////////// +// Processes // +/////////////// + #[derive(Default)] #[repr(C)] pub struct fdio_spawn_action_t { @@ -130,6 +162,8 @@ unsafe extern "C" { pub fn fdio_fd_clone(fd: c_int, out_handle: *mut zx_handle_t) -> zx_status_t; pub fn fdio_fd_create(handle: zx_handle_t, fd: *mut c_int) -> zx_status_t; + + pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t; } // fdio_spawn_etc flags @@ -137,173 +171,34 @@ unsafe extern "C" { pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; -pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; pub const FDIO_SPAWN_CLONE_UTC_CLOCK: u32 = 0x0020; -pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; // fdio_spawn_etc actions -pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; -// Errors +//////////// +// Errors // +//////////// -#[allow(unused)] -pub const ERR_INTERNAL: zx_status_t = -1; +pub type zx_status_t = i32; -// ERR_NOT_SUPPORTED: The operation is not implemented, supported, -// or enabled. -#[allow(unused)] -pub const ERR_NOT_SUPPORTED: zx_status_t = -2; +pub const ZX_OK: zx_status_t = 0; +pub const ZX_ERR_NOT_SUPPORTED: zx_status_t = -2; +pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10; +pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11; +pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12; +pub const ZX_ERR_BAD_STATE: zx_status_t = -20; +pub const ZX_ERR_TIMED_OUT: zx_status_t = -21; -// ERR_NO_RESOURCES: The system was not able to allocate some resource -// needed for the operation. -#[allow(unused)] -pub const ERR_NO_RESOURCES: zx_status_t = -3; - -// ERR_NO_MEMORY: The system was not able to allocate memory needed -// for the operation. -#[allow(unused)] -pub const ERR_NO_MEMORY: zx_status_t = -4; - -// ERR_CALL_FAILED: The second phase of zx_channel_call(; did not complete -// successfully. -#[allow(unused)] -pub const ERR_CALL_FAILED: zx_status_t = -5; - -// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be -// retried. This should not be seen outside of the VDSO. -#[allow(unused)] -pub const ERR_INTERRUPTED_RETRY: zx_status_t = -6; - -// ======= Parameter errors ======= -// ERR_INVALID_ARGS: an argument is invalid, ex. null pointer -#[allow(unused)] -pub const ERR_INVALID_ARGS: zx_status_t = -10; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] -pub const ERR_BAD_HANDLE: zx_status_t = -11; - -// ERR_WRONG_TYPE: The subject of the operation is the wrong type to -// perform the operation. -// Example: Attempting a message_read on a thread handle. -#[allow(unused)] -pub const ERR_WRONG_TYPE: zx_status_t = -12; - -// ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] -pub const ERR_BAD_SYSCALL: zx_status_t = -13; - -// ERR_OUT_OF_RANGE: An argument is outside the valid range for this -// operation. -#[allow(unused)] -pub const ERR_OUT_OF_RANGE: zx_status_t = -14; - -// ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for -// this operation. -#[allow(unused)] -pub const ERR_BUFFER_TOO_SMALL: zx_status_t = -15; - -// ======= Precondition or state errors ======= -// ERR_BAD_STATE: operation failed because the current state of the -// object does not allow it, or a precondition of the operation is -// not satisfied -#[allow(unused)] -pub const ERR_BAD_STATE: zx_status_t = -20; - -// ERR_TIMED_OUT: The time limit for the operation elapsed before -// the operation completed. -#[allow(unused)] -pub const ERR_TIMED_OUT: zx_status_t = -21; - -// ERR_SHOULD_WAIT: The operation cannot be performed currently but -// potentially could succeed if the caller waits for a prerequisite -// to be satisfied, for example waiting for a handle to be readable -// or writable. -// Example: Attempting to read from a message pipe that has no -// messages waiting but has an open remote will return ERR_SHOULD_WAIT. -// Attempting to read from a message pipe that has no messages waiting -// and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] -pub const ERR_SHOULD_WAIT: zx_status_t = -22; - -// ERR_CANCELED: The in-progress operation (e.g., a wait) has been -// // canceled. -#[allow(unused)] -pub const ERR_CANCELED: zx_status_t = -23; - -// ERR_PEER_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] -pub const ERR_PEER_CLOSED: zx_status_t = -24; - -// ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] -pub const ERR_NOT_FOUND: zx_status_t = -25; - -// ERR_ALREADY_EXISTS: An object with the specified identifier -// already exists. -// Example: Attempting to create a file when a file already exists -// with that name. -#[allow(unused)] -pub const ERR_ALREADY_EXISTS: zx_status_t = -26; - -// ERR_ALREADY_BOUND: The operation failed because the named entity -// is already owned or controlled by another entity. The operation -// could succeed later if the current owner releases the entity. -#[allow(unused)] -pub const ERR_ALREADY_BOUND: zx_status_t = -27; - -// ERR_UNAVAILABLE: The subject of the operation is currently unable -// to perform the operation. -// Note: This is used when there's no direct way for the caller to -// observe when the subject will be able to perform the operation -// and should thus retry. -#[allow(unused)] -pub const ERR_UNAVAILABLE: zx_status_t = -28; - -// ======= Permission check errors ======= -// ERR_ACCESS_DENIED: The caller did not have permission to perform -// the specified operation. -#[allow(unused)] -pub const ERR_ACCESS_DENIED: zx_status_t = -30; - -// ======= Input-output errors ======= -// ERR_IO: Otherwise unspecified error occurred during I/O. -#[allow(unused)] -pub const ERR_IO: zx_status_t = -40; - -// ERR_REFUSED: The entity the I/O operation is being performed on -// rejected the operation. -// Example: an I2C device NAK'ing a transaction or a disk controller -// rejecting an invalid command. -#[allow(unused)] -pub const ERR_IO_REFUSED: zx_status_t = -41; - -// ERR_IO_DATA_INTEGRITY: The data in the operation failed an integrity -// check and is possibly corrupted. -// Example: CRC or Parity error. -#[allow(unused)] -pub const ERR_IO_DATA_INTEGRITY: zx_status_t = -42; - -// ERR_IO_DATA_LOSS: The data in the operation is currently unavailable -// and may be permanently lost. -// Example: A disk block is irrecoverably damaged. -#[allow(unused)] -pub const ERR_IO_DATA_LOSS: zx_status_t = -43; - -// Filesystem specific errors -#[allow(unused)] -pub const ERR_BAD_PATH: zx_status_t = -50; -#[allow(unused)] -pub const ERR_NOT_DIR: zx_status_t = -51; -#[allow(unused)] -pub const ERR_NOT_FILE: zx_status_t = -52; -// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. -#[allow(unused)] -pub const ERR_FILE_BIG: zx_status_t = -53; -// ERR_NO_SPACE: Filesystem or device space is exhausted. -#[allow(unused)] -pub const ERR_NO_SPACE: zx_status_t = -54; +pub fn zx_cvt(t: T) -> io::Result +where + T: TryInto + Copy, +{ + if let Ok(status) = TryInto::try_into(t) { + if status < 0 { Err(io::Error::from_raw_os_error(status)) } else { Ok(t) } + } else { + Err(io::Error::last_os_error()) + } +} diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 8d89163c42ce..c23278bdf5e5 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -254,67 +254,29 @@ pub fn futex_wake_all(futex: &Atomic) { unsafe { emscripten_futex_wake(futex, i32::MAX) }; } -#[cfg(target_os = "fuchsia")] -pub mod zircon { - pub type zx_futex_t = crate::sync::atomic::Atomic; - pub type zx_handle_t = u32; - pub type zx_status_t = i32; - pub type zx_time_t = i64; - - pub const ZX_HANDLE_INVALID: zx_handle_t = 0; - - pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX; - - pub const ZX_OK: zx_status_t = 0; - pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10; - pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11; - pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12; - pub const ZX_ERR_BAD_STATE: zx_status_t = -20; - pub const ZX_ERR_TIMED_OUT: zx_status_t = -21; - - unsafe extern "C" { - pub fn zx_clock_get_monotonic() -> zx_time_t; - pub fn zx_futex_wait( - value_ptr: *const zx_futex_t, - current_value: zx_futex_t, - new_futex_owner: zx_handle_t, - deadline: zx_time_t, - ) -> zx_status_t; - pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; - pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; - pub fn zx_thread_self() -> zx_handle_t; - } -} - #[cfg(target_os = "fuchsia")] pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) -> bool { + use super::fuchsia::*; + // Sleep forever if the timeout is longer than fits in a i64. let deadline = timeout - .and_then(|d| { - i64::try_from(d.as_nanos()) - .ok()? - .checked_add(unsafe { zircon::zx_clock_get_monotonic() }) - }) - .unwrap_or(zircon::ZX_TIME_INFINITE); + .and_then(|d| i64::try_from(d.as_nanos()).ok()?.checked_add(zx_clock_get_monotonic())) + .unwrap_or(ZX_TIME_INFINITE); unsafe { - zircon::zx_futex_wait( - futex, - core::sync::atomic::AtomicU32::new(expected), - zircon::ZX_HANDLE_INVALID, - deadline, - ) != zircon::ZX_ERR_TIMED_OUT + zx_futex_wait(futex, zx_futex_t::new(expected), ZX_HANDLE_INVALID, deadline) + != ZX_ERR_TIMED_OUT } } // Fuchsia doesn't tell us how many threads are woken up, so this always returns false. #[cfg(target_os = "fuchsia")] pub fn futex_wake(futex: &Atomic) -> bool { - unsafe { zircon::zx_futex_wake(futex, 1) }; + unsafe { super::fuchsia::zx_futex_wake(futex, 1) }; false } #[cfg(target_os = "fuchsia")] pub fn futex_wake_all(futex: &Atomic) { - unsafe { zircon::zx_futex_wake(futex, u32::MAX) }; + unsafe { super::fuchsia::zx_futex_wake(futex, u32::MAX) }; } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 4cdc2eaf0e53..afda7c65e108 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -22,23 +22,6 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; #[cfg(any(target_os = "espidf", target_os = "nuttx"))] pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used -#[cfg(target_os = "fuchsia")] -mod zircon { - type zx_handle_t = u32; - type zx_status_t = i32; - pub const ZX_PROP_NAME: u32 = 3; - - unsafe extern "C" { - pub fn zx_object_set_property( - handle: zx_handle_t, - property: u32, - value: *const libc::c_void, - value_size: libc::size_t, - ) -> zx_status_t; - pub fn zx_thread_self() -> zx_handle_t; - } -} - pub struct Thread { id: libc::pthread_t, } @@ -216,7 +199,7 @@ impl Thread { #[cfg(target_os = "fuchsia")] pub fn set_name(name: &CStr) { - use self::zircon::*; + use super::fuchsia::*; unsafe { zx_object_set_property( zx_thread_self(), diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs index 0de32ecffd4b..eb62bbd808e8 100644 --- a/library/std/src/sys/process/unix/fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -81,7 +81,7 @@ impl Command { let mut handle = ZX_HANDLE_INVALID; let status = fdio_fd_clone(target_fd, &mut handle); - if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED { + if status == ZX_ERR_INVALID_ARGS || status == ZX_ERR_NOT_SUPPORTED { // This descriptor is closed; skip it rather than generating an // error. return Ok(Default::default()); @@ -197,7 +197,7 @@ impl Process { zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut()); match status { 0 => {} // Success - x if x == ERR_TIMED_OUT => { + x if x == ZX_ERR_TIMED_OUT => { return Ok(None); } _ => { diff --git a/library/std/src/sys/sync/mutex/fuchsia.rs b/library/std/src/sys/sync/mutex/fuchsia.rs index 3d388a4564a3..cbb1926530f5 100644 --- a/library/std/src/sys/sync/mutex/fuchsia.rs +++ b/library/std/src/sys/sync/mutex/fuchsia.rs @@ -39,7 +39,7 @@ use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{Atomic, AtomicU32}; -use crate::sys::futex::zircon::{ +use crate::sys::fuchsia::{ ZX_ERR_BAD_HANDLE, ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK, ZX_TIME_INFINITE, zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, @@ -83,13 +83,13 @@ impl Mutex { #[inline] pub fn try_lock(&self) -> bool { - let thread_self = unsafe { zx_thread_self() }; + let thread_self = zx_thread_self(); self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok() } #[inline] pub fn lock(&self) { - let thread_self = unsafe { zx_thread_self() }; + let thread_self = zx_thread_self(); if let Err(state) = self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed) { From a8f7fd1d2633ce5196bd5a00882cb03fd6046067 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 5 May 2025 10:35:46 +0000 Subject: [PATCH 224/302] update `cc_detect` tests Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/cc_detect/tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index b4a1b52dd230..43d61ce02c5a 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -181,7 +181,7 @@ fn test_language_clang() { #[test] fn test_new_cc_build() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let cfg = new_cc_build(&build, target.clone()); let compiler = cfg.get_compiler(); @@ -190,7 +190,7 @@ fn test_new_cc_build() { #[test] fn test_default_compiler_wasi() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); // SAFETY: bootstrap tests run on a single thread @@ -215,7 +215,7 @@ fn test_default_compiler_wasi() { #[test] fn test_default_compiler_fallback() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut cfg = cc::Build::new(); let result = default_compiler(&mut cfg, Language::C, target, &build); @@ -224,7 +224,7 @@ fn test_default_compiler_fallback() { #[test] fn test_find_target_with_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut target_config = Target::default(); target_config.cc = Some(PathBuf::from("dummy-cc")); @@ -249,7 +249,7 @@ fn test_find_target_with_config() { #[test] fn test_find_target_without_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); build.config.target_config.clear(); find_target(&build, target.clone()); @@ -262,7 +262,7 @@ fn test_find_target_without_config() { #[test] fn test_find() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); build.targets.push(target1.clone()); From fe98130e0ff87ef16170b4f03afd5c7bbb7da573 Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 15 Apr 2025 22:09:10 -0700 Subject: [PATCH 225/302] match ergonomics for string and byte string literal patterns --- compiler/rustc_hir_typeck/src/pat.rs | 89 ++++++++++++++----- .../const-pats-do-not-mislead-inference.rs | 48 ++++++++++ ...ats-do-not-mislead-inference.stable.stderr | 44 +++++++++ tests/ui/pattern/deref-patterns/needs-gate.rs | 17 ++++ .../pattern/deref-patterns/needs-gate.stderr | 32 ++++++- tests/ui/pattern/deref-patterns/strings.rs | 20 +++-- .../ui/pattern/deref-patterns/typeck_fail.rs | 13 --- .../pattern/deref-patterns/typeck_fail.stderr | 23 +---- 8 files changed, 223 insertions(+), 63 deletions(-) create mode 100644 tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs create mode 100644 tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index ea335c7a4a7b..c96ad0749a1e 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -177,16 +177,20 @@ enum PeelKind { /// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference /// any number of `&`/`&mut` references, plus a single smart pointer. ExplicitDerefPat, - /// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer - /// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt` - /// field contains the ADT def that the pattern is a constructor for, if applicable, so that we - /// don't peel it. See [`ResolvedPat`] for more information. - Implicit { until_adt: Option }, + /// Implicitly peel references, and if `deref_patterns` is enabled, smart pointer ADTs. + Implicit { + /// The ADT the pattern is a constructor for, if applicable, so that we don't peel it. See + /// [`ResolvedPat`] for more information. + until_adt: Option, + /// The number of references at the head of the pattern's type, so we can leave that many + /// untouched. This is `1` for string literals, and `0` for most patterns. + pat_ref_layers: usize, + }, } impl AdjustMode { const fn peel_until_adt(opt_adt_def: Option) -> AdjustMode { - AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } } + AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } } } const fn peel_all() -> AdjustMode { AdjustMode::peel_until_adt(None) @@ -488,9 +492,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match pat.kind { // Peel off a `&` or `&mut` from the scrutinee type. See the examples in // `tests/ui/rfcs/rfc-2005-default-binding-mode`. - _ if let AdjustMode::Peel { .. } = adjust_mode + _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode && pat.default_binding_modes - && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() + && self.should_peel_ref(peel_kind, expected) => { debug!("inspecting {:?}", expected); @@ -665,21 +670,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. - // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. - // - // Call `resolve_vars_if_possible` here for inline const blocks. - PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { - ty::Ref(..) => AdjustMode::Pass, - _ => { - // Path patterns have already been handled, and inline const blocks currently - // aren't possible to write, so any handling for them would be untested. - if cfg!(debug_assertions) - && self.tcx.features().deref_patterns() - && !matches!(lt.kind, PatExprKind::Lit { .. }) - { - span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind); + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}` unless + // `deref_patterns` is enabled. + PatKind::Expr(lt) => { + // Path patterns have already been handled, and inline const blocks currently + // aren't possible to write, so any handling for them would be untested. + if cfg!(debug_assertions) + && self.tcx.features().deref_patterns() + && !matches!(lt.kind, PatExprKind::Lit { .. }) + { + span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind); + } + // Call `resolve_vars_if_possible` here for inline const blocks. + let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)); + // If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`. + if self.tcx.features().deref_patterns() { + let mut peeled_ty = lit_ty; + let mut pat_ref_layers = 0; + while let ty::Ref(_, inner_ty, mutbl) = *peeled_ty.kind() { + // We rely on references at the head of constants being immutable. + debug_assert!(mutbl.is_not()); + pat_ref_layers += 1; + peeled_ty = inner_ty; } - AdjustMode::peel_all() + AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: None, pat_ref_layers } } + } else { + if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() } } }, @@ -705,6 +721,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Assuming `expected` is a reference type, determine whether to peel it before matching. + fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool { + debug_assert!(expected.is_ref()); + let pat_ref_layers = match peel_kind { + PeelKind::ExplicitDerefPat => 0, + PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers, + }; + + // Most patterns don't have reference types, so we'll want to peel all references from the + // scrutinee before matching. To optimize for the common case, return early. + if pat_ref_layers == 0 { + return true; + } + debug_assert!( + self.tcx.features().deref_patterns(), + "Peeling for patterns with reference types is gated by `deref_patterns`." + ); + + // If the pattern has as many or more layers of reference as the expected type, we can match + // without peeling more, *unless* we find a smart pointer that we also need to peel. + // TODO: always peel `&mut` + let mut expected_ref_layers = 0; + while let ty::Ref(_, inner_ty, _) = *expected.kind() { + expected_ref_layers += 1; + expected = inner_ty; + } + pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected) + } + /// Determine whether `expected` is a smart pointer type that should be peeled before matching. fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool { // Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case. diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs new file mode 100644 index 000000000000..437c2ef7c651 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs @@ -0,0 +1,48 @@ +//@ revisions: stable deref_patterns +//@[deref_patterns] check-pass +//! `deref_patterns` allows string and byte string literal patterns to implicitly peel references +//! and smart pointers from the scrutinee before matching. Since strings and byte strings themselves +//! have reference types, we need to make sure we don't peel too much. By leaving the type of the +//! match scrutinee partially uninferred, these tests make sure we only peel as much as needed in +//! order to match. In particular, when peeling isn't needed, the results should be the same was +//! we'd get without `deref_patterns` enabled. + +#![cfg_attr(deref_patterns, feature(deref_patterns))] +#![cfg_attr(deref_patterns, expect(incomplete_features))] + +fn uninferred() -> T { unimplemented!() } + +// Assert type equality without allowing coercions. +trait Is {} +impl Is for T {} +fn has_type(_: impl Is) {} + +fn main() { + // We don't need to peel anything to unify the type of `x` with `&str`, so `x: &str`. + let x = uninferred(); + if let "..." = x {} + has_type::<&str>(x); + + // We don't need to peel anything to unify the type of `&x` with `&[u8; 3]`, so `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = &x {} + has_type::<[u8; 3]>(x); + + // Peeling a single `&` lets us unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = &&x {} + //[stable]~^ ERROR: mismatched types + has_type::<[u8; 3]>(x); + + // We have to peel both the `&` and the box before unifying the type of `x` with `&str`. + let x = uninferred(); + if let "..." = &Box::new(x) {} + //[stable]~^ ERROR mismatched types + has_type::<&str>(x); + + // After peeling the box, we can unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = Box::new(&x) {} + //[stable]~^ ERROR mismatched types + has_type::<[u8; 3]>(x); +} diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr new file mode 100644 index 000000000000..9dcb91311846 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr @@ -0,0 +1,44 @@ +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:33:12 + | +LL | if let b"..." = &&x {} + | ^^^^^^ --- this expression has type `&&_` + | | + | expected `&&_`, found `&[u8; 3]` + | + = note: expected reference `&&_` + found reference `&'static [u8; 3]` + +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:39:12 + | +LL | if let "..." = &Box::new(x) {} + | ^^^^^ ------------ this expression has type `&Box<_>` + | | + | expected `&Box<_>`, found `&str` + | + = note: expected reference `&Box<_>` + found reference `&'static str` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | if let "..." = &*Box::new(x) {} + | + + +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:45:12 + | +LL | if let b"..." = Box::new(&x) {} + | ^^^^^^ ------------ this expression has type `Box<&_>` + | | + | expected `Box<&_>`, found `&[u8; 3]` + | + = note: expected struct `Box<&_>` + found reference `&'static [u8; 3]` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | if let b"..." = *Box::new(&x) {} + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index 7944744ee839..5dcf69a92d3c 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -29,4 +29,21 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + + // `deref_patterns` allows string and byte string patterns to implicitly peel references. + match &"str" { + "str" => {} + //~^ ERROR: mismatched types + _ => {} + } + match &b"str" { + b"str" => {} + //~^ ERROR: mismatched types + _ => {} + } + match "str".to_owned() { + "str" => {} + //~^ ERROR: mismatched types + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index e886ca980558..55e1fa826e86 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -47,7 +47,37 @@ LL | match *(b"test" as &[u8]) { LL | b"test" => {} | ^^^^^^^ expected `[u8]`, found `&[u8; 4]` -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:35:9 + | +LL | match &"str" { + | ------ this expression has type `&&str` +LL | "str" => {} + | ^^^^^ expected `&&str`, found `&str` + | + = note: expected reference `&&_` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:40:9 + | +LL | match &b"str" { + | ------- this expression has type `&&[u8; 3]` +LL | b"str" => {} + | ^^^^^^ expected `&&[u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&&_` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:45:9 + | +LL | match "str".to_owned() { + | ---------------- this expression has type `String` +LL | "str" => {} + | ^^^^^ expected `String`, found `&str` + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs index 536e943b3f67..7d571c81e91c 100644 --- a/tests/ui/pattern/deref-patterns/strings.rs +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -14,10 +14,18 @@ fn main() { }; assert_eq!(test_actual, test_expect); - // Test string literals in explicit `deref!(_)` patterns. + // Test string literals in deref patterns. let test_actual = match test_in.to_string() { deref!("zero") => 0, - deref!("one") => 1, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test peeling references in addition to smart pointers. + let test_actual = match &test_in.to_string() { + deref!("zero") => 0, + "one" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); @@ -47,18 +55,18 @@ fn main() { }; assert_eq!(test_actual, test_expect); - // Test byte string literals used as arrays in explicit `deref!(_)` patterns. + // Test byte string literals used as arrays in deref patterns. let test_actual = match Box::new(*test_in) { deref!(b"0") => 0, - deref!(b"1") => 1, + b"1" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); - // Test byte string literals used as slices in explicit `deref!(_)` patterns. + // Test byte string literals used as slices in deref patterns. let test_actual = match test_in.to_vec() { deref!(b"0") => 0, - deref!(b"1") => 1, + b"1" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 52d84f7a34de..6ae87bb7bc36 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -2,19 +2,6 @@ #![allow(incomplete_features)] fn main() { - // FIXME(deref_patterns): fails to typecheck because string literal patterns don't peel - // references from the scrutinee. - match "foo".to_string() { - "foo" => {} - //~^ ERROR: mismatched types - _ => {} - } - match &"foo".to_string() { - "foo" => {} - //~^ ERROR: mismatched types - _ => {} - } - // Make sure we don't try implicitly dereferncing any ADT. match Some(0) { Ok(0) => {} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index e87528c1c51a..fc29caac5630 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -1,24 +1,5 @@ error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:8:9 - | -LL | match "foo".to_string() { - | ----------------- this expression has type `String` -LL | "foo" => {} - | ^^^^^ expected `String`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:13:9 - | -LL | match &"foo".to_string() { - | ------------------ this expression has type `&String` -LL | "foo" => {} - | ^^^^^ expected `&String`, found `&str` - | - = note: expected reference `&String` - found reference `&'static str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:20:9 + --> $DIR/typeck_fail.rs:7:9 | LL | match Some(0) { | ------- this expression has type `Option<{integer}>` @@ -28,6 +9,6 @@ LL | Ok(0) => {} = note: expected enum `Option<{integer}>` found enum `Result<_, _>` -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. From 17bb4bbc86c2078e8ca09e2fdf6fd380094be6d6 Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 5 May 2025 03:40:37 -0700 Subject: [PATCH 226/302] always peel `&mut`, to allow matching on `&mut str` --- compiler/rustc_hir_typeck/src/pat.rs | 13 ++++-- .../deref-patterns/byte-string-type-errors.rs | 19 +++++++++ .../byte-string-type-errors.stderr | 40 ++++++++++++++++++- .../const-pats-do-not-mislead-inference.rs | 6 +++ ...ats-do-not-mislead-inference.stable.stderr | 13 +++++- tests/ui/pattern/deref-patterns/needs-gate.rs | 9 +++++ .../pattern/deref-patterns/needs-gate.stderr | 35 +++++++++++++++- tests/ui/pattern/deref-patterns/strings.rs | 24 +++++++++++ 8 files changed, 153 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c96ad0749a1e..f9502153afdc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -740,10 +740,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // If the pattern has as many or more layers of reference as the expected type, we can match - // without peeling more, *unless* we find a smart pointer that we also need to peel. - // TODO: always peel `&mut` + // without peeling more, unless we find a smart pointer or `&mut` that we also need to peel. + // We don't treat `&` and `&mut` as interchangeable, but by peeling `&mut`s before matching, + // we can still, e.g., match on a `&mut str` with a string literal pattern. This is because + // string literal patterns may be used where `str` is expected. let mut expected_ref_layers = 0; - while let ty::Ref(_, inner_ty, _) = *expected.kind() { + while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() { + if mutbl.is_mut() { + // Mutable references can't be in the final value of constants, thus they can't be + // at the head of their types, thus we should always peel `&mut`. + return true; + } expected_ref_layers += 1; expected = inner_ty; } diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs index 64acc4748afd..fdcc6cb46111 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs @@ -33,4 +33,23 @@ fn main() { if let b"test" = *b"this array is too long" {} //~^ ERROR mismatched types //~| NOTE expected an array with a size of 22, found one with a size of 4 + + // Test matching on `&mut T`: we peel the `&mut` before applying the usual special cases. + // No special cases apply to `()`, so the "found" type is the type of the literal. + if let b"test" = &mut () {} + //~^ ERROR mismatched types + //~| NOTE expected `()`, found `&[u8; 4]` + + // If the pointee is an array or slice, the usual special cases will apply to the "found" type: + if let b"test" = &mut [] as &mut [i8] {} + //~^ ERROR mismatched type + //~| NOTE expected `[i8]`, found `[u8]` + + if let b"test" = &mut [()] {} + //~^ ERROR mismatched types + //~| NOTE expected `[(); 1]`, found `[u8; 4]` + + if let b"test" = &mut *b"this array is too long" {} + //~^ ERROR mismatched type + //~| NOTE expected an array with a size of 22, found one with a size of 4 } diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr index 0317b7209e16..046682004be7 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr @@ -47,6 +47,44 @@ LL | if let b"test" = *b"this array is too long" {} | | | expected an array with a size of 22, found one with a size of 4 -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:39:12 + | +LL | if let b"test" = &mut () {} + | ^^^^^^^ ------- this expression has type `&mut ()` + | | + | expected `()`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:44:12 + | +LL | if let b"test" = &mut [] as &mut [i8] {} + | ^^^^^^^ -------------------- this expression has type `&mut [i8]` + | | + | expected `[i8]`, found `[u8]` + | + = note: expected slice `[i8]` + found slice `[u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:48:12 + | +LL | if let b"test" = &mut [()] {} + | ^^^^^^^ --------- this expression has type `&mut [(); 1]` + | | + | expected `[(); 1]`, found `[u8; 4]` + | + = note: expected array `[(); 1]` + found array `[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:52:12 + | +LL | if let b"test" = &mut *b"this array is too long" {} + | ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]` + | | + | expected an array with a size of 22, found one with a size of 4 + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs index 437c2ef7c651..3a2531f4b95e 100644 --- a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs @@ -45,4 +45,10 @@ fn main() { if let b"..." = Box::new(&x) {} //[stable]~^ ERROR mismatched types has_type::<[u8; 3]>(x); + + // `&` and `&mut` aren't interchangeable: `&mut`s need to be peeled before unifying, like boxes: + let mut x = uninferred(); + if let "..." = &mut x {} + //[stable]~^ ERROR mismatched types + has_type::<&str>(x); } diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr index 9dcb91311846..61079718c5d5 100644 --- a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr @@ -39,6 +39,17 @@ help: consider dereferencing to access the inner value using the Deref trait LL | if let b"..." = *Box::new(&x) {} | + -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:51:12 + | +LL | if let "..." = &mut x {} + | ^^^^^ ------ this expression has type `&mut _` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static str` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index 5dcf69a92d3c..953051f7b04b 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -46,4 +46,13 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + + // `deref_patterns` allows string and byte string patterns to match on mutable references. + // See also `tests/ui/pattern/byte-string-mutability-mismatch.rs`. + if let "str" = &mut *"str".to_string() {} + //~^ ERROR mismatched types + if let b"str" = &mut b"str".clone() {} + //~^ ERROR mismatched types + if let b"str" = &mut b"str".clone()[..] {} + //~^ ERROR mismatched types } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index 55e1fa826e86..3d938a7e23fc 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -77,7 +77,40 @@ LL | match "str".to_owned() { LL | "str" => {} | ^^^^^ expected `String`, found `&str` -error: aborting due to 8 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:52:12 + | +LL | if let "str" = &mut *"str".to_string() {} + | ^^^^^ ----------------------- this expression has type `&mut str` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:54:12 + | +LL | if let b"str" = &mut b"str".clone() {} + | ^^^^^^ ------------------- this expression has type `&mut [u8; 3]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:56:12 + | +LL | if let b"str" = &mut b"str".clone()[..] {} + | ^^^^^^ ----------------------- this expression has type `&mut [u8]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs index 7d571c81e91c..fac15a9aee3d 100644 --- a/tests/ui/pattern/deref-patterns/strings.rs +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -14,6 +14,14 @@ fn main() { }; assert_eq!(test_actual, test_expect); + // Test matching on `&mut str`. + let test_actual = match &mut *test_in.to_string() { + "zero" => 0, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + // Test string literals in deref patterns. let test_actual = match test_in.to_string() { deref!("zero") => 0, @@ -55,6 +63,22 @@ fn main() { }; assert_eq!(test_actual, test_expect); + // Test matching on `&mut [u8; N]`. + let test_actual = match &mut test_in.clone() { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test matching on `&mut [u8]`. + let test_actual = match &mut test_in.clone()[..] { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + // Test byte string literals used as arrays in deref patterns. let test_actual = match Box::new(*test_in) { deref!(b"0") => 0, From 7e4f6d3a30f22aa86ffbb3a73969646e42952525 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 4 May 2025 20:36:50 -0700 Subject: [PATCH 227/302] update unstable book --- .../src/language-features/deref-patterns.md | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index 0cc7106da48f..fb6df290cc12 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -65,15 +65,26 @@ let deref!(x) = Box::new(NoCopy) else { unreachable!() }; drop::(x); ``` -Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str` -is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is -expected. This lets them be used in `deref!(_)` patterns: +Additionally, `deref_patterns` implements changes to string and byte string literal patterns, +allowing then to be used in deref patterns: ```rust # #![feature(deref_patterns)] # #![allow(incomplete_features)] -match ("test".to_string(), b"test".to_vec()) { - (deref!("test"), deref!(b"test")) => {} +match ("test".to_string(), Box::from("test"), b"test".to_vec()) { + ("test", "test", b"test") => {} + _ => panic!(), +} + +// This works through multiple layers of reference and smart pointer: +match (&Box::new(&"test".to_string()), &&&"test") { + ("test", "test") => {} + _ => panic!(), +} + +// `deref!("...")` syntax may also be used: +match "test".to_string() { + deref!("test") => {} _ => panic!(), } @@ -82,10 +93,16 @@ match *"test" { "test" => {} _ => panic!(), } +match *b"test" { + b"test" => {} + _ => panic!(), +} +match *(b"test" as &[u8]) { + b"test" => {} + _ => panic!(), +} ``` -Implicit deref pattern syntax is not yet supported for string or byte string literals. - [`box_patterns`]: ./box-patterns.md [`string_deref_patterns`]: ./string-deref-patterns.md [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors From 3f0d24ad4c82df2bb1fb6d6ffde52d5a701b3316 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 May 2025 13:49:07 +0200 Subject: [PATCH 228/302] move tests that are identical between SB and TB to shared files --- .../2phase.rs | 43 +-- .../pass/both_borrows/basic_aliasing_model.rs | 272 +++++++++++++++++ .../interior_mutability.rs | 35 ++- .../stacked-borrows/interior_mutability.rs | 176 ----------- .../pass/stacked-borrows/stacked-borrows.rs | 279 ++---------------- .../stacked-borrows/stacked-borrows.stderr | 1 - .../pass/tree_borrows/2phase-interiormut.rs | 27 -- .../tests/pass/tree_borrows/tree-borrows.rs | 257 +--------------- 8 files changed, 326 insertions(+), 764 deletions(-) rename src/tools/miri/tests/pass/{stacked-borrows => both_borrows}/2phase.rs (63%) create mode 100644 src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs rename src/tools/miri/tests/pass/{tree_borrows => both_borrows}/interior_mutability.rs (85%) delete mode 100644 src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs delete mode 100644 src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr delete mode 100644 src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs b/src/tools/miri/tests/pass/both_borrows/2phase.rs similarity index 63% rename from src/tools/miri/tests/pass/stacked-borrows/2phase.rs rename to src/tools/miri/tests/pass/both_borrows/2phase.rs index fb4ba6058373..c53ae4cbd0ea 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs +++ b/src/tools/miri/tests/pass/both_borrows/2phase.rs @@ -1,3 +1,6 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + // FIXME: this miscompiles with optimizations, see . //@compile-flags: -Zmir-opt-level=0 @@ -59,52 +62,12 @@ fn two_phase_overlapping2() { x.add_assign(x + *l); } -fn with_interior_mutability() { - use std::cell::Cell; - - trait Thing: Sized { - fn do_the_thing(&mut self, _s: i32) {} - } - - impl Thing for Cell {} - - let mut x = Cell::new(1); - let l = &x; - - x.do_the_thing({ - x.set(3); - l.set(4); - x.get() + l.get() - }); -} - -// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it. -// Tree Borrows rejects it. -fn aliasing_violation() { - struct Foo(u64); - impl Foo { - fn add(&mut self, n: u64) -> u64 { - self.0 + n - } - } - - let mut f = Foo(0); - let alias = &mut f.0 as *mut u64; - let res = f.add(unsafe { - *alias = 42; - 0 - }); - assert_eq!(res, 42); -} - fn main() { two_phase1(); two_phase2(); two_phase3(false); two_phase3(true); two_phase_raw(); - with_interior_mutability(); two_phase_overlapping1(); two_phase_overlapping2(); - aliasing_violation(); } diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs new file mode 100644 index 000000000000..c2b6a7e68be5 --- /dev/null +++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs @@ -0,0 +1,272 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(allocator_api)] +use std::ptr; + +// Test various aliasing-model-related things. +fn main() { + read_does_not_invalidate1(); + read_does_not_invalidate2(); + mut_raw_then_mut_shr(); + mut_shr_then_mut_raw(); + mut_raw_mut(); + partially_invalidate_mut(); + drop_after_sharing(); + // direct_mut_to_const_raw(); + two_raw(); + shr_and_raw(); + disjoint_mutable_subborrows(); + raw_ref_to_part(); + array_casts(); + mut_below_shr(); + wide_raw_ptr_in_tuple(); + not_unpin_not_protected(); + write_does_not_invalidate_all_aliases(); + box_into_raw_allows_interior_mutable_alias(); +} + +// Make sure that reading from an `&mut` does, like reborrowing to `&`, +// NOT invalidate other reborrows. +fn read_does_not_invalidate1() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &(*xraw).1 }; + let _val = x.1; // we just read, this does NOT invalidate the reborrows. + ret + } + assert_eq!(*foo(&mut (1, 2)), 2); +} +// Same as above, but this time we first create a raw, then read from `&mut` +// and then freeze from the raw. +fn read_does_not_invalidate2() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. + let ret = unsafe { &(*xraw).1 }; + ret + } + assert_eq!(*foo(&mut (1, 2)), 2); +} + +// Escape a mut to raw, then share the same mut and use the share, then the raw. +// That should work. +fn mut_raw_then_mut_shr() { + let mut x = 2; + let xref = &mut x; + let xraw = &mut *xref as *mut _; + let xshr = &*xref; + assert_eq!(*xshr, 2); + unsafe { + *xraw = 4; + } + assert_eq!(x, 4); +} + +// Create first a shared reference and then a raw pointer from a `&mut` +// should permit mutation through that raw pointer. +fn mut_shr_then_mut_raw() { + let xref = &mut 2; + let _xshr = &*xref; + let xraw = xref as *mut _; + unsafe { + *xraw = 3; + } + assert_eq!(*xref, 3); +} + +// Ensure that if we derive from a mut a raw, and then from that a mut, +// and then read through the original mut, that does not invalidate the raw. +// This shows that the read-exception for `&mut` applies even if the `Shr` item +// on the stack is not at the top. +fn mut_raw_mut() { + let mut x = 2; + { + let xref1 = &mut x; + let xraw = xref1 as *mut _; + let _xref2 = unsafe { &mut *xraw }; + let _val = *xref1; + unsafe { + *xraw = 4; + } + // we can now use both xraw and xref1, for reading + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs` + } + assert_eq!(x, 4); +} + +fn partially_invalidate_mut() { + let data = &mut (0u8, 0u8); + let reborrow = &mut *data as *mut (u8, u8); + let shard = unsafe { &mut (*reborrow).0 }; + data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. + *shard += 1; // so we can still use `shard`. + assert_eq!(*data, (1, 1)); +} + +// Make sure that we can handle the situation where a location is frozen when being dropped. +fn drop_after_sharing() { + let x = String::from("hello!"); + let _len = x.len(); +} + +// Make sure that we can create two raw pointers from a mutable reference and use them both. +fn two_raw() { + unsafe { + let x = &mut 0; + let y1 = x as *mut _; + let y2 = x as *mut _; + *y1 += 2; + *y2 += 1; + } +} + +// Make sure that creating a *mut does not invalidate existing shared references. +fn shr_and_raw() { + unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y1; + *y2 += 1; + } +} + +fn disjoint_mutable_subborrows() { + struct Foo { + a: String, + b: Vec, + } + + unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { + &mut (*this).a + } + + unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { + &mut (*this).b + } + + let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; + + let ptr = &mut foo as *mut Foo; + + let a = unsafe { borrow_field_a(ptr) }; + let b = unsafe { borrow_field_b(ptr) }; + b.push(4); + a.push_str(" world"); + assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#); +} + +fn raw_ref_to_part() { + struct Part { + _lame: i32, + } + + #[repr(C)] + struct Whole { + part: Part, + extra: i32, + } + + let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); + let whole = ptr::addr_of_mut!(*Box::leak(it)); + let part = unsafe { ptr::addr_of_mut!((*whole).part) }; + let typed = unsafe { &mut *(part as *mut Whole) }; + assert!(typed.extra == 42); + drop(unsafe { Box::from_raw(whole) }); +} + +/// When casting an array reference to a raw element ptr, that should cover the whole array. +fn array_casts() { + let mut x: [usize; 2] = [0, 0]; + let p = &mut x as *mut usize; + unsafe { + *p.add(1) = 1; + } + + let x: [usize; 2] = [0, 1]; + let p = &x as *const usize; + assert_eq!(unsafe { *p.add(1) }, 1); +} + +/// Transmuting &&i32 to &&mut i32 is fine. +fn mut_below_shr() { + let x = 0; + let y = &x; + let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; + let r = &**p; + let _val = *r; +} + +fn wide_raw_ptr_in_tuple() { + let mut x: Box = Box::new("ouch"); + let r = &mut *x as *mut dyn std::any::Any; + // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw + // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and + // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. + let pair = (r, &0); + let r = unsafe { &mut *pair.0 }; + // Make sure the fn ptr part of the vtable is still fine. + r.type_id(); +} + +fn not_unpin_not_protected() { + // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also + // don't add protectors. (We could, but until we have a better idea for where we want to go with + // the self-referential-coroutine situation, it does not seem worth the potential trouble.) + use std::marker::PhantomPinned; + + pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned); + + fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { + // `f` is allowed to deallocate `x`. + f(x) + } + + inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { + let raw = x as *mut _; + drop(unsafe { Box::from_raw(raw) }); + }); +} + +fn write_does_not_invalidate_all_aliases() { + mod other { + /// Some private memory to store stuff in. + static mut S: *mut i32 = 0 as *mut i32; + + pub fn lib1(x: &&mut i32) { + unsafe { + S = (x as *const &mut i32).cast::<*mut i32>().read(); + } + } + + pub fn lib2() { + unsafe { + *S = 1337; + } + } + } + + let x = &mut 0; + other::lib1(&x); + *x = 42; // a write to x -- invalidates other pointers? + other::lib2(); + assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated +} + +fn box_into_raw_allows_interior_mutable_alias() { + unsafe { + let b = Box::new(std::cell::Cell::new(42)); + let raw = Box::into_raw(b); + let c = &*raw; + let d = raw.cast::(); // bypassing `Cell` -- only okay in Miri tests + // `c` and `d` should permit arbitrary aliasing with each other now. + *d = 1; + c.set(2); + drop(Box::from_raw(raw)); + } +} diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs similarity index 85% rename from src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs rename to src/tools/miri/tests/pass/both_borrows/interior_mutability.rs index 50d745fa363f..f095e215e004 100644 --- a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs @@ -1,5 +1,7 @@ -//@compile-flags: -Zmiri-tree-borrows +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![allow(dangerous_implicit_autorefs)] + use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; @@ -14,6 +16,7 @@ fn main() { ref_protector(); ref_mut_protector(); rust_issue_68303(); + two_phase(); } fn aliasing_mut_and_shr() { @@ -101,13 +104,15 @@ fn unsafe_cell_invalidate() { let raw1 = &mut x as *mut _; let ref1 = unsafe { &mut *raw1 }; let raw2 = ref1 as *mut _; - // Now the borrow tree is: + // Now the borrow stack is: raw1, ref2, raw2. + // + // For TB, the tree is // // Act x // Res `- raw1 // Res `- ref1, raw2 // - // So using raw1 invalidates raw2. + // Either way, using raw1 invalidates raw2. f(unsafe { mem::transmute(raw2) }, raw1); } @@ -179,3 +184,27 @@ fn rust_issue_68303() { assert!(optional.is_some()); *handle = true; } + +fn two_phase() { + use std::cell::Cell; + + trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} + } + + impl Thing for Cell {} + + let mut x = Cell::new(1); + let l = &x; + + x.do_the_thing({ + // In TB terms: + // Several Foreign accesses (both Reads and Writes) to the location + // being reborrowed. Reserved + unprotected + interior mut + // makes the pointer immune to everything as long as all accesses + // are child accesses to its parent pointer x. + x.set(3); + l.set(4); + x.get() + l.get() + }); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs deleted file mode 100644 index e86cb3711acb..000000000000 --- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs +++ /dev/null @@ -1,176 +0,0 @@ -#![allow(dangerous_implicit_autorefs)] - -use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; -use std::mem::{self, MaybeUninit}; - -fn main() { - aliasing_mut_and_shr(); - aliasing_frz_and_shr(); - into_interior_mutability(); - unsafe_cell_2phase(); - unsafe_cell_deallocate(); - unsafe_cell_invalidate(); - refcell_basic(); - ref_protector(); - ref_mut_protector(); - rust_issue_68303(); -} - -fn aliasing_mut_and_shr() { - fn inner(rc: &RefCell, aliasing: &mut i32) { - *aliasing += 4; - let _escape_to_raw = rc as *const _; - *aliasing += 4; - let _shr = &*rc; - *aliasing += 4; - // also turning this into a frozen ref now must work - let aliasing = &*aliasing; - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let mut bmut = rc.borrow_mut(); - inner(&rc, &mut *bmut); - drop(bmut); - assert_eq!(*rc.borrow(), 23 + 12); -} - -fn aliasing_frz_and_shr() { - fn inner(rc: &RefCell, aliasing: &i32) { - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let bshr = rc.borrow(); - inner(&rc, &*bshr); - assert_eq!(*rc.borrow(), 23); -} - -// Getting a pointer into a union with interior mutability used to be tricky -// business (https://github.com/rust-lang/miri/issues/615), but it should work -// now. -fn into_interior_mutability() { - let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); - x.as_ptr(); - x.write((Cell::new(0), 1)); - let ptr = unsafe { x.assume_init_ref() }; - assert_eq!(ptr.1, 1); -} - -// Two-phase borrows of the pointer returned by UnsafeCell::get() should not -// invalidate aliases. -fn unsafe_cell_2phase() { - unsafe { - let x = &UnsafeCell::new(vec![]); - let x2 = &*x; - (*x.get()).push(0); - let _val = (*x2.get()).get(0); - } -} - -/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call. -/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.) -fn unsafe_cell_deallocate() { - fn f(x: &UnsafeCell) { - let b: Box = unsafe { Box::from_raw(x as *const _ as *mut i32) }; - drop(b) - } - - let b = Box::new(0i32); - f(unsafe { mem::transmute(Box::into_raw(b)) }); -} - -/// As a side-effect of the above, we also allow this -- at least for now. -fn unsafe_cell_invalidate() { - fn f(_x: &UnsafeCell, y: *mut i32) { - // Writing to y invalidates x, but that is okay. - unsafe { - *y += 1; - } - } - - let mut x = 0i32; - let raw1 = &mut x as *mut _; - let ref1 = unsafe { &mut *raw1 }; - let raw2 = ref1 as *mut _; - // Now the borrow stack is: raw1, ref2, raw2. - // So using raw1 invalidates raw2. - f(unsafe { mem::transmute(raw2) }, raw1); -} - -fn refcell_basic() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} - -// Adding a Stacked Borrows protector for `Ref` would break this -fn ref_protector() { - fn break_it(rc: &RefCell, r: Ref<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as read-only for the entire - // duration of this function. - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow()) -} - -fn ref_mut_protector() { - fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as inaccessible for the entire - // duration of this function - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow_mut()) -} - -/// Make sure we do not have bad enum layout optimizations. -fn rust_issue_68303() { - let optional = Some(RefCell::new(false)); - let mut handle = optional.as_ref().unwrap().borrow_mut(); - assert!(optional.is_some()); - *handle = true; -} diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs index 4261f411eea4..3620f1536fb9 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,100 +1,9 @@ -#![feature(allocator_api)] -use std::ptr; - -// Test various stacked-borrows-related things. +// Test various stacked-borrows-specific things +// (i.e., these do not work the same under TB). fn main() { - read_does_not_invalidate1(); - read_does_not_invalidate2(); - mut_raw_then_mut_shr(); - mut_shr_then_mut_raw(); - mut_raw_mut(); mut_raw_mut2(); - partially_invalidate_mut(); - drop_after_sharing(); // direct_mut_to_const_raw(); - two_raw(); - shr_and_raw(); - disjoint_mutable_subborrows(); - raw_ref_to_part(); - array_casts(); - mut_below_shr(); - wide_raw_ptr_in_tuple(); - not_unpin_not_protected(); - write_does_not_invalidate_all_aliases(); - box_into_raw_allows_interior_mutable_alias(); -} - -// Make sure that reading from an `&mut` does, like reborrowing to `&`, -// NOT invalidate other reborrows. -fn read_does_not_invalidate1() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let ret = unsafe { &(*xraw).1 }; - let _val = x.1; // we just read, this does NOT invalidate the reborrows. - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} -// Same as above, but this time we first create a raw, then read from `&mut` -// and then freeze from the raw. -fn read_does_not_invalidate2() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. - let ret = unsafe { &(*xraw).1 }; - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} - -// Escape a mut to raw, then share the same mut and use the share, then the raw. -// That should work. -fn mut_raw_then_mut_shr() { - let mut x = 2; - let xref = &mut x; - let xraw = &mut *xref as *mut _; - let xshr = &*xref; - assert_eq!(*xshr, 2); - unsafe { - *xraw = 4; - } - assert_eq!(x, 4); -} - -// Create first a shared reference and then a raw pointer from a `&mut` -// should permit mutation through that raw pointer. -fn mut_shr_then_mut_raw() { - let xref = &mut 2; - let _xshr = &*xref; - let xraw = xref as *mut _; - unsafe { - *xraw = 3; - } - assert_eq!(*xref, 3); -} - -// Ensure that if we derive from a mut a raw, and then from that a mut, -// and then read through the original mut, that does not invalidate the raw. -// This shows that the read-exception for `&mut` applies even if the `Shr` item -// on the stack is not at the top. -fn mut_raw_mut() { - let mut x = 2; - { - let xref1 = &mut x; - let xraw = xref1 as *mut _; - let _xref2 = unsafe { &mut *xraw }; - let _val = *xref1; - unsafe { - *xraw = 4; - } - // we can now use both xraw and xref1, for reading - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs` - } - assert_eq!(x, 4); + two_phase_aliasing_violation(); } // A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows. @@ -109,21 +18,6 @@ fn mut_raw_mut2() { } } -fn partially_invalidate_mut() { - let data = &mut (0u8, 0u8); - let reborrow = &mut *data as *mut (u8, u8); - let shard = unsafe { &mut (*reborrow).0 }; - data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. - *shard += 1; // so we can still use `shard`. - assert_eq!(*data, (1, 1)); -} - -// Make sure that we can handle the situation where a location is frozen when being dropped. -fn drop_after_sharing() { - let x = String::from("hello!"); - let _len = x.len(); -} - // Make sure that coercing &mut T to *const T produces a writeable pointer. // TODO: This is currently disabled, waiting on a decision on /*fn direct_mut_to_const_raw() { @@ -133,160 +27,21 @@ fn drop_after_sharing() { assert_eq!(*x, 1); }*/ -// Make sure that we can create two raw pointers from a mutable reference and use them both. -fn two_raw() { - unsafe { - let x = &mut 0; - let y1 = x as *mut _; - let y2 = x as *mut _; - *y1 += 2; - *y2 += 1; - } -} - -// Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { - unsafe { - use std::mem; - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y1; - *y2 += 1; - } -} - -fn disjoint_mutable_subborrows() { - struct Foo { - a: String, - b: Vec, +// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it. +// Tree Borrows rejects it. +fn two_phase_aliasing_violation() { + struct Foo(u64); + impl Foo { + fn add(&mut self, n: u64) -> u64 { + self.0 + n + } } - unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { - &mut (*this).a - } - - unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { - &mut (*this).b - } - - let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; - - let ptr = &mut foo as *mut Foo; - - let a = unsafe { borrow_field_a(ptr) }; - let b = unsafe { borrow_field_b(ptr) }; - b.push(4); - a.push_str(" world"); - eprintln!("{:?} {:?}", a, b); -} - -fn raw_ref_to_part() { - struct Part { - _lame: i32, - } - - #[repr(C)] - struct Whole { - part: Part, - extra: i32, - } - - let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); - let whole = ptr::addr_of_mut!(*Box::leak(it)); - let part = unsafe { ptr::addr_of_mut!((*whole).part) }; - let typed = unsafe { &mut *(part as *mut Whole) }; - assert!(typed.extra == 42); - drop(unsafe { Box::from_raw(whole) }); -} - -/// When casting an array reference to a raw element ptr, that should cover the whole array. -fn array_casts() { - let mut x: [usize; 2] = [0, 0]; - let p = &mut x as *mut usize; - unsafe { - *p.add(1) = 1; - } - - let x: [usize; 2] = [0, 1]; - let p = &x as *const usize; - assert_eq!(unsafe { *p.add(1) }, 1); -} - -/// Transmuting &&i32 to &&mut i32 is fine. -fn mut_below_shr() { - let x = 0; - let y = &x; - let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; - let r = &**p; - let _val = *r; -} - -fn wide_raw_ptr_in_tuple() { - let mut x: Box = Box::new("ouch"); - let r = &mut *x as *mut dyn std::any::Any; - // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw - // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and - // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. - let pair = (r, &0); - let r = unsafe { &mut *pair.0 }; - // Make sure the fn ptr part of the vtable is still fine. - r.type_id(); -} - -fn not_unpin_not_protected() { - // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also - // don't add protectors. (We could, but until we have a better idea for where we want to go with - // the self-referential-coroutine situation, it does not seem worth the potential trouble.) - use std::marker::PhantomPinned; - - pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned); - - fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { - // `f` may mutate, but it may not deallocate! - f(x) - } - - inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { - let raw = x as *mut _; - drop(unsafe { Box::from_raw(raw) }); + let mut f = Foo(0); + let alias = &mut f.0 as *mut u64; + let res = f.add(unsafe { + *alias = 42; + 0 }); -} - -fn write_does_not_invalidate_all_aliases() { - mod other { - /// Some private memory to store stuff in. - static mut S: *mut i32 = 0 as *mut i32; - - pub fn lib1(x: &&mut i32) { - unsafe { - S = (x as *const &mut i32).cast::<*mut i32>().read(); - } - } - - pub fn lib2() { - unsafe { - *S = 1337; - } - } - } - - let x = &mut 0; - other::lib1(&x); - *x = 42; // a write to x -- invalidates other pointers? - other::lib2(); - assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated -} - -fn box_into_raw_allows_interior_mutable_alias() { - unsafe { - let b = Box::new(std::cell::Cell::new(42)); - let raw = Box::into_raw(b); - let c = &*raw; - let d = raw.cast::(); // bypassing `Cell` -- only okay in Miri tests - // `c` and `d` should permit arbitrary aliasing with each other now. - *d = 1; - c.set(2); - drop(Box::from_raw(raw)); - } + assert_eq!(res, 42); } diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr deleted file mode 100644 index 8ee4e25dbef8..000000000000 --- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr +++ /dev/null @@ -1 +0,0 @@ -"hello world" [0, 1, 2, 4] diff --git a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs deleted file mode 100644 index af52f53791a4..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@compile-flags: -Zmiri-tree-borrows - -// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs, -// this is the opposite situation: the Write is not problematic because -// the Protector has not yet been added and the Reserved has interior -// mutability. -use core::cell::Cell; - -trait Thing: Sized { - fn do_the_thing(&mut self, _s: i32) {} -} -impl Thing for Cell {} - -fn main() { - let mut x = Cell::new(1); - let l = &x; - - x.do_the_thing({ - // Several Foreign accesses (both Reads and Writes) to the location - // being reborrowed. Reserved + unprotected + interior mut - // makes the pointer immune to everything as long as all accesses - // are child accesses to its parent pointer x. - x.set(3); - l.set(4); - x.get() + l.get() - }); -} diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs index eddcb7b12185..87eb447049d6 100644 --- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs +++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs @@ -3,6 +3,8 @@ use std::{mem, ptr}; +// Test various tree-borrows-specific things +// (i.e., these do not work the same under SB). fn main() { aliasing_read_only_mutable_refs(); string_as_mut_ptr(); @@ -10,24 +12,6 @@ fn main() { direct_mut_to_const_raw(); local_addr_of_mut(); returned_mut_is_usable(); - - // Stacked Borrows tests - read_does_not_invalidate1(); - read_does_not_invalidate2(); - mut_raw_then_mut_shr(); - mut_shr_then_mut_raw(); - mut_raw_mut(); - partially_invalidate_mut(); - drop_after_sharing(); - two_raw(); - shr_and_raw(); - disjoint_mutable_subborrows(); - raw_ref_to_part(); - array_casts(); - mut_below_shr(); - wide_raw_ptr_in_tuple(); - not_unpin_not_protected(); - write_does_not_invalidate_all_aliases(); } #[allow(unused_assignments)] @@ -109,96 +93,6 @@ fn returned_mut_is_usable() { *y = 1; } -// ----- The tests below were taken from Stacked Borrows ---- - -// Make sure that reading from an `&mut` does, like reborrowing to `&`, -// NOT invalidate other reborrows. -fn read_does_not_invalidate1() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let ret = unsafe { &(*xraw).1 }; - let _val = x.1; // we just read, this does NOT invalidate the reborrows. - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} -// Same as above, but this time we first create a raw, then read from `&mut` -// and then freeze from the raw. -fn read_does_not_invalidate2() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. - let ret = unsafe { &(*xraw).1 }; - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} - -// Escape a mut to raw, then share the same mut and use the share, then the raw. -// That should work. -fn mut_raw_then_mut_shr() { - let mut x = 2; - let xref = &mut x; - let xraw = &mut *xref as *mut _; - let xshr = &*xref; - assert_eq!(*xshr, 2); - unsafe { - *xraw = 4; - } - assert_eq!(x, 4); -} - -// Create first a shared reference and then a raw pointer from a `&mut` -// should permit mutation through that raw pointer. -fn mut_shr_then_mut_raw() { - let xref = &mut 2; - let _xshr = &*xref; - let xraw = xref as *mut _; - unsafe { - *xraw = 3; - } - assert_eq!(*xref, 3); -} - -// Ensure that if we derive from a mut a raw, and then from that a mut, -// and then read through the original mut, that does not invalidate the raw. -// This shows that the read-exception for `&mut` applies even if the `Shr` item -// on the stack is not at the top. -fn mut_raw_mut() { - let mut x = 2; - { - let xref1 = &mut x; - let xraw = xref1 as *mut _; - let _xref2 = unsafe { &mut *xraw }; - let _val = *xref1; - unsafe { - *xraw = 4; - } - // we can now use both xraw and xref1, for reading - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs` - } - assert_eq!(x, 4); -} - -fn partially_invalidate_mut() { - let data = &mut (0u8, 0u8); - let reborrow = &mut *data as *mut (u8, u8); - let shard = unsafe { &mut (*reborrow).0 }; - data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. - *shard += 1; // so we can still use `shard`. - assert_eq!(*data, (1, 1)); -} - -// Make sure that we can handle the situation where a location is frozen when being dropped. -fn drop_after_sharing() { - let x = String::from("hello!"); - let _len = x.len(); -} - // Make sure that coercing &mut T to *const T produces a writeable pointer. fn direct_mut_to_const_raw() { let x = &mut 0; @@ -208,150 +102,3 @@ fn direct_mut_to_const_raw() { } assert_eq!(*x, 1); } - -// Make sure that we can create two raw pointers from a mutable reference and use them both. -fn two_raw() { - unsafe { - let x = &mut 0; - let y1 = x as *mut _; - let y2 = x as *mut _; - *y1 += 2; - *y2 += 1; - } -} - -// Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { - unsafe { - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y1; - *y2 += 1; - } -} - -fn disjoint_mutable_subborrows() { - struct Foo { - a: String, - b: Vec, - } - - unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { - &mut (*this).a - } - - unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { - &mut (*this).b - } - - let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; - - let ptr = &mut foo as *mut Foo; - - let a = unsafe { borrow_field_a(ptr) }; - let b = unsafe { borrow_field_b(ptr) }; - b.push(4); - a.push_str(" world"); - assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#); -} - -fn raw_ref_to_part() { - struct Part { - _lame: i32, - } - - #[repr(C)] - struct Whole { - part: Part, - extra: i32, - } - - let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); - let whole = ptr::addr_of_mut!(*Box::leak(it)); - let part = unsafe { ptr::addr_of_mut!((*whole).part) }; - let typed = unsafe { &mut *(part as *mut Whole) }; - assert!(typed.extra == 42); - drop(unsafe { Box::from_raw(whole) }); -} - -/// When casting an array reference to a raw element ptr, that should cover the whole array. -fn array_casts() { - let mut x: [usize; 2] = [0, 0]; - let p = &mut x as *mut usize; - unsafe { - *p.add(1) = 1; - } - - let x: [usize; 2] = [0, 1]; - let p = &x as *const usize; - assert_eq!(unsafe { *p.add(1) }, 1); -} - -/// Transmuting &&i32 to &&mut i32 is fine. -fn mut_below_shr() { - let x = 0; - let y = &x; - let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; - let r = &**p; - let _val = *r; -} - -fn wide_raw_ptr_in_tuple() { - let mut x: Box = Box::new("ouch"); - let r = &mut *x as *mut dyn std::any::Any; - // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw - // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and - // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. - let pair = (r, &0); - let r = unsafe { &mut *pair.0 }; - // Make sure the fn ptr part of the vtable is still fine. - r.type_id(); -} - -fn not_unpin_not_protected() { - // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also - // don't add protectors. (We could, but until we have a better idea for where we want to go with - // the self-referential-coroutine situation, it does not seem worth the potential trouble.) - use std::marker::PhantomPinned; - - pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned); - - fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { - // `f` is allowed to deallocate `x`. - f(x) - } - - inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { - let raw = x as *mut _; - drop(unsafe { Box::from_raw(raw) }); - }); -} - -fn write_does_not_invalidate_all_aliases() { - // In TB there are other ways to do that (`addr_of!(*x)` has the same tag as `x`), - // but let's still make sure this SB test keeps working. - - mod other { - /// Some private memory to store stuff in. - static mut S: *mut i32 = 0 as *mut i32; - - pub fn lib1(x: &&mut i32) { - unsafe { - S = (x as *const &mut i32).cast::<*mut i32>().read(); - } - } - - pub fn lib2() { - unsafe { - *S = 1337; - } - } - } - - let x = &mut 0; - other::lib1(&x); - *x = 42; // a write to x -- invalidates other pointers? - other::lib2(); - assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated -} From 4b58c5034a59f58b9ba1a713a667b4d9ffc1df34 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 5 May 2025 12:34:22 +0000 Subject: [PATCH 229/302] Make -Zfixed-x18 into a target modifier --- compiler/rustc_session/src/options.rs | 2 +- .../ui/target_modifiers/auxiliary/fixed_x18.rs | 7 +++++++ ...incompatible_fixedx18.error_generated.stderr | 13 +++++++++++++ .../target_modifiers/incompatible_fixedx18.rs | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/target_modifiers/auxiliary/fixed_x18.rs create mode 100644 tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr create mode 100644 tests/ui/target_modifiers/incompatible_fixedx18.rs diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5f4695fb1841..c3d922fc9c5e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2208,7 +2208,7 @@ options! { fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), - fixed_x18: bool = (false, parse_bool, [TRACKED], + fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], "make the x18 register reserved on AArch64 (default: no)"), flatten_format_args: bool = (true, parse_bool, [TRACKED], "flatten nested format_args!() and literals into a simplified format_args!() call \ diff --git a/tests/ui/target_modifiers/auxiliary/fixed_x18.rs b/tests/ui/target_modifiers/auxiliary/fixed_x18.rs new file mode 100644 index 000000000000..32eff76ec54c --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/fixed_x18.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target aarch64-unknown-none -Zfixed-x18 +//@ needs-llvm-components: aarch64 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr b/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr new file mode 100644 index 000000000000..096d7cb5f258 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zfixed-x18` will cause an ABI mismatch in crate `incompatible_fixedx18` + --> $DIR/incompatible_fixedx18.rs:12:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zfixed-x18` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zfixed-x18` in this crate is incompatible with `-Zfixed-x18=` in dependency `fixed_x18` + = help: set `-Zfixed-x18=` in this crate or unset `-Zfixed-x18` in `fixed_x18` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=fixed-x18` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.rs b/tests/ui/target_modifiers/incompatible_fixedx18.rs new file mode 100644 index 000000000000..6c13984f608e --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_fixedx18.rs @@ -0,0 +1,17 @@ +//@ aux-build:fixed_x18.rs +//@ compile-flags: --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 + +//@ revisions:allow_match allow_mismatch error_generated +//@[allow_match] compile-flags: -Zfixed-x18 +//@[allow_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=fixed-x18 +//@[error_generated] compile-flags: +//@[allow_mismatch] check-pass +//@[allow_match] check-pass + +#![feature(no_core)] +//[error_generated]~^ ERROR mixing `-Zfixed-x18` will cause an ABI mismatch in crate `incompatible_fixedx18` +#![crate_type = "rlib"] +#![no_core] + +extern crate fixed_x18; From aec861b5ae620d15b7885a56236a02a7a41893b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 May 2025 13:50:01 +0200 Subject: [PATCH 230/302] consistent folder naming: stacked-borrows -> stacked_borrows --- src/tools/miri/tests/pass/both_borrows/2phase.rs | 5 +---- .../coroutine-self-referential.rs | 0 .../pass/{stacked-borrows => stacked_borrows}/int-to-ptr.rs | 0 .../{stacked-borrows => stacked_borrows}/issue-miri-2389.rs | 0 .../issue-miri-2389.stderr | 4 ++-- .../no_field_retagging.rs | 0 .../non_scalar_field_retagging.rs | 0 .../{stacked-borrows => stacked_borrows}/stack-printing.rs | 0 .../stack-printing.stdout | 0 .../{stacked-borrows => stacked_borrows}/stacked-borrows.rs | 3 +++ .../unknown-bottom-gc.rs | 0 .../zst-field-retagging-terminates.rs | 0 12 files changed, 6 insertions(+), 6 deletions(-) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/coroutine-self-referential.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/int-to-ptr.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/issue-miri-2389.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/issue-miri-2389.stderr (89%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/no_field_retagging.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/non_scalar_field_retagging.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/stack-printing.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/stack-printing.stdout (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/stacked-borrows.rs (90%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/unknown-bottom-gc.rs (100%) rename src/tools/miri/tests/pass/{stacked-borrows => stacked_borrows}/zst-field-retagging-terminates.rs (100%) diff --git a/src/tools/miri/tests/pass/both_borrows/2phase.rs b/src/tools/miri/tests/pass/both_borrows/2phase.rs index c53ae4cbd0ea..7a3962a7c1a4 100644 --- a/src/tools/miri/tests/pass/both_borrows/2phase.rs +++ b/src/tools/miri/tests/pass/both_borrows/2phase.rs @@ -1,9 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -// FIXME: this miscompiles with optimizations, see . -//@compile-flags: -Zmir-opt-level=0 - trait S: Sized { fn tpb(&mut self, _s: Self) {} } @@ -34,9 +31,9 @@ fn two_phase3(b: bool) { )); } -#[allow(unreachable_code)] fn two_phase_raw() { let x: &mut Vec = &mut vec![]; + #[allow(unreachable_code)] // The `push` itself never gets reached. x.push({ // Unfortunately this does not trigger the problem of creating a // raw ponter from a pointer that had a two-phase borrow derived from diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs rename to src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs rename to src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs rename to src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr similarity index 89% rename from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr rename to src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr index bcb7a65e90f0..8ca3c6c618ea 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> tests/pass/stacked-borrows/issue-miri-2389.rs:LL:CC + --> tests/pass/stacked_borrows/issue-miri-2389.rs:LL:CC | LL | let wildcard = &root0 as *const Cell as usize as *const Cell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,5 +10,5 @@ LL | let wildcard = &root0 as *const Cell as usize as *const Cell. +//@compile-flags: -Zmir-opt-level=0 + // Test various stacked-borrows-specific things // (i.e., these do not work the same under TB). fn main() { diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs rename to src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs rename to src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs From 5c7f1d76cb4c7fb48be758b011cb8465d7f00ae8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 May 2025 14:45:38 +0200 Subject: [PATCH 231/302] alloc_addresses: when we are running out of addresses, start reusing more aggressively --- .../miri/bench-cargo-miri/big-allocs/src/main.rs | 5 +---- src/tools/miri/src/alloc_addresses/mod.rs | 5 +++++ src/tools/miri/src/alloc_addresses/reuse_pool.rs | 15 +++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs index 5b807ac3df1f..89797c498206 100644 --- a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs +++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs @@ -7,10 +7,7 @@ fn main() { // We can't use too big of an allocation or this code will encounter an allocation failure in // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect // we're trying to measure is clearly visible above the interpreter's startup time. - // FIXME (https://github.com/rust-lang/miri/issues/4253): On 32bit targets, we can run out of - // usable addresses if we don't reuse, leading to random test failures. - let count = if cfg!(target_pointer_width = "32") { 8 } else { 12 }; - for _ in 0..count { + for _ in 0..20 { drop(Vec::::with_capacity(512 * 1024 * 1024)); } } diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 75eb0415a6f7..dd389d97cdce 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -205,6 +205,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { if global_state.next_base_addr > this.target_usize_max() { throw_exhaust!(AddressSpaceFull); } + // If we filled up more than half the address space, start aggressively reusing + // addresses to avoid running out. + if global_state.next_base_addr > u64::try_from(this.target_isize_max()).unwrap() { + global_state.reuse.address_space_shortage(); + } interp_ok(base_addr) } diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs index c0d24a9fbbcf..29d4f2bb7b0f 100644 --- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs +++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs @@ -20,7 +20,7 @@ pub struct ReusePool { /// allocations as address-size pairs, the list must be sorted by the size and then the thread ID. /// /// Each of these maps has at most MAX_POOL_SIZE elements, and since alignment is limited to - /// less than 64 different possible value, that bounds the overall size of the pool. + /// less than 64 different possible values, that bounds the overall size of the pool. /// /// We also store the ID and the data-race clock of the thread that donated this pool element, /// to ensure synchronization with the thread that picks up this address. @@ -36,6 +36,15 @@ impl ReusePool { } } + /// Call this when we are using up a lot of the address space: if memory reuse is enabled at all, + /// this will bump the intra-thread reuse rate to 100% so that we can keep running this program as + /// long as possible. + pub fn address_space_shortage(&mut self) { + if self.address_reuse_rate > 0.0 { + self.address_reuse_rate = 1.0; + } + } + fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> { let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap(); if self.pool.len() <= pool_idx { @@ -55,9 +64,7 @@ impl ReusePool { clock: impl FnOnce() -> VClock, ) { // Let's see if we even want to remember this address. - // We don't remember stack addresses: there's a lot of them (so the perf impact is big), - // and we only want to reuse stack slots within the same thread or else we'll add a lot of - // undesired synchronization. + // We don't remember stack addresses since there's so many of them (so the perf impact is big). if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) { return; } From 3a1ee645cad501e2fd766bbacea5654a795f352b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Apr 2025 21:55:50 +0000 Subject: [PATCH 232/302] Resolve instance for SymFn in global/naked asm --- compiler/rustc_codegen_ssa/src/base.rs | 8 ++++- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 4 ++- tests/ui/asm/global-asm-mono-sym-fn.rs | 27 ++++++++++++++ tests/ui/asm/naked-asm-mono-sym-fn.rs | 35 +++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/ui/asm/global-asm-mono-sym-fn.rs create mode 100644 tests/ui/asm/naked-asm-mono-sym-fn.rs diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 89439e409378..775ab9071e74 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -457,7 +457,13 @@ where rustc_hir::InlineAsmOperand::SymFn { expr } => { let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), + &ty::FnDef(def_id, args) => Instance::expect_resolve( + cx.tcx(), + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + expr.span, + ), _ => span_bug!(*op_sp, "asm sym is not a function"), }; diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 0301ef437c0d..d2a687359e0b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -95,7 +95,9 @@ fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndL ); let instance = match mono_type.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), + &ty::FnDef(def_id, args) => { + Instance::expect_resolve(cx.tcx(), cx.typing_env(), def_id, args, value.span) + } _ => bug!("asm sym is not a function"), }; diff --git a/tests/ui/asm/global-asm-mono-sym-fn.rs b/tests/ui/asm/global-asm-mono-sym-fn.rs new file mode 100644 index 000000000000..e584a98badb0 --- /dev/null +++ b/tests/ui/asm/global-asm-mono-sym-fn.rs @@ -0,0 +1,27 @@ +// Test that we're properly monomorphizing sym args in global asm blocks +// that point to associated items. + +//@ edition: 2021 +//@ needs-asm-support +//@ only-x86_64-unknown-linux-gnu +//@ build-pass + +#![no_main] + +use std::arch::global_asm; + +fn foo() { + loop {} +} + +trait Foo { + fn bar(); +} + +impl Foo for i32 { + fn bar() { + loop {} + } +} + +global_asm!(".global main", "main:", "call {}", sym ::bar); diff --git a/tests/ui/asm/naked-asm-mono-sym-fn.rs b/tests/ui/asm/naked-asm-mono-sym-fn.rs new file mode 100644 index 000000000000..2bd554beacf8 --- /dev/null +++ b/tests/ui/asm/naked-asm-mono-sym-fn.rs @@ -0,0 +1,35 @@ +// Regression test for . +// Test that we're properly monomorphizing sym args in naked asm blocks +// that point to associated items. + +//@ edition: 2021 +//@ needs-asm-support +//@ only-x86_64 +//@ build-pass + +trait T { + extern "C" fn t(); +} + +enum E {} + +impl T for E { + extern "C" fn t() { + println!("Const generic: {}", C); + } +} + +#[unsafe(naked)] +extern "C" fn foo() { + core::arch::naked_asm!( + "push rax", + "call {fn}", + "pop rax", + "ret", + fn = sym ::t, + ); +} + +fn main() { + foo::>(); +} From 833c212b81d38ce4fb10b7084549291052878822 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 28 Apr 2025 14:40:16 +0000 Subject: [PATCH 233/302] Rename Instance::new to Instance::new_raw and add a note that it is raw --- .../src/intrinsics/mod.rs | 2 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- .../src/coverageinfo/mapgen/unused.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- .../src/back/symbol_export.rs | 4 ++-- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_lint/src/foreign_modules.rs | 2 +- .../src/middle/exported_symbols.rs | 2 +- .../rustc_middle/src/mir/interpret/queries.rs | 6 +++--- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 18 +++++++++++++----- compiler/rustc_monomorphize/src/collector.rs | 4 ++-- compiler/rustc_smir/src/rustc_smir/builder.rs | 2 +- compiler/rustc_symbol_mangling/src/test.rs | 2 +- compiler/rustc_ty_utils/src/instance.rs | 10 +++++----- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- tests/ui/asm/naked-asm-mono-sym-fn.rs | 8 ++++---- 18 files changed, 41 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index d3f47ad72633..e866b8962551 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1282,7 +1282,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic.name, ); } - return Err(Instance::new(instance.def_id(), instance.args)); + return Err(Instance::new_raw(instance.def_id(), instance.args)); } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index d22f4229e237..2ed5ec4381ed 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -399,7 +399,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } // Fall back to default body - _ => return Err(Instance::new(instance.def_id(), instance.args)), + _ => return Err(Instance::new_raw(instance.def_id(), instance.args)), }; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs index 68f60f169b5b..fe3a7a1580b5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs @@ -157,7 +157,7 @@ fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty: let def_id = local_def_id.to_def_id(); // Make a dummy instance that fills in all generics with placeholders. - ty::Instance::new( + ty::Instance::new_raw( def_id, ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let ty::GenericParamDefKind::Lifetime = param.kind { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index ffeab59b05c3..bfaad8f2f1ef 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -613,7 +613,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { _ => { debug!("unknown intrinsic '{}' -- falling back to default body", name); // Call the fallback body instead of generating the intrinsic code - return Err(ty::Instance::new(instance.def_id(), instance.args)); + return Err(ty::Instance::new_raw(instance.def_id(), instance.args)); } }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 1bfdbc0b620e..5f0a0cf922af 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -612,7 +612,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( ExportedSymbol::Generic(def_id, args) => { rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, - Instance::new(def_id, args), + Instance::new_raw(def_id, args), instantiating_crate, ) } @@ -660,7 +660,7 @@ fn calling_convention_for_symbol<'tcx>( None } ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), - ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)), + ExportedSymbol::Generic(def_id, args) => Some(Instance::new_raw(def_id, args)), // DropGlue always use the Rust calling convention and thus follow the target's default // symbol decoration scheme. ExportedSymbol::DropGlue(..) => None, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 309b8f2c7613..91dde13be550 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -216,7 +216,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { check::maybe_check_static_with_link_section(tcx, item_def_id); } DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { - let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); + let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::fully_monomorphized(); tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid)); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 0494c78a7a97..d0668794198a 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -104,7 +104,7 @@ impl ClashingExternDeclarations { /// for the item, return its HirId without updating the set. fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option { let did = fi.owner_id.to_def_id(); - let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); + let instance = Instance::new_raw(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); if let Some(&existing_id) = self.seen_decls.get(&name) { // Avoid updating the map with the new entry when we do find a collision. We want to diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 3c62017072e4..1d67d0fe3bbf 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -56,7 +56,7 @@ impl<'tcx> ExportedSymbol<'tcx> { match *self { ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)), ExportedSymbol::Generic(def_id, args) => { - tcx.symbol_name(ty::Instance::new(def_id, args)) + tcx.symbol_name(ty::Instance::new_raw(def_id, args)) } ExportedSymbol::DropGlue(ty) => { tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e5d1dda3aa0f..4a5c42c721c1 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); self.const_eval_global_id(typing_env, cid, DUMMY_SP) @@ -39,7 +39,7 @@ impl<'tcx> TyCtxt<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); let inputs = self.erase_regions(typing_env.as_query_input(cid)); @@ -209,7 +209,7 @@ impl<'tcx> TyCtxtEnsureOk<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self.tcx, def_id); - let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args)); + let instance = ty::Instance::new_raw(def_id, self.tcx.erase_regions(args)); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6b413a7383a5..7243f87ee638 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -318,7 +318,7 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { match *self { MonoItem::Fn(instance) => write!(f, "fn {instance}"), MonoItem::Static(def_id) => { - write!(f, "static {}", Instance::new(def_id, GenericArgs::empty())) + write!(f, "static {}", Instance::new_raw(def_id, GenericArgs::empty())) } MonoItem::GlobalAsm(..) => write!(f, "global_asm"), } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6af9d4aae301..4981233cebe6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2481,7 +2481,7 @@ rustc_queries! { query resolve_instance_raw( key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)> ) -> Result>, ErrorGuaranteed> { - desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } + desc { "resolving instance `{}`", ty::Instance::new_raw(key.value.0, key.value.1) } } query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d660e7d0d602..0d99a1b51499 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -491,7 +491,15 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { } impl<'tcx> Instance<'tcx> { - pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { + /// Creates a new [`InstanceKind::Item`] from the `def_id` and `args`. + /// + /// Note that this item corresponds to the body of `def_id` directly, which + /// likely does not make sense for trait items which need to be resolved to an + /// implementation, and which may not even have a body themselves. Usages of + /// this function should probably use [`Instance::expect_resolve`], or if run + /// in a polymorphic environment or within a lint (that may encounter ambiguity) + /// [`Instance::try_resolve`] instead. + pub fn new_raw(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { assert!( !args.has_escaping_bound_vars(), "args of instance {def_id:?} has escaping bound vars: {args:?}" @@ -510,7 +518,7 @@ impl<'tcx> Instance<'tcx> { } }); - Instance::new(def_id, args) + Instance::new_raw(def_id, args) } #[inline] @@ -603,7 +611,7 @@ impl<'tcx> Instance<'tcx> { let type_length = type_length(args); if !tcx.type_length_limit().value_within_limit(type_length) { let (shrunk, written_to_path) = - shrunk_instance_name(tcx, Instance::new(def_id, args)); + shrunk_instance_name(tcx, Instance::new_raw(def_id, args)); let mut path = PathBuf::new(); let was_written = if let Some(path2) = written_to_path { path = path2; @@ -773,7 +781,7 @@ impl<'tcx> Instance<'tcx> { match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, args), - _ => Instance::new(def_id, args), + _ => Instance::new_raw(def_id, args), } } @@ -899,7 +907,7 @@ impl<'tcx> Instance<'tcx> { // This is important for `Iterator`'s combinators, but also useful for // adding future default methods to `Future`, for instance. debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) + Some(Instance::new_raw(trait_item_id, rcvr_args)) } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1e3744e19f54..c6a81e60b2b5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -931,7 +931,7 @@ fn visit_instance_use<'tcx>( // We explicitly skip this otherwise to ensure we get a linker error // if anyone tries to call this intrinsic and the codegen backend did not // override the implementation. - let instance = ty::Instance::new(instance.def_id(), instance.args); + let instance = ty::Instance::new_raw(instance.def_id(), instance.args); if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); } @@ -1520,7 +1520,7 @@ impl<'v> RootCollector<'_, 'v> { ty::Closure(def_id, args) | ty::Coroutine(def_id, args) | ty::CoroutineClosure(def_id, args) => { - Instance::new(def_id, self.tcx.erase_regions(args)) + Instance::new_raw(def_id, self.tcx.erase_regions(args)) } _ => unreachable!(), }; diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 64763b71d303..40e6d21c0637 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -22,7 +22,7 @@ impl<'tcx> BodyBuilder<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { let instance = match instance.def { // To get the fallback body of an intrinsic, we need to convert it to an item. - ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), + ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args), _ => instance, }; BodyBuilder { tcx, instance } diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index ddeeadff13d1..0c6d1495e39c 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -56,7 +56,7 @@ impl SymbolNamesTest<'_> { // some subset. for attr in tcx.get_attrs(def_id, SYMBOL_NAME) { let def_id = def_id.to_def_id(); - let instance = Instance::new( + let instance = Instance::new_raw( def_id, tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)), ); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index da83566dad02..166e8f193429 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -235,7 +235,7 @@ fn resolve_associated_item<'tcx>( tcx.ensure_ok().compare_impl_item(leaf_def_item)?; } - Some(ty::Instance::new(leaf_def.item.def_id, args)) + Some(ty::Instance::new_raw(leaf_def.item.def_id, args)) } traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); @@ -280,7 +280,7 @@ fn resolve_associated_item<'tcx>( // Use the default `fn clone_from` from `trait Clone`. let args = tcx.erase_regions(rcvr_args); - Some(ty::Instance::new(trait_item_id, args)) + Some(ty::Instance::new_raw(trait_item_id, args)) } } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) { @@ -329,7 +329,7 @@ fn resolve_associated_item<'tcx>( // sync with the built-in trait implementations (since all of the // implementations return `FnOnce::Output`). if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() { - Some(Instance::new(coroutine_closure_def_id, args)) + Some(Instance::new_raw(coroutine_closure_def_id, args)) } else { Some(Instance { def: ty::InstanceKind::ConstructCoroutineInClosureShim { @@ -362,7 +362,7 @@ fn resolve_associated_item<'tcx>( args, }) } else { - Some(Instance::new(coroutine_closure_def_id, args)) + Some(Instance::new_raw(coroutine_closure_def_id, args)) } } ty::Closure(closure_def_id, args) => { @@ -381,7 +381,7 @@ fn resolve_associated_item<'tcx>( let name = tcx.item_name(trait_item_id); assert_eq!(name, sym::transmute); let args = tcx.erase_regions(rcvr_args); - Some(ty::Instance::new(trait_item_id, args)) + Some(ty::Instance::new_raw(trait_item_id, args)) } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 63859c0396e4..6d3e77b6b6e9 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -263,7 +263,7 @@ impl<'tcx> NonCopyConst<'tcx> { fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None, diff --git a/tests/ui/asm/naked-asm-mono-sym-fn.rs b/tests/ui/asm/naked-asm-mono-sym-fn.rs index 2bd554beacf8..948c290c0b4f 100644 --- a/tests/ui/asm/naked-asm-mono-sym-fn.rs +++ b/tests/ui/asm/naked-asm-mono-sym-fn.rs @@ -7,26 +7,26 @@ //@ only-x86_64 //@ build-pass -trait T { +trait Tr { extern "C" fn t(); } enum E {} -impl T for E { +impl Tr for E { extern "C" fn t() { println!("Const generic: {}", C); } } #[unsafe(naked)] -extern "C" fn foo() { +extern "C" fn foo() { core::arch::naked_asm!( "push rax", "call {fn}", "pop rax", "ret", - fn = sym ::t, + fn = sym ::t, ); } From 2426dbcde20d1c34a50ff1cce9df6215b66e3d1b Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Mon, 5 May 2025 16:36:04 +0300 Subject: [PATCH 234/302] Handle rustc_middle cases of rustc::potential_query_instability lint --- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_middle/src/query/mod.rs | 2 +- .../rustc_middle/src/query/on_disk_cache.rs | 4 +-- compiler/rustc_middle/src/ty/context.rs | 7 ++--- compiler/rustc_middle/src/ty/diagnostics.rs | 4 +-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 30 ++++++++----------- compiler/rustc_resolve/src/lib.rs | 2 +- .../clippy_lints/src/wildcard_imports.rs | 2 +- .../clippy/tests/ui/wildcard_imports.fixed | 10 +++---- .../clippy/tests/ui/wildcard_imports.stderr | 10 +++---- .../wildcard_imports_2021.edition2018.fixed | 10 +++---- .../wildcard_imports_2021.edition2018.stderr | 10 +++---- .../wildcard_imports_2021.edition2021.fixed | 10 +++---- .../wildcard_imports_2021.edition2021.stderr | 10 +++---- 15 files changed, 54 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1e6178144c92..9951b691be1b 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -27,7 +27,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0d5fba3cc69b..5f9f27b5fcd3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2169,7 +2169,7 @@ rustc_queries! { query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet { desc { "fetching potentially unused trait imports" } } - query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet { + query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxIndexSet { desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 14e3ce8bef6b..ce879be75fee 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::mem; use std::sync::Arc; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::sync::{HashMapExt, Lock, RwLock}; use rustc_data_structures::unhash::UnhashMap; @@ -57,7 +57,7 @@ pub struct OnDiskCache { // Collects all `QuerySideEffect` created during the current compilation // session. - current_side_effects: Lock>, + current_side_effects: Lock>, file_index_to_stable_id: FxHashMap, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 162ca1f4af85..87bd2785bedd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,7 +28,6 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; -use rustc_data_structures::unord::UnordSet; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; @@ -2378,6 +2377,8 @@ macro_rules! sty_debug_print { $(let mut $variant = total;)* for shard in tcx.interners.type_.lock_shards() { + // It seems that ordering doesn't affect anything here. + #[allow(rustc::potential_query_instability)] let types = shard.iter(); for &(InternedInSet(t), ()) in types { let variant = match t.internee { @@ -3355,9 +3356,7 @@ pub fn provide(providers: &mut Providers) { providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { - tcx.arena.alloc(UnordSet::from( - tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default(), - )) + tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default()) }; providers.extern_mod_stmt_cnum = diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d3abb3d64b8c..e2bae831efc0 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use std::ops::ControlFlow; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize, }; @@ -287,7 +287,7 @@ pub fn suggest_constraining_type_params<'a>( param_names_and_constraints: impl Iterator)>, span_to_replace: Option, ) -> bool { - let mut grouped = FxHashMap::default(); + let mut grouped = FxIndexMap::default(); let mut unstable_suggestion = false; param_names_and_constraints.for_each(|(param_name, constraint, def_id)| { let stable = match def_id { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 80f1bd7c6f46..d94331926ff4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -172,7 +172,7 @@ pub struct ResolverGlobalCtxt { pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, - pub glob_map: FxHashMap>, + pub glob_map: FxIndexMap>, pub main_def: Option, pub trait_impls: FxIndexMap>, /// A list of proc macro LocalDefIds, written out in the order in which diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3281cb4135a0..69940ab446c9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -6,7 +6,7 @@ use std::ops::{Deref, DerefMut}; use rustc_abi::{ExternAbi, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::LangItem; @@ -3489,8 +3489,8 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { // Once constructed, unique namespace+symbol pairs will have a `Some(_)` entry, while // non-unique pairs will have a `None` entry. - let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option> = - &mut FxHashMap::default(); + let unique_symbols_rev: &mut FxIndexMap<(Namespace, Symbol), Option> = + &mut FxIndexMap::default(); for symbol_set in tcx.resolutions(()).glob_map.values() { for symbol in symbol_set { @@ -3500,27 +3500,23 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { } } - for_each_def(tcx, |ident, ns, def_id| { - use std::collections::hash_map::Entry::{Occupied, Vacant}; - - match unique_symbols_rev.entry((ns, ident.name)) { - Occupied(mut v) => match v.get() { - None => {} - Some(existing) => { - if *existing != def_id { - v.insert(None); - } + for_each_def(tcx, |ident, ns, def_id| match unique_symbols_rev.entry((ns, ident.name)) { + IndexEntry::Occupied(mut v) => match v.get() { + None => {} + Some(existing) => { + if *existing != def_id { + v.insert(None); } - }, - Vacant(v) => { - v.insert(Some(def_id)); } + }, + IndexEntry::Vacant(v) => { + v.insert(Some(def_id)); } }); // Put the symbol from all the unique namespace+symbol pairs into `map`. let mut map: DefIdMap = Default::default(); - for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + for ((_, symbol), opt_def_id) in unique_symbols_rev.drain(..) { use std::collections::hash_map::Entry::{Occupied, Vacant}; if let Some(def_id) = opt_def_id { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3ac66840d87d..42f113959bd1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1104,7 +1104,7 @@ pub struct Resolver<'ra, 'tcx> { underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. - glob_map: FxHashMap>, + glob_map: FxIndexMap>, glob_error: Option, visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, used_imports: FxHashSet, diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 405310512dff..393060d52609 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -150,7 +150,7 @@ impl LateLintPass<'_> for WildcardImports { (span, false) }; - let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(); + let mut imports: Vec<_> = used_imports.iter().map(ToString::to_string).collect(); let imports_string = if imports.len() == 1 { imports.pop().unwrap() } else if braced_glob { diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index a26b4a34190c..17510683f03e 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -16,7 +16,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports #[macro_use] use crate::struct_mod::{A, inner_struct_mod}; @@ -26,7 +26,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -138,7 +138,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -160,7 +160,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -190,7 +190,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index f774126102bc..26434656a509 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:19:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:22:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:29:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:100:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:141:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:154:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:163:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:193:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:203:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed index a3d1aebba8af..f97b883ea231 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -14,7 +14,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; //~^ wildcard_imports @@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -132,7 +132,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -154,7 +154,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -184,7 +184,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index a1b557f39f0d..873ce41b04f4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:19:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:95:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:148:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed index a3d1aebba8af..f97b883ea231 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -14,7 +14,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; //~^ wildcard_imports @@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -132,7 +132,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -154,7 +154,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -184,7 +184,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index a1b557f39f0d..873ce41b04f4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:19:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:95:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:148:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 From 45598de7048f350f48651b67b4dfc4dfcb30deeb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 1 May 2025 18:52:41 +0000 Subject: [PATCH 235/302] Do not gather local all together at the beginning of typeck --- compiler/rustc_hir_typeck/src/_match.rs | 4 +- compiler/rustc_hir_typeck/src/check.rs | 5 +- compiler/rustc_hir_typeck/src/expr.rs | 10 +-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +- .../rustc_hir_typeck/src/gather_locals.rs | 51 +++++++++++--- compiler/rustc_hir_typeck/src/lib.rs | 4 -- .../async-closures/def-path.stderr | 4 +- ...re-print-generic-trim-off-verbose-2.stderr | 2 +- .../closure-print-generic-verbose-2.stderr | 2 +- .../const-arg-in-const-arg.min.stderr | 70 +++++++++---------- .../dependence_lint.gce.stderr | 38 +++++----- tests/ui/const-generics/invalid-enum.stderr | 44 ++++++------ ...tion-correct-dyn-incompatible-trait.stderr | 36 +++++----- tests/ui/issues/issue-18959.rs | 1 - tests/ui/issues/issue-18959.stderr | 24 ++----- tests/ui/lint/bare-trait-objects-path.stderr | 40 +++++------ .../disambiguate-multiple-blanket-impl.stderr | 30 ++++---- .../methods/disambiguate-multiple-impl.stderr | 30 ++++---- .../disambiguate-multiple-trait-2.stderr | 64 ++++++++--------- .../disambiguate-multiple-trait.stderr | 30 ++++---- .../generics-default-stability.stderr | 48 ++++++------- .../suggest-vec-allocator-api.stderr | 20 +++--- .../bound/on-structs-and-enums-locals.stderr | 34 ++++----- .../bound/on-structs-and-enums-xc1.stderr | 24 +++---- 24 files changed, 318 insertions(+), 303 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 38319862334a..2e7831f16aee 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use crate::coercion::{AsCoercionSite, CoerceMany}; -use crate::{Diverges, Expectation, FnCtxt, Needs}; +use crate::{Diverges, Expectation, FnCtxt, GatherLocalsVisitor, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] @@ -43,6 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span); for arm in arms { + GatherLocalsVisitor::gather_from_arm(self, arm); + self.check_pat_top(arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2189fdf0f343..99103f14d682 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -3,7 +3,6 @@ use std::cell::RefCell; use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::check_function_signature; use rustc_infer::infer::RegionVariableOrigin; @@ -50,7 +49,9 @@ pub(super) fn check_fn<'a, 'tcx>( let span = body.value.span; - GatherLocalsVisitor::new(fcx).visit_body(body); + for param in body.params { + GatherLocalsVisitor::gather_from_param(fcx, param); + } // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index db2650ed357e..2c28ffd1fe3d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -16,7 +16,6 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::NoVariantNamed; @@ -50,8 +49,8 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::{ - BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast, - fatally_break_rust, report_unexpected_variant_res, type_error_struct, + BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs, + TupleArgumentsFlag, cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1518,11 +1517,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let_expr: &'tcx hir::LetExpr<'tcx>, hir_id: HirId, ) -> Ty<'tcx> { + GatherLocalsVisitor::gather_from_let_expr(self, let_expr, hir_id); + // for let statements, this is done in check_stmt let init = let_expr.init; self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); + // otherwise check exactly as a let statement self.check_decl((let_expr, hir_id).into()); + // but return a bool, for this is a boolean expression if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered { self.set_tainted_by_errors(error_guaranteed); @@ -1827,7 +1830,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a new function context. let def_id = block.def_id; let fcx = FnCtxt::new(self, self.param_env, def_id); - crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(body.value, expected); fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c804dc5e7fba..6cc7e82bbf73 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -37,8 +37,8 @@ use crate::method::probe::IsSuggestion; use crate::method::probe::Mode::MethodCall; use crate::method::probe::ProbeScope::TraitsInScope; use crate::{ - BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors, - struct_span_code_err, + BreakableCtxt, Diverges, Expectation, FnCtxt, GatherLocalsVisitor, LoweredTy, Needs, + TupleArgumentsFlag, errors, struct_span_code_err, }; rustc_index::newtype_index! { @@ -1765,6 +1765,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check a `let` statement. fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) { + GatherLocalsVisitor::gather_from_local(self, local); + let ty = self.check_decl(local.into()); self.write_ty(local.hir_id, ty); if local.pat.is_never_pattern() { diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 5d87e800096f..a8bbc89dbded 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -55,6 +55,14 @@ impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> { } } +/// The `GatherLocalsVisitor` is responsible for initializing local variable types +/// in the [`ty::TypeckResults`] for all subpatterns in statements and expressions +/// like `let`, `match`, and params of function bodies. It also adds `Sized` bounds +/// for these types (with exceptions for unsized feature gates like `unsized_fn_params`). +/// +/// Failure to visit locals will cause an ICE in writeback when the local's type is +/// resolved. Visiting locals twice will ICE in the `GatherLocalsVisitor`, since it +/// will overwrite the type previously stored in the local. pub(super) struct GatherLocalsVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, // parameters are special cases of patterns, but we want to handle them as @@ -63,9 +71,37 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> { outermost_fn_param_pat: Option<(Span, HirId)>, } +// N.B. additional `gather_*` functions should be careful to only walk the pattern +// for new expressions, since visiting sub-expressions or nested bodies may initialize +// locals which are not conceptually owned by the gathered statement or expression. impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { - Self { fcx, outermost_fn_param_pat: None } + pub(crate) fn gather_from_local(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::LetStmt<'tcx>) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.declare(local.into()); + visitor.visit_pat(local.pat); + } + + pub(crate) fn gather_from_let_expr( + fcx: &'a FnCtxt<'a, 'tcx>, + let_expr: &'tcx hir::LetExpr<'tcx>, + expr_hir_id: hir::HirId, + ) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.declare((let_expr, expr_hir_id).into()); + visitor.visit_pat(let_expr.pat); + } + + pub(crate) fn gather_from_param(fcx: &'a FnCtxt<'a, 'tcx>, param: &'tcx hir::Param<'tcx>) { + let mut visitor = GatherLocalsVisitor { + fcx, + outermost_fn_param_pat: Some((param.ty_span, param.hir_id)), + }; + visitor.visit_pat(param.pat); + } + + pub(crate) fn gather_from_arm(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::Arm<'tcx>) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.visit_pat(local.pat); } fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option>) -> Ty<'tcx> { @@ -73,12 +109,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { None => { // Infer the variable's type. let var_ty = self.fcx.next_ty_var(span); - self.fcx.locals.borrow_mut().insert(nid, var_ty); + assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None); var_ty } Some(typ) => { // Take type that the user specified. - self.fcx.locals.borrow_mut().insert(nid, typ); + assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None); typ } } @@ -133,13 +169,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_expr(self, expr) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let old_outermost_fn_param_pat = - self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id)); - intravisit::walk_param(self, param); - self.outermost_fn_param_pat = old_outermost_fn_param_pat; - } - // Add pattern bindings. fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { if let PatKind::Binding(_, _, ident, _) = p.kind { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d861a4f81b0e..78233a34c461 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -46,7 +46,6 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, HirIdMap, Node}; use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; @@ -191,9 +190,6 @@ fn typeck_with_inspect<'tcx>( let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))); fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code); - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor::new(&fcx).visit_body(body); - fcx.check_expr_coercible_to_type(body.value, expected_type, None); fcx.write_ty(id, expected_type); diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index 13ebaf67e54a..b50e353b6988 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index b71cfc503339..bcf5759a194f 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{mod1::f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` + found closure `{mod1::f::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index 88f4dc9b92ab..a8d2b07a00dc 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` + found closure `{f::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index 06a6a5f59d6d..16512cb69e23 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -240,41 +240,6 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:36:24 - | -LL | let _: Foo<{ bar::() }>; - | ^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Foo<{ bar::<{ N }>() }>; - | + + - -error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:38:24 - | -LL | let _: Foo<{ faz::<'a>(&()) }>; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:10:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - -error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:41:24 - | -LL | let _: Foo<{ faz::<'b>(&()) }>; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:10:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - error: constant expression depends on a generic parameter --> $DIR/const-arg-in-const-arg.rs:25:17 | @@ -326,6 +291,41 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/const-arg-in-const-arg.rs:36:24 + | +LL | let _: Foo<{ bar::() }>; + | ^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Foo<{ bar::<{ N }>() }>; + | + + + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/const-arg-in-const-arg.rs:38:24 + | +LL | let _: Foo<{ faz::<'a>(&()) }>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:10:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/const-arg-in-const-arg.rs:41:24 + | +LL | let _: Foo<{ faz::<'b>(&()) }>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:10:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + error[E0747]: unresolved item provided when a constant was expected --> $DIR/const-arg-in-const-arg.rs:45:27 | diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr index 7e318f8786f3..f6119c17bf47 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr @@ -1,22 +1,3 @@ -error: overly complex generic constant - --> $DIR/dependence_lint.rs:21:17 - | -LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants - | - = help: consider moving this anonymous constant into a `const` function - -error: unconstrained generic constant - --> $DIR/dependence_lint.rs:14:12 - | -LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try adding a `where` bound - | -LL | fn foo() where [(); size_of::<*mut T>()]: { - | ++++++++++++++++++++++++++++++++ - error: unconstrained generic constant --> $DIR/dependence_lint.rs:10:9 | @@ -36,5 +17,24 @@ LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error w | = help: consider moving this anonymous constant into a `const` function +error: unconstrained generic constant + --> $DIR/dependence_lint.rs:14:12 + | +LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | fn foo() where [(); size_of::<*mut T>()]: { + | ++++++++++++++++++++++++++++++++ + +error: overly complex generic constant + --> $DIR/dependence_lint.rs:21:17 + | +LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants + | + = help: consider moving this anonymous constant into a `const` function + error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/invalid-enum.stderr b/tests/ui/const-generics/invalid-enum.stderr index 7e8a632b34f7..f588ff0bc8eb 100644 --- a/tests/ui/const-generics/invalid-enum.stderr +++ b/tests/ui/const-generics/invalid-enum.stderr @@ -25,28 +25,6 @@ LL | let _: Example = Example { x: 0 }; | not a type | help: try using the variant's enum: `CompileFlag` -error[E0747]: unresolved item provided when a constant was expected - --> $DIR/invalid-enum.rs:31:18 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; - | + + - -error[E0747]: type provided when a constant was expected - --> $DIR/invalid-enum.rs:35:18 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; - | + + - error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-enum.rs:23:12 | @@ -69,6 +47,28 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | test_2::<_, { CompileFlag::A }>(0); | + + +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | + + + +error[E0747]: type provided when a constant was expected + --> $DIR/invalid-enum.rs:35:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | + + + error: aborting due to 7 previous errors Some errors have detailed explanations: E0573, E0747. diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index bb3f7899bf1c..c1e93ccb83ca 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -1,21 +1,3 @@ -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 - | -LL | let test: &mut dyn Bar = &mut thing; - | ^^^^^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 - | -LL | fn foo(&self, val: T); - | ^^^ ...because method `foo` has generic type parameters -... -LL | trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - = help: only type `Thing` implements `Bar`; consider using it directly instead. - error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30 | @@ -35,6 +17,24 @@ LL | trait Bar: Foo { } = help: only type `Thing` implements `Bar`; consider using it directly instead. = note: required for the cast from `&mut Thing` to `&mut dyn Bar` +error[E0038]: the trait `Bar` is not dyn compatible + --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 + | +LL | let test: &mut dyn Bar = &mut thing; + | ^^^^^^^^^^^^ `Bar` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 + | +LL | fn foo(&self, val: T); + | ^^^ ...because method `foo` has generic type parameters +... +LL | trait Bar: Foo { } + | --- this trait is not dyn compatible... + = help: consider moving `foo` to another trait + = help: only type `Thing` implements `Bar`; consider using it directly instead. + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-18959.rs b/tests/ui/issues/issue-18959.rs index f4cab630f2e9..6aeb34879ea1 100644 --- a/tests/ui/issues/issue-18959.rs +++ b/tests/ui/issues/issue-18959.rs @@ -20,5 +20,4 @@ fn main() { //~^ ERROR E0038 //~| ERROR E0038 foo(test); - //~^ ERROR E0038 } diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index c37c4177bfc1..1e050b115e57 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -30,22 +30,6 @@ LL | pub trait Bar: Foo { } | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:19:15 - | -LL | let test: &dyn Bar = &mut thing; - | ^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-18959.rs:1:20 - | -LL | pub trait Foo { fn foo(&self, ext_thing: &T); } - | ^^^ ...because method `foo` has generic type parameters -LL | pub trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:19:26 | @@ -64,10 +48,10 @@ LL | pub trait Bar: Foo { } = note: required for the cast from `&mut Thing` to `&dyn Bar` error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:22:9 + --> $DIR/issue-18959.rs:19:15 | -LL | foo(test); - | ^^^^ `Bar` is not dyn compatible +LL | let test: &dyn Bar = &mut thing; + | ^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -79,6 +63,6 @@ LL | pub trait Bar: Foo { } | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index d2d139dd025a..fbb647c37c5a 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -1,23 +1,3 @@ -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:23:12 - | -LL | let _: Dyn::Ty; - | ^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see - = note: `#[warn(bare_trait_objects)]` on by default -help: if this is a dyn-compatible trait, use `dyn` - | -LL | let _: ::Ty; - | ++++ + - -error[E0223]: ambiguous associated type - --> $DIR/bare-trait-objects-path.rs:23:12 - | -LL | let _: Dyn::Ty; - | ^^^^^^^ help: use fully-qualified syntax: `::Ty` - warning: trait objects without an explicit `dyn` are deprecated --> $DIR/bare-trait-objects-path.rs:14:5 | @@ -26,6 +6,7 @@ LL | Dyn::func(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default help: if this is a dyn-compatible trait, use `dyn` | LL | ::func(); @@ -57,6 +38,25 @@ help: if this is a dyn-compatible trait, use `dyn` LL | ::CONST; | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/bare-trait-objects-path.rs:23:12 + | +LL | let _: Dyn::Ty; + | ^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: if this is a dyn-compatible trait, use `dyn` + | +LL | let _: ::Ty; + | ++++ + + +error[E0223]: ambiguous associated type + --> $DIR/bare-trait-objects-path.rs:23:12 + | +LL | let _: Dyn::Ty; + | ^^^^^^^ help: use fully-qualified syntax: `::Ty` + error: aborting due to 1 previous error; 4 warnings emitted For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr b/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr index 1b81dc5aafb7..ee698ed0e75f 100644 --- a/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr +++ b/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr @@ -1,18 +1,3 @@ -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-blanket-impl.rs:36:12 - | -LL | let _: S::Type; - | ^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::Type; -LL + let _: ::Type; - | -LL - let _: S::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-blanket-impl.rs:30:8 | @@ -63,6 +48,21 @@ LL - S::CONST; LL + ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-blanket-impl.rs:36:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 3 previous errors Some errors have detailed explanations: E0034, E0223. diff --git a/tests/ui/methods/disambiguate-multiple-impl.stderr b/tests/ui/methods/disambiguate-multiple-impl.stderr index 2563c2327b7a..319d5886f8ed 100644 --- a/tests/ui/methods/disambiguate-multiple-impl.stderr +++ b/tests/ui/methods/disambiguate-multiple-impl.stderr @@ -1,18 +1,3 @@ -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-impl.rs:32:12 - | -LL | let _: S::Type = (); - | ^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::Type = (); -LL + let _: ::Type = (); - | -LL - let _: S::Type = (); -LL + let _: ::Type = (); - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-impl.rs:29:8 | @@ -38,6 +23,21 @@ LL - S::foo(&s); LL + B::foo(&s); | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-impl.rs:32:12 + | +LL | let _: S::Type = (); + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type = (); +LL + let _: ::Type = (); + | +LL - let _: S::Type = (); +LL + let _: ::Type = (); + | + error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-impl.rs:34:16 | diff --git a/tests/ui/methods/disambiguate-multiple-trait-2.stderr b/tests/ui/methods/disambiguate-multiple-trait-2.stderr index 08e264c20c89..f9119e607501 100644 --- a/tests/ui/methods/disambiguate-multiple-trait-2.stderr +++ b/tests/ui/methods/disambiguate-multiple-trait-2.stderr @@ -1,26 +1,3 @@ -error[E0221]: ambiguous associated type `Type` in bounds of `T` - --> $DIR/disambiguate-multiple-trait-2.rs:23:12 - | -LL | type Type; - | --------- ambiguous `Type` from `A` -... -LL | type Type; - | --------- ambiguous `Type` from `B` -... -LL | let _: T::Type; - | ^^^^^^^ ambiguous associated type `Type` - | -help: use fully-qualified syntax to disambiguate - | -LL - let _: T::Type; -LL + let _: ::Type; - | -help: use fully-qualified syntax to disambiguate - | -LL - let _: T::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-trait-2.rs:16:7 | @@ -73,19 +50,27 @@ LL - let _ = T::CONST; LL + let _ = ::CONST; | -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-trait-2.rs:52:12 +error[E0221]: ambiguous associated type `Type` in bounds of `T` + --> $DIR/disambiguate-multiple-trait-2.rs:23:12 | -LL | let _: S::Type; - | ^^^^^^^ +LL | type Type; + | --------- ambiguous `Type` from `A` +... +LL | type Type; + | --------- ambiguous `Type` from `B` +... +LL | let _: T::Type; + | ^^^^^^^ ambiguous associated type `Type` | -help: use fully-qualified syntax +help: use fully-qualified syntax to disambiguate | -LL - let _: S::Type; -LL + let _: ::Type; +LL - let _: T::Type; +LL + let _: ::Type; | -LL - let _: S::Type; -LL + let _: ::Type; +help: use fully-qualified syntax to disambiguate + | +LL - let _: T::Type; +LL + let _: ::Type; | error[E0034]: multiple applicable items in scope @@ -138,6 +123,21 @@ LL - let _ = S::CONST; LL + let _ = ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait-2.rs:52:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 6 previous errors Some errors have detailed explanations: E0034, E0221, E0223. diff --git a/tests/ui/methods/disambiguate-multiple-trait.stderr b/tests/ui/methods/disambiguate-multiple-trait.stderr index a977fe2cd033..f35eec3b048c 100644 --- a/tests/ui/methods/disambiguate-multiple-trait.stderr +++ b/tests/ui/methods/disambiguate-multiple-trait.stderr @@ -1,18 +1,3 @@ -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-trait.rs:30:12 - | -LL | let _: S::Type; - | ^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::Type; -LL + let _: ::Type; - | -LL - let _: S::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-trait.rs:24:8 | @@ -63,6 +48,21 @@ LL - let _ = S::CONST; LL + let _ = ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait.rs:30:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 3 previous errors Some errors have detailed explanations: E0034, E0223. diff --git a/tests/ui/stability-attribute/generics-default-stability.stderr b/tests/ui/stability-attribute/generics-default-stability.stderr index f4f51a14248e..53ef3e170cc1 100644 --- a/tests/ui/stability-attribute/generics-default-stability.stderr +++ b/tests/ui/stability-attribute/generics-default-stability.stderr @@ -270,6 +270,18 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:71:39 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:78:39 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:84:20 | @@ -279,6 +291,12 @@ LL | let _: Struct5 = Struct5 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:84:39 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:90:20 | @@ -297,6 +315,12 @@ LL | let _: Struct5 = Struct5 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:92:39 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:100:19 | @@ -468,30 +492,6 @@ LL | let _: Box1 = Box1::new(1); = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: use of deprecated field `unstable_generic_param::Struct4::field`: test - --> $DIR/generics-default-stability.rs:71:39 - | -LL | let _: Struct4 = Struct4 { field: 1 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct4::field`: test - --> $DIR/generics-default-stability.rs:78:39 - | -LL | let _: Struct4 = Struct4 { field: 0 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct5::field`: test - --> $DIR/generics-default-stability.rs:84:39 - | -LL | let _: Struct5 = Struct5 { field: 1 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct5::field`: test - --> $DIR/generics-default-stability.rs:92:39 - | -LL | let _: Struct5 = Struct5 { field: 0 }; - | ^^^^^^^^ - error: aborting due to 28 previous errors; 40 warnings emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr b/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr index 6662ceda90b9..78b7d07b60cc 100644 --- a/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr +++ b/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr @@ -26,16 +26,6 @@ LL + String, LL ~ _)> = vec![]; | -error[E0658]: use of unstable library feature `allocator_api` - --> $DIR/suggest-vec-allocator-api.rs:8:26 - | -LL | let _boxed: Box = Box::new(10); - | ^ - | - = note: see issue #32838 for more information - = help: add `#![feature(allocator_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: use of unstable library feature `allocator_api` --> $DIR/suggest-vec-allocator-api.rs:7:24 | @@ -48,6 +38,16 @@ LL | let _ = Vec::::new(); = help: add `#![feature(allocator_api)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature `allocator_api` + --> $DIR/suggest-vec-allocator-api.rs:8:26 + | +LL | let _boxed: Box = Box::new(10); + | ^ + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr index 01cf76c62d54..88077f4e4d7d 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr @@ -1,20 +1,3 @@ -error[E0277]: the trait bound `usize: Trait` is not satisfied - --> $DIR/on-structs-and-enums-locals.rs:15:14 - | -LL | let baz: Foo = loop { }; - | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -help: this trait has no implementations, consider adding one - --> $DIR/on-structs-and-enums-locals.rs:1:1 - | -LL | trait Trait { - | ^^^^^^^^^^^ -note: required by a bound in `Foo` - --> $DIR/on-structs-and-enums-locals.rs:5:14 - | -LL | struct Foo { - | ^^^^^ required by this bound in `Foo` - error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/on-structs-and-enums-locals.rs:11:12 | @@ -32,6 +15,23 @@ note: required by a bound in `Foo` LL | struct Foo { | ^^^^^ required by this bound in `Foo` +error[E0277]: the trait bound `usize: Trait` is not satisfied + --> $DIR/on-structs-and-enums-locals.rs:15:14 + | +LL | let baz: Foo = loop { }; + | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` + | +help: this trait has no implementations, consider adding one + --> $DIR/on-structs-and-enums-locals.rs:1:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ +note: required by a bound in `Foo` + --> $DIR/on-structs-and-enums-locals.rs:5:14 + | +LL | struct Foo { + | ^^^^^ required by this bound in `Foo` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr b/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr index 3fb5decb723e..1f46415e2436 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr @@ -1,15 +1,3 @@ -error[E0277]: the trait bound `f64: Trait` is not satisfied - --> $DIR/on-structs-and-enums-xc1.rs:12:14 - | -LL | let bar: Bar = return; - | ^^^^^^^^ the trait `Trait` is not implemented for `f64` - | -note: required by a bound in `Bar` - --> $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16 - | -LL | pub enum Bar { - | ^^^^^ required by this bound in `Bar` - error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/on-structs-and-enums-xc1.rs:9:12 | @@ -22,6 +10,18 @@ note: required by a bound in `Foo` LL | pub struct Foo { | ^^^^^ required by this bound in `Foo` +error[E0277]: the trait bound `f64: Trait` is not satisfied + --> $DIR/on-structs-and-enums-xc1.rs:12:14 + | +LL | let bar: Bar = return; + | ^^^^^^^^ the trait `Trait` is not implemented for `f64` + | +note: required by a bound in `Bar` + --> $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16 + | +LL | pub enum Bar { + | ^^^^^ required by this bound in `Bar` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. From 896cf8029c6a87b920e05dd569482dad6adbddfc Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 5 May 2025 22:56:03 +0800 Subject: [PATCH 236/302] Add ui test fn-trait-use-named-params Signed-off-by: xizheyin --- .../fn-trait-use-named-params-issue-140169.rs | 6 ++++++ ...trait-use-named-params-issue-140169.stderr | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/fn/fn-trait-use-named-params-issue-140169.rs create mode 100644 tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs new file mode 100644 index 000000000000..fae5f6c15193 --- /dev/null +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs @@ -0,0 +1,6 @@ +fn g(_: fn(a: u8)) {} +fn x(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` +fn y(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` +fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` + +fn main(){} diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr new file mode 100644 index 000000000000..e599afb1345f --- /dev/null +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr @@ -0,0 +1,20 @@ +error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` + --> $DIR/fn-trait-use-named-params-issue-140169.rs:2:25 + | +LL | fn x(_: impl Fn(u8, vvvv: u8)) {} + | ^ expected one of 7 possible tokens + +error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` + --> $DIR/fn-trait-use-named-params-issue-140169.rs:3:21 + | +LL | fn y(_: impl Fn(aaaa: u8, u8)) {} + | ^ expected one of 7 possible tokens + +error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` + --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:21 + | +LL | fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} + | ^ expected one of 7 possible tokens + +error: aborting due to 3 previous errors + From 29f9aaf5038ba61d9a8ef8d1deb642d389c82ba0 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 5 May 2025 14:56:56 +0000 Subject: [PATCH 237/302] calculate step duration in a panic-safe way Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index c32d9c2870cf..6469bb5f2722 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1534,7 +1534,7 @@ impl<'a> Builder<'a> { let out = step.clone().run(self); let dur = start.elapsed(); let deps = self.time_spent_on_dependencies.replace(parent + dur); - (out, dur - deps) + (out, dur.saturating_sub(deps)) }; if self.config.print_step_timings && !self.config.dry_run() { From 662182637e100642d1e5de7cb193da837a14ae48 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 12 Apr 2025 15:53:46 +0000 Subject: [PATCH 238/302] Implement RFC 3503: frontmatters Supercedes #137193 --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_lexer/src/cursor.rs | 14 +- compiler/rustc_lexer/src/lib.rs | 155 +++++++++++++++++- compiler/rustc_lexer/src/tests.rs | 2 +- compiler/rustc_parse/messages.ftl | 13 ++ compiler/rustc_parse/src/errors.rs | 55 +++++++ compiler/rustc_parse/src/lexer/mod.rs | 106 +++++++++++- compiler/rustc_span/src/symbol.rs | 1 + .../language-features/arbitrary-self-types.md | 2 +- .../src/language-features/f128.md | 2 +- .../src/language-features/f16.md | 2 +- .../src/language-features/frontmatter.md | 25 +++ src/librustdoc/html/highlight.rs | 6 +- .../crates/parser/src/lexed_str.rs | 9 + .../parser/src/syntax_kind/generated.rs | 4 +- .../rust-analyzer/crates/syntax/rust.ungram | 1 + .../crates/syntax/src/ast/generated/nodes.rs | 4 + .../xtask/src/codegen/grammar.rs | 1 + .../feature-gates/feature-gate-frontmatter.rs | 5 + .../feature-gate-frontmatter.stderr | 15 ++ tests/ui/frontmatter/auxiliary/lib.rs | 6 + tests/ui/frontmatter/auxiliary/makro.rs | 8 + .../frontmatter/dot-in-infostring-leading.rs | 9 + .../dot-in-infostring-leading.stderr | 10 ++ .../dot-in-infostring-non-leading.rs | 9 + tests/ui/frontmatter/escape.rs | 14 ++ tests/ui/frontmatter/extra-after-end.rs | 7 + tests/ui/frontmatter/extra-after-end.stderr | 8 + .../frontmatter/frontmatter-after-tokens.rs | 10 ++ .../frontmatter-after-tokens.stderr | 10 ++ .../frontmatter-non-lexible-tokens.rs | 12 ++ .../frontmatter/frontmatter-whitespace-1.rs | 10 ++ .../frontmatter-whitespace-1.stderr | 26 +++ .../frontmatter/frontmatter-whitespace-2.rs | 15 ++ .../frontmatter-whitespace-2.stderr | 26 +++ .../frontmatter/frontmatter-whitespace-3.rs | 16 ++ .../frontmatter/frontmatter-whitespace-4.rs | 9 + tests/ui/frontmatter/included-frontmatter.rs | 12 ++ tests/ui/frontmatter/infostring-fail.rs | 9 + tests/ui/frontmatter/infostring-fail.stderr | 10 ++ tests/ui/frontmatter/mismatch-1.rs | 10 ++ tests/ui/frontmatter/mismatch-1.stderr | 16 ++ tests/ui/frontmatter/mismatch-2.rs | 8 + tests/ui/frontmatter/mismatch-2.stderr | 22 +++ tests/ui/frontmatter/multifrontmatter-2.rs | 12 ++ .../ui/frontmatter/multifrontmatter-2.stderr | 22 +++ tests/ui/frontmatter/multifrontmatter.rs | 13 ++ tests/ui/frontmatter/multifrontmatter.stderr | 10 ++ tests/ui/frontmatter/proc-macro-observer.rs | 12 ++ tests/ui/frontmatter/shebang.rs | 13 ++ tests/ui/frontmatter/unclosed-1.rs | 10 ++ tests/ui/frontmatter/unclosed-1.stderr | 16 ++ tests/ui/frontmatter/unclosed-2.rs | 15 ++ tests/ui/frontmatter/unclosed-2.stderr | 31 ++++ tests/ui/frontmatter/unclosed-3.rs | 16 ++ tests/ui/frontmatter/unclosed-3.stderr | 41 +++++ tests/ui/frontmatter/unclosed-4.rs | 9 + tests/ui/frontmatter/unclosed-4.stderr | 16 ++ tests/ui/frontmatter/unclosed-5.rs | 10 ++ tests/ui/frontmatter/unclosed-5.stderr | 29 ++++ 61 files changed, 970 insertions(+), 22 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/frontmatter.md create mode 100644 tests/ui/feature-gates/feature-gate-frontmatter.rs create mode 100644 tests/ui/feature-gates/feature-gate-frontmatter.stderr create mode 100644 tests/ui/frontmatter/auxiliary/lib.rs create mode 100644 tests/ui/frontmatter/auxiliary/makro.rs create mode 100644 tests/ui/frontmatter/dot-in-infostring-leading.rs create mode 100644 tests/ui/frontmatter/dot-in-infostring-leading.stderr create mode 100644 tests/ui/frontmatter/dot-in-infostring-non-leading.rs create mode 100644 tests/ui/frontmatter/escape.rs create mode 100644 tests/ui/frontmatter/extra-after-end.rs create mode 100644 tests/ui/frontmatter/extra-after-end.stderr create mode 100644 tests/ui/frontmatter/frontmatter-after-tokens.rs create mode 100644 tests/ui/frontmatter/frontmatter-after-tokens.stderr create mode 100644 tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-1.rs create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-1.stderr create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-2.rs create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-2.stderr create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-3.rs create mode 100644 tests/ui/frontmatter/frontmatter-whitespace-4.rs create mode 100644 tests/ui/frontmatter/included-frontmatter.rs create mode 100644 tests/ui/frontmatter/infostring-fail.rs create mode 100644 tests/ui/frontmatter/infostring-fail.stderr create mode 100644 tests/ui/frontmatter/mismatch-1.rs create mode 100644 tests/ui/frontmatter/mismatch-1.stderr create mode 100644 tests/ui/frontmatter/mismatch-2.rs create mode 100644 tests/ui/frontmatter/mismatch-2.stderr create mode 100644 tests/ui/frontmatter/multifrontmatter-2.rs create mode 100644 tests/ui/frontmatter/multifrontmatter-2.stderr create mode 100644 tests/ui/frontmatter/multifrontmatter.rs create mode 100644 tests/ui/frontmatter/multifrontmatter.stderr create mode 100644 tests/ui/frontmatter/proc-macro-observer.rs create mode 100644 tests/ui/frontmatter/shebang.rs create mode 100644 tests/ui/frontmatter/unclosed-1.rs create mode 100644 tests/ui/frontmatter/unclosed-1.stderr create mode 100644 tests/ui/frontmatter/unclosed-2.rs create mode 100644 tests/ui/frontmatter/unclosed-2.stderr create mode 100644 tests/ui/frontmatter/unclosed-3.rs create mode 100644 tests/ui/frontmatter/unclosed-3.stderr create mode 100644 tests/ui/frontmatter/unclosed-4.rs create mode 100644 tests/ui/frontmatter/unclosed-4.stderr create mode 100644 tests/ui/frontmatter/unclosed-5.rs create mode 100644 tests/ui/frontmatter/unclosed-5.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e312f15f05b0..915613a39137 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -514,6 +514,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(contracts_internals, "contract internal machinery is for internal use only"); gate_all!(where_clause_attrs, "attributes in `where` clause are unstable"); gate_all!(super_let, "`super let` is experimental"); + gate_all!(frontmatter, "frontmatters are experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 75e09cacb1f1..f6fddfb4d673 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -506,6 +506,8 @@ declare_features! ( (incomplete, fn_delegation, "1.76.0", Some(118212)), /// Allows impls for the Freeze trait. (internal, freeze_impls, "1.78.0", Some(121675)), + /// Frontmatter `---` blocks for use by external tools. + (unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index e0e3bd0e30b1..526693d3de1f 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -1,5 +1,10 @@ use std::str::Chars; +pub enum FrontmatterAllowed { + Yes, + No, +} + /// Peekable iterator over a char sequence. /// /// Next characters can be peeked via `first` method, @@ -8,6 +13,7 @@ pub struct Cursor<'a> { len_remaining: usize, /// Iterator over chars. Slightly faster than a &str. chars: Chars<'a>, + pub(crate) frontmatter_allowed: FrontmatterAllowed, #[cfg(debug_assertions)] prev: char, } @@ -15,10 +21,11 @@ pub struct Cursor<'a> { pub(crate) const EOF_CHAR: char = '\0'; impl<'a> Cursor<'a> { - pub fn new(input: &'a str) -> Cursor<'a> { + pub fn new(input: &'a str, frontmatter_allowed: FrontmatterAllowed) -> Cursor<'a> { Cursor { len_remaining: input.len(), chars: input.chars(), + frontmatter_allowed, #[cfg(debug_assertions)] prev: EOF_CHAR, } @@ -95,6 +102,11 @@ impl<'a> Cursor<'a> { Some(c) } + /// Moves to a substring by a number of bytes. + pub(crate) fn bump_bytes(&mut self, n: usize) { + self.chars = self.as_str()[n..].chars(); + } + /// Eats symbols while predicate returns true or until the end of file is reached. pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) { // It was tried making optimized version of this for eg. line comments, but diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f9c71b2fa651..2374f3882509 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -35,8 +35,8 @@ pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; use self::LiteralKind::*; use self::TokenKind::*; -pub use crate::cursor::Cursor; use crate::cursor::EOF_CHAR; +pub use crate::cursor::{Cursor, FrontmatterAllowed}; /// Parsed token. /// It doesn't contain information about data that has been parsed, @@ -57,17 +57,27 @@ impl Token { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenKind { /// A line comment, e.g. `// comment`. - LineComment { doc_style: Option }, + LineComment { + doc_style: Option, + }, /// A block comment, e.g. `/* block comment */`. /// /// Block comments can be recursive, so a sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. - BlockComment { doc_style: Option, terminated: bool }, + BlockComment { + doc_style: Option, + terminated: bool, + }, /// Any whitespace character sequence. Whitespace, + Frontmatter { + has_invalid_preceding_whitespace: bool, + invalid_infostring: bool, + }, + /// An identifier or keyword, e.g. `ident` or `continue`. Ident, @@ -109,10 +119,15 @@ pub enum TokenKind { /// this type will need to check for and reject that case. /// /// See [LiteralKind] for more details. - Literal { kind: LiteralKind, suffix_start: u32 }, + Literal { + kind: LiteralKind, + suffix_start: u32, + }, /// A lifetime, e.g. `'a`. - Lifetime { starts_with_number: bool }, + Lifetime { + starts_with_number: bool, + }, /// `;` Semi, @@ -280,7 +295,7 @@ pub fn strip_shebang(input: &str) -> Option { #[inline] pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> { debug_assert!(!input.is_empty()); - let mut cursor = Cursor::new(input); + let mut cursor = Cursor::new(input, FrontmatterAllowed::No); // Move past the leading `r` or `br`. for _ in 0..prefix_len { cursor.bump().unwrap(); @@ -290,7 +305,7 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> /// Creates an iterator that produces tokens from the input string. pub fn tokenize(input: &str) -> impl Iterator { - let mut cursor = Cursor::new(input); + let mut cursor = Cursor::new(input, FrontmatterAllowed::No); std::iter::from_fn(move || { let token = cursor.advance_token(); if token.kind != TokenKind::Eof { Some(token) } else { None } @@ -361,7 +376,34 @@ impl Cursor<'_> { Some(c) => c, None => return Token::new(TokenKind::Eof, 0), }; + let token_kind = match first_char { + c if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && is_whitespace(c) => + { + let mut last = first_char; + while is_whitespace(self.first()) { + let Some(c) = self.bump() else { + break; + }; + last = c; + } + // invalid frontmatter opening as whitespace preceding it isn't newline. + // combine the whitespace and the frontmatter to a single token as we shall + // error later. + if last != '\n' && self.as_str().starts_with("---") { + self.bump(); + self.frontmatter(true) + } else { + Whitespace + } + } + '-' if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && self.as_str().starts_with("--") => + { + // happy path + self.frontmatter(false) + } // Slash, comment or block comment. '/' => match self.first() { '/' => self.line_comment(), @@ -464,11 +506,110 @@ impl Cursor<'_> { c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Unknown, }; + if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && !matches!(token_kind, Whitespace) + { + // stop allowing frontmatters after first non-whitespace token + self.frontmatter_allowed = FrontmatterAllowed::No; + } let res = Token::new(token_kind, self.pos_within_token()); self.reset_pos_within_token(); res } + /// Given that one `-` was eaten, eat the rest of the frontmatter. + fn frontmatter(&mut self, has_invalid_preceding_whitespace: bool) -> TokenKind { + debug_assert_eq!('-', self.prev()); + + let pos = self.pos_within_token(); + self.eat_while(|c| c == '-'); + + // one `-` is eaten by the caller. + let length_opening = self.pos_within_token() - pos + 1; + + // must be ensured by the caller + debug_assert!(length_opening >= 3); + + // whitespace between the opening and the infostring. + self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); + + // copied from `eat_identifier`, but allows `.` in infostring to allow something like + // `---Cargo.toml` as a valid opener + if is_id_start(self.first()) { + self.bump(); + self.eat_while(|c| is_id_continue(c) || c == '.'); + } + + self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); + let invalid_infostring = self.first() != '\n'; + + let mut s = self.as_str(); + let mut found = false; + while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { + let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); + if s[preceding_chars_start..closing].chars().all(is_whitespace) { + // candidate found + self.bump_bytes(closing); + // in case like + // ---cargo + // --- blahblah + // or + // ---cargo + // ---- + // combine those stuff into this frontmatter token such that it gets detected later. + self.eat_until(b'\n'); + found = true; + break; + } else { + s = &s[closing + length_opening as usize..]; + } + } + + if !found { + // recovery strategy: a closing statement might have precending whitespace/newline + // but not have enough dashes to properly close. In this case, we eat until there, + // and report a mismatch in the parser. + let mut rest = self.as_str(); + // We can look for a shorter closing (starting with four dashes but closing with three) + // and other indications that Rust has started and the infostring has ended. + let mut potential_closing = rest + .find("\n---") + // n.b. only in the case where there are dashes, we move the index to the line where + // the dashes start as we eat to include that line. For other cases those are Rust code + // and not included in the frontmatter. + .map(|x| x + 1) + .or_else(|| rest.find("\nuse ")) + .or_else(|| rest.find("\n//!")) + .or_else(|| rest.find("\n#![")); + + if potential_closing.is_none() { + // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace + // on a standalone line. Might be wrong. + while let Some(closing) = rest.find("---") { + let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); + if rest[preceding_chars_start..closing].chars().all(is_whitespace) { + // candidate found + potential_closing = Some(closing); + break; + } else { + rest = &rest[closing + 3..]; + } + } + } + + if let Some(potential_closing) = potential_closing { + // bump to the potential closing, and eat everything on that line. + self.bump_bytes(potential_closing); + self.eat_until(b'\n'); + } else { + // eat everything. this will get reported as an unclosed frontmatter. + self.eat_while(|_| true); + } + } + + Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } + } + fn line_comment(&mut self) -> TokenKind { debug_assert!(self.prev() == '/' && self.first() == '/'); self.bump(); diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 8203ae70b070..fc8d9b9d57bc 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -4,7 +4,7 @@ use super::*; fn check_raw_str(s: &str, expected: Result) { let s = &format!("r{}", s); - let mut cursor = Cursor::new(s); + let mut cursor = Cursor::new(s, FrontmatterAllowed::No); cursor.bump(); let res = cursor.raw_double_quoted_string(0); assert_eq!(res, expected); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ac4f7ed64e22..3e953e6c8555 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -297,6 +297,19 @@ parse_forgot_paren = perhaps you forgot parentheses? parse_found_expr_would_be_stmt = expected expression, found `{$token}` .label = expected expression +parse_frontmatter_extra_characters_after_close = extra characters after frontmatter close are not allowed +parse_frontmatter_invalid_close_preceding_whitespace = invalid preceding whitespace for frontmatter close + .note = frontmatter close should not be preceded by whitespace +parse_frontmatter_invalid_infostring = invalid infostring for frontmatter + .note = frontmatter infostrings must be a single identifier immediately following the opening +parse_frontmatter_invalid_opening_preceding_whitespace = invalid preceding whitespace for frontmatter opening + .note = frontmatter opening should not be preceded by whitespace +parse_frontmatter_length_mismatch = frontmatter close does not match the opening + .label_opening = the opening here has {$len_opening} dashes... + .label_close = ...while the close has {$len_close} dashes +parse_frontmatter_unclosed = unclosed frontmatter + .note = frontmatter opening here was not closed + parse_function_body_equals_expr = function body cannot be `= expression;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6a6fb0eb9b5b..9e5c81d44a56 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -735,6 +735,61 @@ pub(crate) struct FoundExprWouldBeStmt { pub suggestion: ExprParenthesesNeeded, } +#[derive(Diagnostic)] +#[diag(parse_frontmatter_extra_characters_after_close)] +pub(crate) struct FrontmatterExtraCharactersAfterClose { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_infostring)] +#[note] +pub(crate) struct FrontmatterInvalidInfostring { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_opening_preceding_whitespace)] +pub(crate) struct FrontmatterInvalidOpeningPrecedingWhitespace { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_unclosed)] +pub(crate) struct FrontmatterUnclosed { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_close_preceding_whitespace)] +pub(crate) struct FrontmatterInvalidClosingPrecedingWhitespace { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_length_mismatch)] +pub(crate) struct FrontmatterLengthMismatch { + #[primary_span] + pub span: Span, + #[label(parse_label_opening)] + pub opening: Span, + #[label(parse_label_close)] + pub close: Span, + pub len_opening: usize, + pub len_close: usize, +} + #[derive(Diagnostic)] #[diag(parse_leading_plus_not_supported)] pub(crate) struct LeadingPlusNotSupported { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index e8a5cae54cf8..78c5742414b8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; -use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError}; +use rustc_lexer::{ + Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, +}; use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ @@ -15,7 +17,7 @@ use rustc_session::lint::builtin::{ TEXT_DIRECTION_CODEPOINT_IN_COMMENT, }; use rustc_session::parse::ParseSess; -use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::debug; use crate::errors; @@ -56,7 +58,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>( start_pos = start_pos + BytePos::from_usize(shebang_len); } - let cursor = Cursor::new(src); + let cursor = Cursor::new(src, FrontmatterAllowed::Yes); let mut lexer = Lexer { psess, start_pos, @@ -193,6 +195,11 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let content = self.str_from_to(content_start, content_end); self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) } + rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => { + self.validate_frontmatter(start, has_invalid_preceding_whitespace, invalid_infostring); + preceded_by_whitespace = true; + continue; + } rustc_lexer::TokenKind::Whitespace => { preceded_by_whitespace = true; continue; @@ -256,7 +263,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // was consumed. let lit_start = start + BytePos(prefix_len); self.pos = lit_start; - self.cursor = Cursor::new(&str_before[prefix_len as usize..]); + self.cursor = Cursor::new(&str_before[prefix_len as usize..], FrontmatterAllowed::No); self.report_unknown_prefix(start); let prefix_span = self.mk_sp(start, lit_start); return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); @@ -361,7 +368,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // Reset the state so we just lex the `'r`. let lt_start = start + BytePos(2); self.pos = lt_start; - self.cursor = Cursor::new(&str_before[2 as usize..]); + self.cursor = Cursor::new(&str_before[2 as usize..], FrontmatterAllowed::No); let lifetime_name = self.str_from(start); let ident = Symbol::intern(lifetime_name); @@ -474,6 +481,91 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } } + fn validate_frontmatter( + &self, + start: BytePos, + has_invalid_preceding_whitespace: bool, + invalid_infostring: bool, + ) { + let s = self.str_from(start); + let real_start = s.find("---").unwrap(); + let frontmatter_opening_pos = BytePos(real_start as u32) + start; + let s_new = &s[real_start..]; + let within = s_new.trim_start_matches('-'); + let len_opening = s_new.len() - within.len(); + + let frontmatter_opening_end_pos = frontmatter_opening_pos + BytePos(len_opening as u32); + if has_invalid_preceding_whitespace { + let line_start = + BytePos(s[..real_start].rfind("\n").map_or(0, |i| i as u32 + 1)) + start; + let span = self.mk_sp(line_start, frontmatter_opening_end_pos); + let label_span = self.mk_sp(line_start, frontmatter_opening_pos); + self.dcx().emit_err(errors::FrontmatterInvalidOpeningPrecedingWhitespace { + span, + note_span: label_span, + }); + } + + if invalid_infostring { + let line_end = s[real_start..].find('\n').unwrap_or(s[real_start..].len()); + let span = self.mk_sp( + frontmatter_opening_end_pos, + frontmatter_opening_pos + BytePos(line_end as u32), + ); + self.dcx().emit_err(errors::FrontmatterInvalidInfostring { span }); + } + + let last_line_start = within.rfind('\n').map_or(0, |i| i + 1); + let last_line = &within[last_line_start..]; + let last_line_trimmed = last_line.trim_start_matches(is_whitespace); + let last_line_start_pos = frontmatter_opening_end_pos + BytePos(last_line_start as u32); + + let frontmatter_span = self.mk_sp(frontmatter_opening_pos, self.pos); + self.psess.gated_spans.gate(sym::frontmatter, frontmatter_span); + + if !last_line_trimmed.starts_with("---") { + let label_span = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos); + self.dcx().emit_err(errors::FrontmatterUnclosed { + span: frontmatter_span, + note_span: label_span, + }); + return; + } + + if last_line_trimmed.len() != last_line.len() { + let line_end = last_line_start_pos + BytePos(last_line.len() as u32); + let span = self.mk_sp(last_line_start_pos, line_end); + let whitespace_end = + last_line_start_pos + BytePos((last_line.len() - last_line_trimmed.len()) as u32); + let label_span = self.mk_sp(last_line_start_pos, whitespace_end); + self.dcx().emit_err(errors::FrontmatterInvalidClosingPrecedingWhitespace { + span, + note_span: label_span, + }); + } + + let rest = last_line_trimmed.trim_start_matches('-'); + let len_close = last_line_trimmed.len() - rest.len(); + if len_close != len_opening { + let span = self.mk_sp(frontmatter_opening_pos, self.pos); + let opening = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos); + let last_line_close_pos = last_line_start_pos + BytePos(len_close as u32); + let close = self.mk_sp(last_line_start_pos, last_line_close_pos); + self.dcx().emit_err(errors::FrontmatterLengthMismatch { + span, + opening, + close, + len_opening, + len_close, + }); + } + + if !rest.trim_matches(is_whitespace).is_empty() { + let span = self.mk_sp(last_line_start_pos, self.pos); + self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span }); + } + } + fn cook_doc_comment( &self, content_start: BytePos, @@ -839,7 +931,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let space_pos = start + BytePos(1); let space_span = self.mk_sp(space_pos, space_pos); - let mut cursor = Cursor::new(str_before); + let mut cursor = Cursor::new(str_before, FrontmatterAllowed::No); let (is_string, span, unterminated) = match cursor.guarded_double_quoted_string() { Some(rustc_lexer::GuardedStr { n_hashes, terminated, token_len }) => { @@ -905,7 +997,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // For backwards compatibility, roll back to after just the first `#` // and return the `Pound` token. self.pos = start + BytePos(1); - self.cursor = Cursor::new(&str_before[1..]); + self.cursor = Cursor::new(&str_before[1..], FrontmatterAllowed::No); token::Pound } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ba3e6d7ca826..d7dbdf04a8c3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1047,6 +1047,7 @@ symbols! { from_u16, from_usize, from_yeet, + frontmatter, fs_create_dir, fsub_algebraic, fsub_fast, diff --git a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md index 2f8b52d40439..d660dd13fe47 100644 --- a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md +++ b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md @@ -2,7 +2,7 @@ The tracking issue for this feature is: [#44874] -[#38788]: https://github.com/rust-lang/rust/issues/44874 +[#44874]: https://github.com/rust-lang/rust/issues/44874 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/f128.md b/src/doc/unstable-book/src/language-features/f128.md index 0cc5f6772302..b523ffe10f25 100644 --- a/src/doc/unstable-book/src/language-features/f128.md +++ b/src/doc/unstable-book/src/language-features/f128.md @@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909] --- -Enable the `f128` type for IEEE 128-bit floating numbers (quad precision). +Enable the `f128` type for IEEE 128-bit floating numbers (quad precision). diff --git a/src/doc/unstable-book/src/language-features/f16.md b/src/doc/unstable-book/src/language-features/f16.md index efb07a5146d4..5f31dcbb06c0 100644 --- a/src/doc/unstable-book/src/language-features/f16.md +++ b/src/doc/unstable-book/src/language-features/f16.md @@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909] --- -Enable the `f16` type for IEEE 16-bit floating numbers (half precision). +Enable the `f16` type for IEEE 16-bit floating numbers (half precision). diff --git a/src/doc/unstable-book/src/language-features/frontmatter.md b/src/doc/unstable-book/src/language-features/frontmatter.md new file mode 100644 index 000000000000..1d5b4feb6ac1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/frontmatter.md @@ -0,0 +1,25 @@ +# `frontmatter` + +The tracking issue for this feature is: [#136889] + +------ + +The `frontmatter` feature allows an extra metadata block at the top of files for consumption by +external tools. For example, it can be used by [`cargo-script`] files to specify dependencies. + +```rust +#!/usr/bin/env -S cargo -Zscript +--- +[dependencies] +libc = "0.2.172" +--- +#![feature(frontmatter)] +# mod libc { pub type c_int = i32; } + +fn main() { + let x: libc::c_int = 1i32; +} +``` + +[#136889]: https://github.com/rust-lang/rust/issues/136889 +[`cargo-script`]: https://rust-lang.github.io/rfcs/3502-cargo-script.html diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c943d3ad4d05..2db1ea8450ce 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -9,7 +9,7 @@ use std::collections::VecDeque; use std::fmt::{Display, Write}; use rustc_data_structures::fx::FxIndexMap; -use rustc_lexer::{Cursor, LiteralKind, TokenKind}; +use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, DUMMY_SP, Span}; @@ -638,7 +638,8 @@ impl<'src> Classifier<'src> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondence_map`. fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self { - let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) }); + let tokens = + PeekIter::new(TokenIter { src, cursor: Cursor::new(src, FrontmatterAllowed::Yes) }); let decorations = decoration_info.map(Decorations::new); Classifier { tokens, @@ -884,6 +885,7 @@ impl<'src> Classifier<'src> { | TokenKind::At | TokenKind::Tilde | TokenKind::Colon + | TokenKind::Frontmatter { .. } | TokenKind::Unknown => return no_highlight(sink), TokenKind::Question => Class::QuestionMark, diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 585e7ffb1aef..0a5c16dc4c49 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -179,6 +179,15 @@ impl<'a> Converter<'a> { COMMENT } + rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => { + if *has_invalid_preceding_whitespace { + err = "invalid preceding whitespace for frontmatter opening" + } else if *invalid_infostring { + err = "invalid infostring for frontmatter" + } + FRONTMATTER + } + rustc_lexer::TokenKind::Whitespace => WHITESPACE, rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE, diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index e6f93a1fbda5..b1727509b137 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -150,6 +150,7 @@ pub enum SyntaxKind { STRING, COMMENT, ERROR, + FRONTMATTER, IDENT, LIFETIME_IDENT, NEWLINE, @@ -483,6 +484,7 @@ impl SyntaxKind { | YIELD_EXPR | COMMENT | ERROR + | FRONTMATTER | IDENT | LIFETIME_IDENT | NEWLINE @@ -994,7 +996,7 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } +macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; [frontmatter] => { $ crate :: SyntaxKind :: FRONTMATTER } ; } impl ::core::marker::Copy for SyntaxKind {} impl ::core::clone::Clone for SyntaxKind { #[inline] diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index a0ae0d68581a..10abca7d35d9 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -133,6 +133,7 @@ Meta = SourceFile = '#shebang'? + '#frontmatter'? Attr* Item* diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 1243f6418fe2..cd9f4dba8908 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1524,6 +1524,10 @@ impl ast::HasAttrs for SourceFile {} impl ast::HasDocComments for SourceFile {} impl ast::HasModuleItem for SourceFile {} impl SourceFile { + #[inline] + pub fn frontmatter_token(&self) -> Option { + support::token(&self.syntax, T![frontmatter]) + } #[inline] pub fn shebang_token(&self) -> Option { support::token(&self.syntax, T![shebang]) } } diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs index 82df78c1a898..b5350de2b517 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs @@ -670,6 +670,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String { [ident] => { $crate::SyntaxKind::IDENT }; [string] => { $crate::SyntaxKind::STRING }; [shebang] => { $crate::SyntaxKind::SHEBANG }; + [frontmatter] => { $crate::SyntaxKind::FRONTMATTER }; } impl ::core::marker::Copy for SyntaxKind {} diff --git a/tests/ui/feature-gates/feature-gate-frontmatter.rs b/tests/ui/feature-gates/feature-gate-frontmatter.rs new file mode 100644 index 000000000000..58e1f57eec02 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-frontmatter.rs @@ -0,0 +1,5 @@ +---cargo +//~^ ERROR: frontmatters are experimental +--- + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-frontmatter.stderr b/tests/ui/feature-gates/feature-gate-frontmatter.stderr new file mode 100644 index 000000000000..57d38db8e76a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-frontmatter.stderr @@ -0,0 +1,15 @@ +error[E0658]: frontmatters are experimental + --> $DIR/feature-gate-frontmatter.rs:1:1 + | +LL | / ---cargo +LL | | +LL | | --- + | |___^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/frontmatter/auxiliary/lib.rs b/tests/ui/frontmatter/auxiliary/lib.rs new file mode 100644 index 000000000000..ff7094f410f5 --- /dev/null +++ b/tests/ui/frontmatter/auxiliary/lib.rs @@ -0,0 +1,6 @@ +---something +--- + +pub fn foo(x: i32) -> i32 { + -x +} diff --git a/tests/ui/frontmatter/auxiliary/makro.rs b/tests/ui/frontmatter/auxiliary/makro.rs new file mode 100644 index 000000000000..78e7417afb5f --- /dev/null +++ b/tests/ui/frontmatter/auxiliary/makro.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn check(_: TokenStream) -> TokenStream { + assert!("---\n---".parse::().unwrap().is_empty()); + Default::default() +} diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.rs b/tests/ui/frontmatter/dot-in-infostring-leading.rs new file mode 100644 index 000000000000..0d3d699644e9 --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-leading.rs @@ -0,0 +1,9 @@ +---.toml +//~^ ERROR: invalid infostring for frontmatter +--- + +// infostrings cannot have leading dots + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.stderr b/tests/ui/frontmatter/dot-in-infostring-leading.stderr new file mode 100644 index 000000000000..bc86bd80eece --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-leading.stderr @@ -0,0 +1,10 @@ +error: invalid infostring for frontmatter + --> $DIR/dot-in-infostring-leading.rs:1:4 + | +LL | ---.toml + | ^^^^^ + | + = note: frontmatter infostrings must be a single identifier immediately following the opening + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/dot-in-infostring-non-leading.rs b/tests/ui/frontmatter/dot-in-infostring-non-leading.rs new file mode 100644 index 000000000000..a4d17bb6e813 --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-non-leading.rs @@ -0,0 +1,9 @@ +---Cargo.toml +--- + +// infostrings can contain dots as long as a dot isn't the first character. +//@ check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/escape.rs b/tests/ui/frontmatter/escape.rs new file mode 100644 index 000000000000..0e6f064607e8 --- /dev/null +++ b/tests/ui/frontmatter/escape.rs @@ -0,0 +1,14 @@ +---- + +--- + +---- + +//@ check-pass + +// This test checks that longer dashes for opening and closing can be used to +// escape sequences such as three dashes inside the frontmatter block. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/extra-after-end.rs b/tests/ui/frontmatter/extra-after-end.rs new file mode 100644 index 000000000000..de2cf4cc85ef --- /dev/null +++ b/tests/ui/frontmatter/extra-after-end.rs @@ -0,0 +1,7 @@ +--- +---cargo +//~^ ERROR: extra characters after frontmatter close are not allowed + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/extra-after-end.stderr b/tests/ui/frontmatter/extra-after-end.stderr new file mode 100644 index 000000000000..c2770fdfd41f --- /dev/null +++ b/tests/ui/frontmatter/extra-after-end.stderr @@ -0,0 +1,8 @@ +error: extra characters after frontmatter close are not allowed + --> $DIR/extra-after-end.rs:2:1 + | +LL | ---cargo + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.rs b/tests/ui/frontmatter/frontmatter-after-tokens.rs new file mode 100644 index 000000000000..6683991dc4af --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-after-tokens.rs @@ -0,0 +1,10 @@ +#![feature(frontmatter)] + +--- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +// frontmatters must be at the start of a file. This test ensures that. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.stderr b/tests/ui/frontmatter/frontmatter-after-tokens.stderr new file mode 100644 index 000000000000..919456924d02 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-after-tokens.stderr @@ -0,0 +1,10 @@ +error: expected item, found `-` + --> $DIR/frontmatter-after-tokens.rs:3:1 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs b/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs new file mode 100644 index 000000000000..ea042edef06b --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs @@ -0,0 +1,12 @@ +---uwu +🏳️‍⚧️ +--- + +//@ check-pass + +#![feature(frontmatter)] + +// check that frontmatter blocks can have tokens that are otherwise not accepted by +// the lexer as Rust code. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.rs b/tests/ui/frontmatter/frontmatter-whitespace-1.rs new file mode 100644 index 000000000000..8b6e2d1af849 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.rs @@ -0,0 +1,10 @@ + --- +//~^ ERROR: invalid preceding whitespace for frontmatter opening + --- +//~^ ERROR: invalid preceding whitespace for frontmatter close + +#![feature(frontmatter)] + +// check that whitespaces should not precede the frontmatter opening or close. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr new file mode 100644 index 000000000000..37ece27acb22 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr @@ -0,0 +1,26 @@ +error: invalid preceding whitespace for frontmatter opening + --> $DIR/frontmatter-whitespace-1.rs:1:1 + | +LL | --- + | ^^^^^ + | +note: frontmatter opening should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-1.rs:1:1 + | +LL | --- + | ^^ + +error: invalid preceding whitespace for frontmatter close + --> $DIR/frontmatter-whitespace-1.rs:3:1 + | +LL | --- + | ^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-1.rs:3:1 + | +LL | --- + | ^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.rs b/tests/ui/frontmatter/frontmatter-whitespace-2.rs new file mode 100644 index 000000000000..e8c100849b40 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.rs @@ -0,0 +1,15 @@ +---cargo + +//@ compile-flags: --crate-type lib + +#![feature(frontmatter)] + +fn foo(x: i32) -> i32 { + ---x + //~^ ERROR: invalid preceding whitespace for frontmatter close + //~| ERROR: extra characters after frontmatter close are not allowed +} +//~^ ERROR: unexpected closing delimiter: `}` + +// this test is for the weird case that valid Rust code can have three dashes +// within them and get treated as a frontmatter close. diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr new file mode 100644 index 000000000000..ada6af0ec04c --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr @@ -0,0 +1,26 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^ + +error: extra characters after frontmatter close are not allowed + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^^^^^ + +error: unexpected closing delimiter: `}` + --> $DIR/frontmatter-whitespace-2.rs:11:1 + | +LL | } + | ^ unexpected closing delimiter + +error: aborting due to 3 previous errors + diff --git a/tests/ui/frontmatter/frontmatter-whitespace-3.rs b/tests/ui/frontmatter/frontmatter-whitespace-3.rs new file mode 100644 index 000000000000..95e0981e2ae8 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-3.rs @@ -0,0 +1,16 @@ + + +---cargo +--- + +// please note the whitespace characters after the first four lines. +// This ensures that we accept whitespaces before the frontmatter, after +// the frontmatter opening and the frontmatter close. + +//@ check-pass +// ignore-tidy-end-whitespace +// ignore-tidy-leading-newlines + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-4.rs b/tests/ui/frontmatter/frontmatter-whitespace-4.rs new file mode 100644 index 000000000000..3bda3227838c --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-4.rs @@ -0,0 +1,9 @@ +--- cargo +--- + +//@ check-pass +// A frontmatter infostring can have leading whitespace. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/included-frontmatter.rs b/tests/ui/frontmatter/included-frontmatter.rs new file mode 100644 index 000000000000..57616cd1228c --- /dev/null +++ b/tests/ui/frontmatter/included-frontmatter.rs @@ -0,0 +1,12 @@ +#![feature(frontmatter)] + +//@ check-pass + +include!("auxiliary/lib.rs"); + +// auxiliary/lib.rs contains a frontmatter. Ensure that we can use them in an +// `include!` macro. + +fn main() { + foo(1); +} diff --git a/tests/ui/frontmatter/infostring-fail.rs b/tests/ui/frontmatter/infostring-fail.rs new file mode 100644 index 000000000000..91542f62f1a5 --- /dev/null +++ b/tests/ui/frontmatter/infostring-fail.rs @@ -0,0 +1,9 @@ +---cargo,clippy +//~^ ERROR: invalid infostring for frontmatter +--- + +// infostrings can only be a single identifier. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/infostring-fail.stderr b/tests/ui/frontmatter/infostring-fail.stderr new file mode 100644 index 000000000000..6b264abc90f1 --- /dev/null +++ b/tests/ui/frontmatter/infostring-fail.stderr @@ -0,0 +1,10 @@ +error: invalid infostring for frontmatter + --> $DIR/infostring-fail.rs:1:4 + | +LL | ---cargo,clippy + | ^^^^^^^^^^^^ + | + = note: frontmatter infostrings must be a single identifier immediately following the opening + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/mismatch-1.rs b/tests/ui/frontmatter/mismatch-1.rs new file mode 100644 index 000000000000..37e2b0af6b18 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-1.rs @@ -0,0 +1,10 @@ +---cargo +//~^ ERROR: frontmatter close does not match the opening +---- + +// there must be the same number of dashes for both the opening and the close +// of the frontmatter. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/mismatch-1.stderr b/tests/ui/frontmatter/mismatch-1.stderr new file mode 100644 index 000000000000..b6e29294d9e1 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-1.stderr @@ -0,0 +1,16 @@ +error: frontmatter close does not match the opening + --> $DIR/mismatch-1.rs:1:1 + | +LL | ---cargo + | ^-- + | | + | _the opening here has 3 dashes... + | | +LL | | +LL | | ---- + | |_---^ + | | + | ...while the close has 4 dashes + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/mismatch-2.rs b/tests/ui/frontmatter/mismatch-2.rs new file mode 100644 index 000000000000..422abe1d6bc9 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-2.rs @@ -0,0 +1,8 @@ +----cargo +//~^ ERROR: frontmatter close does not match the opening +---cargo +//~^ ERROR: extra characters after frontmatter close are not allowed + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/mismatch-2.stderr b/tests/ui/frontmatter/mismatch-2.stderr new file mode 100644 index 000000000000..90bb7b80bcea --- /dev/null +++ b/tests/ui/frontmatter/mismatch-2.stderr @@ -0,0 +1,22 @@ +error: frontmatter close does not match the opening + --> $DIR/mismatch-2.rs:1:1 + | +LL | ----cargo + | ^--- + | | + | _the opening here has 4 dashes... + | | +LL | | +LL | | ---cargo + | |_---____^ + | | + | ...while the close has 3 dashes + +error: extra characters after frontmatter close are not allowed + --> $DIR/mismatch-2.rs:3:1 + | +LL | ---cargo + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/multifrontmatter-2.rs b/tests/ui/frontmatter/multifrontmatter-2.rs new file mode 100644 index 000000000000..33cc30cb4655 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter-2.rs @@ -0,0 +1,12 @@ +--- + --- +//~^ ERROR: invalid preceding whitespace for frontmatter close + + --- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter-2.stderr b/tests/ui/frontmatter/multifrontmatter-2.stderr new file mode 100644 index 000000000000..ed9ac4029e27 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter-2.stderr @@ -0,0 +1,22 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/multifrontmatter-2.rs:2:1 + | +LL | --- + | ^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/multifrontmatter-2.rs:2:1 + | +LL | --- + | ^ + +error: expected item, found `-` + --> $DIR/multifrontmatter-2.rs:5:2 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/multifrontmatter.rs b/tests/ui/frontmatter/multifrontmatter.rs new file mode 100644 index 000000000000..f3afa47bd383 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter.rs @@ -0,0 +1,13 @@ +--- +--- + +--- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +// test that we do not parse another frontmatter block after the first one. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter.stderr b/tests/ui/frontmatter/multifrontmatter.stderr new file mode 100644 index 000000000000..2e9d1cee9ddb --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter.stderr @@ -0,0 +1,10 @@ +error: expected item, found `-` + --> $DIR/multifrontmatter.rs:4:1 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/proc-macro-observer.rs new file mode 100644 index 000000000000..bafbe912032e --- /dev/null +++ b/tests/ui/frontmatter/proc-macro-observer.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ proc-macro: makro.rs +//@ edition: 2021 + +#![feature(frontmatter)] + +makro::check!(); + +// checks that a proc-macro cannot observe frontmatter tokens. +// see auxiliary/makro.rs for how it is tested. + +fn main() {} diff --git a/tests/ui/frontmatter/shebang.rs b/tests/ui/frontmatter/shebang.rs new file mode 100644 index 000000000000..abd983f219bd --- /dev/null +++ b/tests/ui/frontmatter/shebang.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env -S cargo -Zscript +--- +[dependencies] +clap = "4" +--- + +//@ check-pass + +// Shebangs on a file can precede a frontmatter. + +#![feature(frontmatter)] + +fn main () {} diff --git a/tests/ui/frontmatter/unclosed-1.rs b/tests/ui/frontmatter/unclosed-1.rs new file mode 100644 index 000000000000..d8b52b3e69c7 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-1.rs @@ -0,0 +1,10 @@ +----cargo +//~^ ERROR: unclosed frontmatter + +// This test checks that the #! characters can help us recover a frontmatter +// close. There should not be a "missing `main` function" error as the rest +// are properly parsed. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-1.stderr b/tests/ui/frontmatter/unclosed-1.stderr new file mode 100644 index 000000000000..04031d128398 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-1.stderr @@ -0,0 +1,16 @@ +error: unclosed frontmatter + --> $DIR/unclosed-1.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-1.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/unclosed-2.rs b/tests/ui/frontmatter/unclosed-2.rs new file mode 100644 index 000000000000..add266dce5b0 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-2.rs @@ -0,0 +1,15 @@ +----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +//@ compile-flags: --crate-type lib + +// Leading whitespace on the feature line prevents recovery. However +// the dashes quoted will not be used for recovery and the entire file +// should be treated as within the frontmatter block. + + #![feature(frontmatter)] + +fn foo() -> &str { + "----" +} diff --git a/tests/ui/frontmatter/unclosed-2.stderr b/tests/ui/frontmatter/unclosed-2.stderr new file mode 100644 index 000000000000..0a4022c1557b --- /dev/null +++ b/tests/ui/frontmatter/unclosed-2.stderr @@ -0,0 +1,31 @@ +error: unclosed frontmatter + --> $DIR/unclosed-2.rs:1:1 + | +LL | / ----cargo +... | +LL | | "----" +LL | | } + | |__^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-2.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error[E0658]: frontmatters are experimental + --> $DIR/unclosed-2.rs:1:1 + | +LL | / ----cargo +... | +LL | | "----" +LL | | } + | |__^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/frontmatter/unclosed-3.rs b/tests/ui/frontmatter/unclosed-3.rs new file mode 100644 index 000000000000..75f3fbda675c --- /dev/null +++ b/tests/ui/frontmatter/unclosed-3.rs @@ -0,0 +1,16 @@ +----cargo +//~^ ERROR: frontmatter close does not match the opening + +//@ compile-flags: --crate-type lib + +// Unfortunate recovery situation. Not really preventable with improving the +// recovery strategy, but this type of code is rare enough already. + + #![feature(frontmatter)] + +fn foo(x: i32) -> i32 { + ---x + //~^ ERROR: invalid preceding whitespace for frontmatter close + //~| ERROR: extra characters after frontmatter close are not allowed +} +//~^ ERROR: unexpected closing delimiter: `}` diff --git a/tests/ui/frontmatter/unclosed-3.stderr b/tests/ui/frontmatter/unclosed-3.stderr new file mode 100644 index 000000000000..cd69cb000408 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-3.stderr @@ -0,0 +1,41 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^ + +error: frontmatter close does not match the opening + --> $DIR/unclosed-3.rs:1:1 + | +LL | ----cargo + | ^--- + | | + | _the opening here has 4 dashes... + | | +... | +LL | | fn foo(x: i32) -> i32 { +LL | | ---x + | |_---____^ + | | + | ...while the close has 3 dashes + +error: extra characters after frontmatter close are not allowed + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^^^^^ + +error: unexpected closing delimiter: `}` + --> $DIR/unclosed-3.rs:15:1 + | +LL | } + | ^ unexpected closing delimiter + +error: aborting due to 4 previous errors + diff --git a/tests/ui/frontmatter/unclosed-4.rs b/tests/ui/frontmatter/unclosed-4.rs new file mode 100644 index 000000000000..41f6461db634 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-4.rs @@ -0,0 +1,9 @@ +----cargo +//~^ ERROR: unclosed frontmatter + +//! Similarly, a module-level content should allow for recovery as well (as +//! per unclosed-1.rs) + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-4.stderr b/tests/ui/frontmatter/unclosed-4.stderr new file mode 100644 index 000000000000..b3ba56937bba --- /dev/null +++ b/tests/ui/frontmatter/unclosed-4.stderr @@ -0,0 +1,16 @@ +error: unclosed frontmatter + --> $DIR/unclosed-4.rs:1:1 + | +LL | / ----cargo +LL | | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-4.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/unclosed-5.rs b/tests/ui/frontmatter/unclosed-5.rs new file mode 100644 index 000000000000..9abbcfff94c7 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-5.rs @@ -0,0 +1,10 @@ +----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +// Similarly, a use statement should allow for recovery as well (as +// per unclosed-1.rs) + +use std::env; + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-5.stderr b/tests/ui/frontmatter/unclosed-5.stderr new file mode 100644 index 000000000000..e904014a175a --- /dev/null +++ b/tests/ui/frontmatter/unclosed-5.stderr @@ -0,0 +1,29 @@ +error: unclosed frontmatter + --> $DIR/unclosed-5.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-5.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error[E0658]: frontmatters are experimental + --> $DIR/unclosed-5.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From cdf4143eb8209926e39a36df244880734bd46a23 Mon Sep 17 00:00:00 2001 From: Vladimir Krivopalov Date: Mon, 3 Mar 2025 12:06:09 -0500 Subject: [PATCH 239/302] Implement `VecDeque::truncate_front()` Tracking issue: #140667 Signed-off-by: Vladimir Krivopalov --- .../alloc/src/collections/vec_deque/mod.rs | 67 ++++++++++++++++++ library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/vec_deque.rs | 69 +++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index f8844e2d3a5c..712f38a76c01 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1188,6 +1188,73 @@ impl VecDeque { } } + /// Shortens the deque, keeping the last `len` elements and dropping + /// the rest. + /// + /// If `len` is greater or equal to the deque's current length, this has + /// no effect. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vec_deque_truncate_front)] + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_front(5); + /// buf.push_front(10); + /// buf.push_front(15); + /// assert_eq!(buf, [15, 10, 5]); + /// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..])); + /// buf.truncate_front(1); + /// assert_eq!(buf.as_slices(), (&[5][..], &[][..])); + /// ``` + #[unstable(feature = "vec_deque_truncate_front", issue = "140667")] + pub fn truncate_front(&mut self, len: usize) { + /// Runs the destructor for all items in the slice when it gets dropped (normally or + /// during unwinding). + struct Dropper<'a, T>(&'a mut [T]); + + impl<'a, T> Drop for Dropper<'a, T> { + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(self.0); + } + } + } + + unsafe { + if len >= self.len { + // No action is taken + return; + } + + let (front, back) = self.as_mut_slices(); + if len > back.len() { + // The 'back' slice remains unchanged. + // front.len() + back.len() == self.len, so 'end' is non-negative + // and end < front.len() + let end = front.len() - (len - back.len()); + let drop_front = front.get_unchecked_mut(..end) as *mut _; + self.head += end; + self.len = len; + ptr::drop_in_place(drop_front); + } else { + let drop_front = front as *mut _; + // 'end' is non-negative by the condition above + let end = back.len() - len; + let drop_back = back.get_unchecked_mut(..end) as *mut _; + self.head = self.to_physical_idx(self.len - len); + self.len = len; + + // Make sure the second half is dropped even when a destructor + // in the first one panics. + let _back_dropper = Dropper(&mut *drop_back); + ptr::drop_in_place(drop_front); + } + } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index f1f4cc6f93bb..38309585fad6 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -37,6 +37,7 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_deque_pop_if)] +#![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![allow(internal_features)] diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 1b03c29e5bda..b77ea3a312be 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -1686,6 +1686,40 @@ fn truncate_leak() { assert_eq!(unsafe { DROPS }, 7); } +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn truncate_front_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok(); + + assert_eq!(unsafe { DROPS }, 7); +} + #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { @@ -1863,3 +1897,38 @@ fn test_collect_from_into_iter_keeps_allocation() { assert_eq!(v.capacity(), 13); } } + +#[test] +fn test_truncate_front() { + let mut v = VecDeque::with_capacity(13); + v.extend(0..7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(10); + assert_eq!(v.len(), 7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(7); + assert_eq!(v.len(), 7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(3); + assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice())); + assert_eq!(v.len(), 3); + v.truncate_front(0); + assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice())); + assert_eq!(v.len(), 0); + + v.clear(); + v.extend(0..7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.push_front(9); + v.push_front(8); + v.push_front(7); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(12); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(10); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(8); + assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(5); + assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); +} From b796179f9888b0aff6edf9c393274d9f792a0700 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 15:10:21 +0200 Subject: [PATCH 240/302] Created `tests/rustdoc/reexports` subfolder to limit number of files at the top level --- .../rustdoc/{ => reexport}/alias-reexport.rs | 0 .../rustdoc/{ => reexport}/alias-reexport2.rs | 0 .../anonymous-reexport-108931.rs | 0 .../{ => reexport}/anonymous-reexport.rs | 0 .../auxiliary/alias-reexport.rs | 0 .../auxiliary/alias-reexport2.rs | 0 .../reexport/auxiliary/all-item-types.rs | 22 +++++++++++++++++++ ...ue-113982-doc_auto_cfg-reexport-foreign.rs | 0 .../{ => reexport}/auxiliary/issue-28927-1.rs | 0 .../{ => reexport}/auxiliary/issue-28927-2.rs | 0 .../auxiliary/primitive-reexport.rs | 0 .../auxiliary/reexport-check.rs | 0 .../auxiliary/reexport-doc-aux.rs | 0 .../{ => reexport}/auxiliary/reexports.rs | 0 .../{ => reexport}/blanket-reexport-item.rs | 0 .../{ => reexport}/cfg_doc_reexport.rs | 0 .../doc-hidden-reexports-109449.rs | 0 .../doc_auto_cfg-reexport-foreign-113982.rs | 0 .../duplicated-glob-reexport-60522.rs | 0 .../enum-variant-reexport-35488.rs | 0 .../{ => reexport}/foreigntype-reexport.rs | 0 .../glob-reexport-attribute-merge-120487.rs | 0 ...b-reexport-attribute-merge-doc-auto-cfg.rs | 0 .../ice-reexport-crate-root-28927.rs | 0 .../{ => reexport}/local-reexport-doc.rs | 0 .../{ => reexport}/no-compiler-reexport.rs | 0 .../overlapping-reexport-105735-2.rs | 0 .../overlapping-reexport-105735.rs | 0 .../{ => reexport}/primitive-reexport.rs | 0 .../pub-reexport-of-pub-reexport-46506.rs | 0 .../{ => reexport}/reexport-attr-merge.rs | 0 tests/rustdoc/{ => reexport}/reexport-cfg.rs | 0 .../rustdoc/{ => reexport}/reexport-check.rs | 0 .../{ => reexport}/reexport-dep-foreign-fn.rs | 0 .../reexport-doc-hidden-inside-private.rs | 0 .../{ => reexport}/reexport-doc-hidden.rs | 0 tests/rustdoc/{ => reexport}/reexport-doc.rs | 0 .../{ => reexport}/reexport-hidden-macro.rs | 0 .../rustdoc/{ => reexport}/reexport-macro.rs | 0 .../{ => reexport}/reexport-of-doc-hidden.rs | 0 .../reexport-of-reexport-108679.rs | 0 ...ability-tags-deprecated-and-portability.rs | 0 ...stability-tags-unstable-and-portability.rs | 0 .../reexport-trait-from-hidden-111064-2.rs | 0 .../reexport-trait-from-hidden-111064.rs | 0 .../{ => reexport}/reexports-of-same-name.rs | 0 .../rustdoc/{ => reexport}/reexports-priv.rs | 0 tests/rustdoc/{ => reexport}/reexports.rs | 0 48 files changed, 22 insertions(+) rename tests/rustdoc/{ => reexport}/alias-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/alias-reexport2.rs (100%) rename tests/rustdoc/{ => reexport}/anonymous-reexport-108931.rs (100%) rename tests/rustdoc/{ => reexport}/anonymous-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/alias-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/alias-reexport2.rs (100%) create mode 100644 tests/rustdoc/reexport/auxiliary/all-item-types.rs rename tests/rustdoc/{ => reexport}/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/issue-28927-1.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/issue-28927-2.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/primitive-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/reexport-check.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/reexport-doc-aux.rs (100%) rename tests/rustdoc/{ => reexport}/auxiliary/reexports.rs (100%) rename tests/rustdoc/{ => reexport}/blanket-reexport-item.rs (100%) rename tests/rustdoc/{ => reexport}/cfg_doc_reexport.rs (100%) rename tests/rustdoc/{ => reexport}/doc-hidden-reexports-109449.rs (100%) rename tests/rustdoc/{ => reexport}/doc_auto_cfg-reexport-foreign-113982.rs (100%) rename tests/rustdoc/{ => reexport}/duplicated-glob-reexport-60522.rs (100%) rename tests/rustdoc/{ => reexport}/enum-variant-reexport-35488.rs (100%) rename tests/rustdoc/{ => reexport}/foreigntype-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/glob-reexport-attribute-merge-120487.rs (100%) rename tests/rustdoc/{ => reexport}/glob-reexport-attribute-merge-doc-auto-cfg.rs (100%) rename tests/rustdoc/{ => reexport}/ice-reexport-crate-root-28927.rs (100%) rename tests/rustdoc/{ => reexport}/local-reexport-doc.rs (100%) rename tests/rustdoc/{ => reexport}/no-compiler-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/overlapping-reexport-105735-2.rs (100%) rename tests/rustdoc/{ => reexport}/overlapping-reexport-105735.rs (100%) rename tests/rustdoc/{ => reexport}/primitive-reexport.rs (100%) rename tests/rustdoc/{ => reexport}/pub-reexport-of-pub-reexport-46506.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-attr-merge.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-cfg.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-check.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-dep-foreign-fn.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-doc-hidden-inside-private.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-doc-hidden.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-doc.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-hidden-macro.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-macro.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-of-doc-hidden.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-of-reexport-108679.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-stability-tags-deprecated-and-portability.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-stability-tags-unstable-and-portability.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-trait-from-hidden-111064-2.rs (100%) rename tests/rustdoc/{ => reexport}/reexport-trait-from-hidden-111064.rs (100%) rename tests/rustdoc/{ => reexport}/reexports-of-same-name.rs (100%) rename tests/rustdoc/{ => reexport}/reexports-priv.rs (100%) rename tests/rustdoc/{ => reexport}/reexports.rs (100%) diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/reexport/alias-reexport.rs similarity index 100% rename from tests/rustdoc/alias-reexport.rs rename to tests/rustdoc/reexport/alias-reexport.rs diff --git a/tests/rustdoc/alias-reexport2.rs b/tests/rustdoc/reexport/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/alias-reexport2.rs rename to tests/rustdoc/reexport/alias-reexport2.rs diff --git a/tests/rustdoc/anonymous-reexport-108931.rs b/tests/rustdoc/reexport/anonymous-reexport-108931.rs similarity index 100% rename from tests/rustdoc/anonymous-reexport-108931.rs rename to tests/rustdoc/reexport/anonymous-reexport-108931.rs diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/reexport/anonymous-reexport.rs similarity index 100% rename from tests/rustdoc/anonymous-reexport.rs rename to tests/rustdoc/reexport/anonymous-reexport.rs diff --git a/tests/rustdoc/auxiliary/alias-reexport.rs b/tests/rustdoc/reexport/auxiliary/alias-reexport.rs similarity index 100% rename from tests/rustdoc/auxiliary/alias-reexport.rs rename to tests/rustdoc/reexport/auxiliary/alias-reexport.rs diff --git a/tests/rustdoc/auxiliary/alias-reexport2.rs b/tests/rustdoc/reexport/auxiliary/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/auxiliary/alias-reexport2.rs rename to tests/rustdoc/reexport/auxiliary/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/auxiliary/all-item-types.rs b/tests/rustdoc/reexport/auxiliary/all-item-types.rs new file mode 100644 index 000000000000..f94bd998717a --- /dev/null +++ b/tests/rustdoc/reexport/auxiliary/all-item-types.rs @@ -0,0 +1,22 @@ +#![feature(extern_types)] + +pub mod foo_mod {} +extern "C" { + pub fn foo_ffn(); + pub static FOO_FSTATIC: FooStruct; + pub type FooFType; +} +pub fn foo_fn() {} +pub trait FooTrait {} +pub struct FooStruct; +pub enum FooEnum {} +pub union FooUnion { + x: (), +} +pub type FooType = FooStruct; +pub static FOO_STATIC: FooStruct = FooStruct; +pub const FOO_CONSTANT: FooStruct = FooStruct; +#[macro_export] +macro_rules! foo_macro { + () => (); +} diff --git a/tests/rustdoc/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs b/tests/rustdoc/reexport/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs rename to tests/rustdoc/reexport/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs diff --git a/tests/rustdoc/auxiliary/issue-28927-1.rs b/tests/rustdoc/reexport/auxiliary/issue-28927-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-28927-1.rs rename to tests/rustdoc/reexport/auxiliary/issue-28927-1.rs diff --git a/tests/rustdoc/auxiliary/issue-28927-2.rs b/tests/rustdoc/reexport/auxiliary/issue-28927-2.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-28927-2.rs rename to tests/rustdoc/reexport/auxiliary/issue-28927-2.rs diff --git a/tests/rustdoc/auxiliary/primitive-reexport.rs b/tests/rustdoc/reexport/auxiliary/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/auxiliary/primitive-reexport.rs rename to tests/rustdoc/reexport/auxiliary/primitive-reexport.rs diff --git a/tests/rustdoc/auxiliary/reexport-check.rs b/tests/rustdoc/reexport/auxiliary/reexport-check.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexport-check.rs rename to tests/rustdoc/reexport/auxiliary/reexport-check.rs diff --git a/tests/rustdoc/auxiliary/reexport-doc-aux.rs b/tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexport-doc-aux.rs rename to tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs diff --git a/tests/rustdoc/auxiliary/reexports.rs b/tests/rustdoc/reexport/auxiliary/reexports.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexports.rs rename to tests/rustdoc/reexport/auxiliary/reexports.rs diff --git a/tests/rustdoc/blanket-reexport-item.rs b/tests/rustdoc/reexport/blanket-reexport-item.rs similarity index 100% rename from tests/rustdoc/blanket-reexport-item.rs rename to tests/rustdoc/reexport/blanket-reexport-item.rs diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/reexport/cfg_doc_reexport.rs similarity index 100% rename from tests/rustdoc/cfg_doc_reexport.rs rename to tests/rustdoc/reexport/cfg_doc_reexport.rs diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/reexport/doc-hidden-reexports-109449.rs similarity index 100% rename from tests/rustdoc/doc-hidden-reexports-109449.rs rename to tests/rustdoc/reexport/doc-hidden-reexports-109449.rs diff --git a/tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs b/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs rename to tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs diff --git a/tests/rustdoc/duplicated-glob-reexport-60522.rs b/tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs similarity index 100% rename from tests/rustdoc/duplicated-glob-reexport-60522.rs rename to tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs diff --git a/tests/rustdoc/enum-variant-reexport-35488.rs b/tests/rustdoc/reexport/enum-variant-reexport-35488.rs similarity index 100% rename from tests/rustdoc/enum-variant-reexport-35488.rs rename to tests/rustdoc/reexport/enum-variant-reexport-35488.rs diff --git a/tests/rustdoc/foreigntype-reexport.rs b/tests/rustdoc/reexport/foreigntype-reexport.rs similarity index 100% rename from tests/rustdoc/foreigntype-reexport.rs rename to tests/rustdoc/reexport/foreigntype-reexport.rs diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs similarity index 100% rename from tests/rustdoc/glob-reexport-attribute-merge-120487.rs rename to tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs rename to tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs diff --git a/tests/rustdoc/ice-reexport-crate-root-28927.rs b/tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs similarity index 100% rename from tests/rustdoc/ice-reexport-crate-root-28927.rs rename to tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs diff --git a/tests/rustdoc/local-reexport-doc.rs b/tests/rustdoc/reexport/local-reexport-doc.rs similarity index 100% rename from tests/rustdoc/local-reexport-doc.rs rename to tests/rustdoc/reexport/local-reexport-doc.rs diff --git a/tests/rustdoc/no-compiler-reexport.rs b/tests/rustdoc/reexport/no-compiler-reexport.rs similarity index 100% rename from tests/rustdoc/no-compiler-reexport.rs rename to tests/rustdoc/reexport/no-compiler-reexport.rs diff --git a/tests/rustdoc/overlapping-reexport-105735-2.rs b/tests/rustdoc/reexport/overlapping-reexport-105735-2.rs similarity index 100% rename from tests/rustdoc/overlapping-reexport-105735-2.rs rename to tests/rustdoc/reexport/overlapping-reexport-105735-2.rs diff --git a/tests/rustdoc/overlapping-reexport-105735.rs b/tests/rustdoc/reexport/overlapping-reexport-105735.rs similarity index 100% rename from tests/rustdoc/overlapping-reexport-105735.rs rename to tests/rustdoc/reexport/overlapping-reexport-105735.rs diff --git a/tests/rustdoc/primitive-reexport.rs b/tests/rustdoc/reexport/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/primitive-reexport.rs rename to tests/rustdoc/reexport/primitive-reexport.rs diff --git a/tests/rustdoc/pub-reexport-of-pub-reexport-46506.rs b/tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs similarity index 100% rename from tests/rustdoc/pub-reexport-of-pub-reexport-46506.rs rename to tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs diff --git a/tests/rustdoc/reexport-attr-merge.rs b/tests/rustdoc/reexport/reexport-attr-merge.rs similarity index 100% rename from tests/rustdoc/reexport-attr-merge.rs rename to tests/rustdoc/reexport/reexport-attr-merge.rs diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport/reexport-cfg.rs similarity index 100% rename from tests/rustdoc/reexport-cfg.rs rename to tests/rustdoc/reexport/reexport-cfg.rs diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport-check.rs rename to tests/rustdoc/reexport/reexport-check.rs diff --git a/tests/rustdoc/reexport-dep-foreign-fn.rs b/tests/rustdoc/reexport/reexport-dep-foreign-fn.rs similarity index 100% rename from tests/rustdoc/reexport-dep-foreign-fn.rs rename to tests/rustdoc/reexport/reexport-dep-foreign-fn.rs diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs similarity index 100% rename from tests/rustdoc/reexport-doc-hidden-inside-private.rs rename to tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport/reexport-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport-doc-hidden.rs rename to tests/rustdoc/reexport/reexport-doc-hidden.rs diff --git a/tests/rustdoc/reexport-doc.rs b/tests/rustdoc/reexport/reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport-doc.rs rename to tests/rustdoc/reexport/reexport-doc.rs diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport/reexport-hidden-macro.rs similarity index 100% rename from tests/rustdoc/reexport-hidden-macro.rs rename to tests/rustdoc/reexport/reexport-hidden-macro.rs diff --git a/tests/rustdoc/reexport-macro.rs b/tests/rustdoc/reexport/reexport-macro.rs similarity index 100% rename from tests/rustdoc/reexport-macro.rs rename to tests/rustdoc/reexport/reexport-macro.rs diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport/reexport-of-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport-of-doc-hidden.rs rename to tests/rustdoc/reexport/reexport-of-doc-hidden.rs diff --git a/tests/rustdoc/reexport-of-reexport-108679.rs b/tests/rustdoc/reexport/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/reexport-of-reexport-108679.rs rename to tests/rustdoc/reexport/reexport-of-reexport-108679.rs diff --git a/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs rename to tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs diff --git a/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs rename to tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064-2.rs b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs similarity index 100% rename from tests/rustdoc/reexport-trait-from-hidden-111064-2.rs rename to tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064.rs b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs similarity index 100% rename from tests/rustdoc/reexport-trait-from-hidden-111064.rs rename to tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs diff --git a/tests/rustdoc/reexports-of-same-name.rs b/tests/rustdoc/reexport/reexports-of-same-name.rs similarity index 100% rename from tests/rustdoc/reexports-of-same-name.rs rename to tests/rustdoc/reexport/reexports-of-same-name.rs diff --git a/tests/rustdoc/reexports-priv.rs b/tests/rustdoc/reexport/reexports-priv.rs similarity index 100% rename from tests/rustdoc/reexports-priv.rs rename to tests/rustdoc/reexport/reexports-priv.rs diff --git a/tests/rustdoc/reexports.rs b/tests/rustdoc/reexport/reexports.rs similarity index 100% rename from tests/rustdoc/reexports.rs rename to tests/rustdoc/reexport/reexports.rs From 099f730dcf95404e3f272cb2690a25077b9f2a4b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 15:21:06 +0200 Subject: [PATCH 241/302] Created `tests/rustdoc/source-code-pages` subfolder to limit number of files at the top level --- tests/rustdoc/{ => source-code-pages}/assoc-type-source-link.rs | 0 .../{ => source-code-pages}/auxiliary/issue-26606-macro.rs | 0 tests/rustdoc/{ => source-code-pages}/auxiliary/issue-34274.rs | 0 .../rustdoc/{ => source-code-pages}/auxiliary/source-code-bar.rs | 0 tests/rustdoc/{ => source-code-pages}/auxiliary/source_code.rs | 0 .../{ => source-code-pages}/auxiliary/src-links-external.rs | 0 .../{ => source-code-pages}/check-source-code-urls-to-def-std.rs | 0 .../{ => source-code-pages}/check-source-code-urls-to-def.rs | 0 tests/rustdoc/{ => source-code-pages}/doc-hidden-source.rs | 0 tests/rustdoc/{ => source-code-pages}/html-no-source.rs | 0 tests/rustdoc/{ => source-code-pages}/source-code-highlight.rs | 0 tests/rustdoc/{ => source-code-pages}/source-file.rs | 0 tests/rustdoc/{ => source-code-pages}/source-line-numbers.rs | 0 tests/rustdoc/{ => source-code-pages}/source-version-separator.rs | 0 .../{ => source-code-pages}/src-link-external-macro-26606.rs | 0 tests/rustdoc/{ => source-code-pages}/src-links-auto-impls.rs | 0 tests/rustdoc/{ => source-code-pages}/src-links-external.rs | 0 .../{ => source-code-pages}/src-links-implementor-43893.rs | 0 tests/rustdoc/{ => source-code-pages}/src-links-inlined-34274.rs | 0 tests/rustdoc/{ => source-code-pages}/src-links.rs | 0 .../{ => source-code-pages}/src-links/compiletest-ignore-dir | 0 tests/rustdoc/{ => source-code-pages}/src-links/fizz.rs | 0 tests/rustdoc/{ => source-code-pages}/src-links/mod.rs | 0 .../{ => source-code-pages}/src-mod-path-absolute-26995.rs | 0 .../{ => source-code-pages}/version-separator-without-source.rs | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => source-code-pages}/assoc-type-source-link.rs (100%) rename tests/rustdoc/{ => source-code-pages}/auxiliary/issue-26606-macro.rs (100%) rename tests/rustdoc/{ => source-code-pages}/auxiliary/issue-34274.rs (100%) rename tests/rustdoc/{ => source-code-pages}/auxiliary/source-code-bar.rs (100%) rename tests/rustdoc/{ => source-code-pages}/auxiliary/source_code.rs (100%) rename tests/rustdoc/{ => source-code-pages}/auxiliary/src-links-external.rs (100%) rename tests/rustdoc/{ => source-code-pages}/check-source-code-urls-to-def-std.rs (100%) rename tests/rustdoc/{ => source-code-pages}/check-source-code-urls-to-def.rs (100%) rename tests/rustdoc/{ => source-code-pages}/doc-hidden-source.rs (100%) rename tests/rustdoc/{ => source-code-pages}/html-no-source.rs (100%) rename tests/rustdoc/{ => source-code-pages}/source-code-highlight.rs (100%) rename tests/rustdoc/{ => source-code-pages}/source-file.rs (100%) rename tests/rustdoc/{ => source-code-pages}/source-line-numbers.rs (100%) rename tests/rustdoc/{ => source-code-pages}/source-version-separator.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-link-external-macro-26606.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links-auto-impls.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links-external.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links-implementor-43893.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links-inlined-34274.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links/compiletest-ignore-dir (100%) rename tests/rustdoc/{ => source-code-pages}/src-links/fizz.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-links/mod.rs (100%) rename tests/rustdoc/{ => source-code-pages}/src-mod-path-absolute-26995.rs (100%) rename tests/rustdoc/{ => source-code-pages}/version-separator-without-source.rs (100%) diff --git a/tests/rustdoc/assoc-type-source-link.rs b/tests/rustdoc/source-code-pages/assoc-type-source-link.rs similarity index 100% rename from tests/rustdoc/assoc-type-source-link.rs rename to tests/rustdoc/source-code-pages/assoc-type-source-link.rs diff --git a/tests/rustdoc/auxiliary/issue-26606-macro.rs b/tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-26606-macro.rs rename to tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs diff --git a/tests/rustdoc/auxiliary/issue-34274.rs b/tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-34274.rs rename to tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs diff --git a/tests/rustdoc/auxiliary/source-code-bar.rs b/tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs similarity index 100% rename from tests/rustdoc/auxiliary/source-code-bar.rs rename to tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs diff --git a/tests/rustdoc/auxiliary/source_code.rs b/tests/rustdoc/source-code-pages/auxiliary/source_code.rs similarity index 100% rename from tests/rustdoc/auxiliary/source_code.rs rename to tests/rustdoc/source-code-pages/auxiliary/source_code.rs diff --git a/tests/rustdoc/auxiliary/src-links-external.rs b/tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs similarity index 100% rename from tests/rustdoc/auxiliary/src-links-external.rs rename to tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs diff --git a/tests/rustdoc/check-source-code-urls-to-def-std.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs similarity index 100% rename from tests/rustdoc/check-source-code-urls-to-def-std.rs rename to tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs similarity index 100% rename from tests/rustdoc/check-source-code-urls-to-def.rs rename to tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs diff --git a/tests/rustdoc/doc-hidden-source.rs b/tests/rustdoc/source-code-pages/doc-hidden-source.rs similarity index 100% rename from tests/rustdoc/doc-hidden-source.rs rename to tests/rustdoc/source-code-pages/doc-hidden-source.rs diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/source-code-pages/html-no-source.rs similarity index 100% rename from tests/rustdoc/html-no-source.rs rename to tests/rustdoc/source-code-pages/html-no-source.rs diff --git a/tests/rustdoc/source-code-highlight.rs b/tests/rustdoc/source-code-pages/source-code-highlight.rs similarity index 100% rename from tests/rustdoc/source-code-highlight.rs rename to tests/rustdoc/source-code-pages/source-code-highlight.rs diff --git a/tests/rustdoc/source-file.rs b/tests/rustdoc/source-code-pages/source-file.rs similarity index 100% rename from tests/rustdoc/source-file.rs rename to tests/rustdoc/source-code-pages/source-file.rs diff --git a/tests/rustdoc/source-line-numbers.rs b/tests/rustdoc/source-code-pages/source-line-numbers.rs similarity index 100% rename from tests/rustdoc/source-line-numbers.rs rename to tests/rustdoc/source-code-pages/source-line-numbers.rs diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-code-pages/source-version-separator.rs similarity index 100% rename from tests/rustdoc/source-version-separator.rs rename to tests/rustdoc/source-code-pages/source-version-separator.rs diff --git a/tests/rustdoc/src-link-external-macro-26606.rs b/tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs similarity index 100% rename from tests/rustdoc/src-link-external-macro-26606.rs rename to tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/source-code-pages/src-links-auto-impls.rs similarity index 100% rename from tests/rustdoc/src-links-auto-impls.rs rename to tests/rustdoc/source-code-pages/src-links-auto-impls.rs diff --git a/tests/rustdoc/src-links-external.rs b/tests/rustdoc/source-code-pages/src-links-external.rs similarity index 100% rename from tests/rustdoc/src-links-external.rs rename to tests/rustdoc/source-code-pages/src-links-external.rs diff --git a/tests/rustdoc/src-links-implementor-43893.rs b/tests/rustdoc/source-code-pages/src-links-implementor-43893.rs similarity index 100% rename from tests/rustdoc/src-links-implementor-43893.rs rename to tests/rustdoc/source-code-pages/src-links-implementor-43893.rs diff --git a/tests/rustdoc/src-links-inlined-34274.rs b/tests/rustdoc/source-code-pages/src-links-inlined-34274.rs similarity index 100% rename from tests/rustdoc/src-links-inlined-34274.rs rename to tests/rustdoc/source-code-pages/src-links-inlined-34274.rs diff --git a/tests/rustdoc/src-links.rs b/tests/rustdoc/source-code-pages/src-links.rs similarity index 100% rename from tests/rustdoc/src-links.rs rename to tests/rustdoc/source-code-pages/src-links.rs diff --git a/tests/rustdoc/src-links/compiletest-ignore-dir b/tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir similarity index 100% rename from tests/rustdoc/src-links/compiletest-ignore-dir rename to tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir diff --git a/tests/rustdoc/src-links/fizz.rs b/tests/rustdoc/source-code-pages/src-links/fizz.rs similarity index 100% rename from tests/rustdoc/src-links/fizz.rs rename to tests/rustdoc/source-code-pages/src-links/fizz.rs diff --git a/tests/rustdoc/src-links/mod.rs b/tests/rustdoc/source-code-pages/src-links/mod.rs similarity index 100% rename from tests/rustdoc/src-links/mod.rs rename to tests/rustdoc/source-code-pages/src-links/mod.rs diff --git a/tests/rustdoc/src-mod-path-absolute-26995.rs b/tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs similarity index 100% rename from tests/rustdoc/src-mod-path-absolute-26995.rs rename to tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/source-code-pages/version-separator-without-source.rs similarity index 100% rename from tests/rustdoc/version-separator-without-source.rs rename to tests/rustdoc/source-code-pages/version-separator-without-source.rs From b374996ab8d3d8a10fdf1ffcf2b1c3de3fdbbf64 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 15:50:06 +0200 Subject: [PATCH 242/302] Created `tests/rustdoc/anchors` subfolder to limit number of files at the top level --- .../{ => anchors}/anchor-id-duplicate-method-name-25001.rs | 0 tests/rustdoc/{ => anchors}/anchor-id-trait-method-15169.rs | 0 tests/rustdoc/{ => anchors}/anchor-id-trait-tymethod-28478.rs | 0 tests/rustdoc/{ => anchors}/anchors.no_const_anchor.html | 0 tests/rustdoc/{ => anchors}/anchors.no_const_anchor2.html | 0 tests/rustdoc/{ => anchors}/anchors.no_method_anchor.html | 0 tests/rustdoc/{ => anchors}/anchors.no_trait_method_anchor.html | 0 tests/rustdoc/{ => anchors}/anchors.no_tymethod_anchor.html | 0 tests/rustdoc/{ => anchors}/anchors.no_type_anchor.html | 0 tests/rustdoc/{ => anchors}/anchors.no_type_anchor2.html | 0 tests/rustdoc/{ => anchors}/anchors.rs | 0 tests/rustdoc/{ => anchors}/auxiliary/issue-86620-1.rs | 0 tests/rustdoc/{ => anchors}/disambiguate-anchors-32890.rs | 0 tests/rustdoc/{ => anchors}/disambiguate-anchors-header-29449.rs | 0 .../{ => anchors}/extern-default-method.no_href_on_anchor.html | 0 .../rustdoc/{ => anchors}/method-anchor-in-blanket-impl-86620.rs | 0 tests/rustdoc/{ => anchors}/trait-impl-items-links-and-anchors.rs | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => anchors}/anchor-id-duplicate-method-name-25001.rs (100%) rename tests/rustdoc/{ => anchors}/anchor-id-trait-method-15169.rs (100%) rename tests/rustdoc/{ => anchors}/anchor-id-trait-tymethod-28478.rs (100%) rename tests/rustdoc/{ => anchors}/anchors.no_const_anchor.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_const_anchor2.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_method_anchor.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_trait_method_anchor.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_tymethod_anchor.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_type_anchor.html (100%) rename tests/rustdoc/{ => anchors}/anchors.no_type_anchor2.html (100%) rename tests/rustdoc/{ => anchors}/anchors.rs (100%) rename tests/rustdoc/{ => anchors}/auxiliary/issue-86620-1.rs (100%) rename tests/rustdoc/{ => anchors}/disambiguate-anchors-32890.rs (100%) rename tests/rustdoc/{ => anchors}/disambiguate-anchors-header-29449.rs (100%) rename tests/rustdoc/{ => anchors}/extern-default-method.no_href_on_anchor.html (100%) rename tests/rustdoc/{ => anchors}/method-anchor-in-blanket-impl-86620.rs (100%) rename tests/rustdoc/{ => anchors}/trait-impl-items-links-and-anchors.rs (100%) diff --git a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs similarity index 100% rename from tests/rustdoc/anchor-id-duplicate-method-name-25001.rs rename to tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs diff --git a/tests/rustdoc/anchor-id-trait-method-15169.rs b/tests/rustdoc/anchors/anchor-id-trait-method-15169.rs similarity index 100% rename from tests/rustdoc/anchor-id-trait-method-15169.rs rename to tests/rustdoc/anchors/anchor-id-trait-method-15169.rs diff --git a/tests/rustdoc/anchor-id-trait-tymethod-28478.rs b/tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs similarity index 100% rename from tests/rustdoc/anchor-id-trait-tymethod-28478.rs rename to tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors/anchors.no_const_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_const_anchor.html rename to tests/rustdoc/anchors/anchors.no_const_anchor.html diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors/anchors.no_const_anchor2.html similarity index 100% rename from tests/rustdoc/anchors.no_const_anchor2.html rename to tests/rustdoc/anchors/anchors.no_const_anchor2.html diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors/anchors.no_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_method_anchor.html rename to tests/rustdoc/anchors/anchors.no_method_anchor.html diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors/anchors.no_trait_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_trait_method_anchor.html rename to tests/rustdoc/anchors/anchors.no_trait_method_anchor.html diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors/anchors.no_tymethod_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_tymethod_anchor.html rename to tests/rustdoc/anchors/anchors.no_tymethod_anchor.html diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors/anchors.no_type_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_type_anchor.html rename to tests/rustdoc/anchors/anchors.no_type_anchor.html diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors/anchors.no_type_anchor2.html similarity index 100% rename from tests/rustdoc/anchors.no_type_anchor2.html rename to tests/rustdoc/anchors/anchors.no_type_anchor2.html diff --git a/tests/rustdoc/anchors.rs b/tests/rustdoc/anchors/anchors.rs similarity index 100% rename from tests/rustdoc/anchors.rs rename to tests/rustdoc/anchors/anchors.rs diff --git a/tests/rustdoc/auxiliary/issue-86620-1.rs b/tests/rustdoc/anchors/auxiliary/issue-86620-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-86620-1.rs rename to tests/rustdoc/anchors/auxiliary/issue-86620-1.rs diff --git a/tests/rustdoc/disambiguate-anchors-32890.rs b/tests/rustdoc/anchors/disambiguate-anchors-32890.rs similarity index 100% rename from tests/rustdoc/disambiguate-anchors-32890.rs rename to tests/rustdoc/anchors/disambiguate-anchors-32890.rs diff --git a/tests/rustdoc/disambiguate-anchors-header-29449.rs b/tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs similarity index 100% rename from tests/rustdoc/disambiguate-anchors-header-29449.rs rename to tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs diff --git a/tests/rustdoc/extern-default-method.no_href_on_anchor.html b/tests/rustdoc/anchors/extern-default-method.no_href_on_anchor.html similarity index 100% rename from tests/rustdoc/extern-default-method.no_href_on_anchor.html rename to tests/rustdoc/anchors/extern-default-method.no_href_on_anchor.html diff --git a/tests/rustdoc/method-anchor-in-blanket-impl-86620.rs b/tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs similarity index 100% rename from tests/rustdoc/method-anchor-in-blanket-impl-86620.rs rename to tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs diff --git a/tests/rustdoc/trait-impl-items-links-and-anchors.rs b/tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs similarity index 100% rename from tests/rustdoc/trait-impl-items-links-and-anchors.rs rename to tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs From ff971d001d3440fa609f8c5370432c6b77a5ac6e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:28:15 +0200 Subject: [PATCH 243/302] Created `tests/rustdoc/auto` subfolder to limit number of files at the top level --- tests/rustdoc/{ => auto}/auto-impl-for-trait.rs | 0 tests/rustdoc/{ => auto}/auto-impl-primitive.rs | 0 .../{ => auto}/auto-trait-bounds-by-associated-type-50159.rs | 0 .../{ => auto}/auto-trait-bounds-inference-variables-54705.rs | 0 tests/rustdoc/{ => auto}/auto-trait-bounds-where-51236.rs | 0 tests/rustdoc/{ => auto}/auto-trait-negative-impl-55321.rs | 0 tests/rustdoc/{ => auto}/auto-trait-not-send.rs | 0 tests/rustdoc/{ => auto}/auto-traits.rs | 0 tests/rustdoc/{ => auto}/auto_aliases.rs | 0 tests/rustdoc/{ => auto}/auxiliary/auto-traits.rs | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => auto}/auto-impl-for-trait.rs (100%) rename tests/rustdoc/{ => auto}/auto-impl-primitive.rs (100%) rename tests/rustdoc/{ => auto}/auto-trait-bounds-by-associated-type-50159.rs (100%) rename tests/rustdoc/{ => auto}/auto-trait-bounds-inference-variables-54705.rs (100%) rename tests/rustdoc/{ => auto}/auto-trait-bounds-where-51236.rs (100%) rename tests/rustdoc/{ => auto}/auto-trait-negative-impl-55321.rs (100%) rename tests/rustdoc/{ => auto}/auto-trait-not-send.rs (100%) rename tests/rustdoc/{ => auto}/auto-traits.rs (100%) rename tests/rustdoc/{ => auto}/auto_aliases.rs (100%) rename tests/rustdoc/{ => auto}/auxiliary/auto-traits.rs (100%) diff --git a/tests/rustdoc/auto-impl-for-trait.rs b/tests/rustdoc/auto/auto-impl-for-trait.rs similarity index 100% rename from tests/rustdoc/auto-impl-for-trait.rs rename to tests/rustdoc/auto/auto-impl-for-trait.rs diff --git a/tests/rustdoc/auto-impl-primitive.rs b/tests/rustdoc/auto/auto-impl-primitive.rs similarity index 100% rename from tests/rustdoc/auto-impl-primitive.rs rename to tests/rustdoc/auto/auto-impl-primitive.rs diff --git a/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs b/tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs rename to tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs diff --git a/tests/rustdoc/auto-trait-bounds-inference-variables-54705.rs b/tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-inference-variables-54705.rs rename to tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs diff --git a/tests/rustdoc/auto-trait-bounds-where-51236.rs b/tests/rustdoc/auto/auto-trait-bounds-where-51236.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-where-51236.rs rename to tests/rustdoc/auto/auto-trait-bounds-where-51236.rs diff --git a/tests/rustdoc/auto-trait-negative-impl-55321.rs b/tests/rustdoc/auto/auto-trait-negative-impl-55321.rs similarity index 100% rename from tests/rustdoc/auto-trait-negative-impl-55321.rs rename to tests/rustdoc/auto/auto-trait-negative-impl-55321.rs diff --git a/tests/rustdoc/auto-trait-not-send.rs b/tests/rustdoc/auto/auto-trait-not-send.rs similarity index 100% rename from tests/rustdoc/auto-trait-not-send.rs rename to tests/rustdoc/auto/auto-trait-not-send.rs diff --git a/tests/rustdoc/auto-traits.rs b/tests/rustdoc/auto/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto-traits.rs rename to tests/rustdoc/auto/auto-traits.rs diff --git a/tests/rustdoc/auto_aliases.rs b/tests/rustdoc/auto/auto_aliases.rs similarity index 100% rename from tests/rustdoc/auto_aliases.rs rename to tests/rustdoc/auto/auto_aliases.rs diff --git a/tests/rustdoc/auxiliary/auto-traits.rs b/tests/rustdoc/auto/auxiliary/auto-traits.rs similarity index 100% rename from tests/rustdoc/auxiliary/auto-traits.rs rename to tests/rustdoc/auto/auxiliary/auto-traits.rs From 9db7de5915314a3924548f2b1645d09ba2644dad Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:31:58 +0200 Subject: [PATCH 244/302] Created `tests/rustdoc/jump-to-def` subfolder to limit number of files at the top level --- tests/rustdoc/{ => jump-to-def}/auxiliary/jump-to-def-macro.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-def-doc-links-calls.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-def-doc-links.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-def-macro.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-def-pats.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-def-prelude-types.rs | 0 tests/rustdoc/{ => jump-to-def}/jump-to-non-local-method.rs | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => jump-to-def}/auxiliary/jump-to-def-macro.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-def-doc-links-calls.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-def-doc-links.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-def-macro.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-def-pats.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-def-prelude-types.rs (100%) rename tests/rustdoc/{ => jump-to-def}/jump-to-non-local-method.rs (100%) diff --git a/tests/rustdoc/auxiliary/jump-to-def-macro.rs b/tests/rustdoc/jump-to-def/auxiliary/jump-to-def-macro.rs similarity index 100% rename from tests/rustdoc/auxiliary/jump-to-def-macro.rs rename to tests/rustdoc/jump-to-def/auxiliary/jump-to-def-macro.rs diff --git a/tests/rustdoc/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs similarity index 100% rename from tests/rustdoc/jump-to-def-doc-links-calls.rs rename to tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs diff --git a/tests/rustdoc/jump-to-def-doc-links.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links.rs similarity index 100% rename from tests/rustdoc/jump-to-def-doc-links.rs rename to tests/rustdoc/jump-to-def/jump-to-def-doc-links.rs diff --git a/tests/rustdoc/jump-to-def-macro.rs b/tests/rustdoc/jump-to-def/jump-to-def-macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def-macro.rs rename to tests/rustdoc/jump-to-def/jump-to-def-macro.rs diff --git a/tests/rustdoc/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs similarity index 100% rename from tests/rustdoc/jump-to-def-pats.rs rename to tests/rustdoc/jump-to-def/jump-to-def-pats.rs diff --git a/tests/rustdoc/jump-to-def-prelude-types.rs b/tests/rustdoc/jump-to-def/jump-to-def-prelude-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def-prelude-types.rs rename to tests/rustdoc/jump-to-def/jump-to-def-prelude-types.rs diff --git a/tests/rustdoc/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs similarity index 100% rename from tests/rustdoc/jump-to-non-local-method.rs rename to tests/rustdoc/jump-to-def/jump-to-non-local-method.rs From a00b39961a9b45c788b86ef9f874d886f5403280 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:32:47 +0200 Subject: [PATCH 245/302] Move intra-doc tests into the expected subfolder --- tests/rustdoc/{ => intra-doc}/ice-intra-doc-links-107995.rs | 0 .../{ => intra-doc}/intra-doc-link-method-trait-impl-72340.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => intra-doc}/ice-intra-doc-links-107995.rs (100%) rename tests/rustdoc/{ => intra-doc}/intra-doc-link-method-trait-impl-72340.rs (100%) diff --git a/tests/rustdoc/ice-intra-doc-links-107995.rs b/tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/ice-intra-doc-links-107995.rs rename to tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/intra-doc-link-method-trait-impl-72340.rs b/tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs similarity index 100% rename from tests/rustdoc/intra-doc-link-method-trait-impl-72340.rs rename to tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs From eee6c9753588fe1888d3ddb264f9516e7ac56997 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:34:16 +0200 Subject: [PATCH 246/302] Created `tests/rustdoc/private` subfolder to limit number of files at the top level --- tests/rustdoc/{ => private}/doc-hidden-private-67851-both.rs | 0 tests/rustdoc/{ => private}/doc-hidden-private-67851-hidden.rs | 0 tests/rustdoc/{ => private}/doc-hidden-private-67851-neither.rs | 0 tests/rustdoc/{ => private}/doc-hidden-private-67851-private.rs | 0 tests/rustdoc/{ => private}/empty-impl-block-private-with-doc.rs | 0 tests/rustdoc/{ => private}/empty-impl-block-private.rs | 0 tests/rustdoc/{ => private}/empty-mod-private.rs | 0 tests/rustdoc/{ => private}/enum-variant-private-46767.rs | 0 tests/rustdoc/{ => private}/files-creation-private.rs | 0 tests/rustdoc/{ => private}/hidden-private.rs | 0 .../{ => private}/inline-private-with-intermediate-doc-hidden.rs | 0 tests/rustdoc/{ => private}/inner-private-110422.rs | 0 tests/rustdoc/{ => private}/macro-document-private-duplicate.rs | 0 tests/rustdoc/{ => private}/macro-document-private.rs | 0 tests/rustdoc/{ => private}/macro-private-not-documented.rs | 0 tests/rustdoc/{ => private}/missing-private-inlining-109258.rs | 0 tests/rustdoc/{ => private}/private-fields-tuple-struct.rs | 0 tests/rustdoc/{ => private}/private-non-local-fields-2.rs | 0 tests/rustdoc/{ => private}/private-non-local-fields.rs | 0 tests/rustdoc/{ => private}/private-type-alias.rs | 0 tests/rustdoc/{ => private}/private-type-cycle-110629.rs | 0 tests/rustdoc/{ => private}/private-use-decl-macro-47038.rs | 0 tests/rustdoc/{ => private}/private-use.rs | 0 .../{ => private}/public-impl-mention-private-generic-46380-2.rs | 0 tests/rustdoc/{ => private}/traits-in-bodies-private.rs | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => private}/doc-hidden-private-67851-both.rs (100%) rename tests/rustdoc/{ => private}/doc-hidden-private-67851-hidden.rs (100%) rename tests/rustdoc/{ => private}/doc-hidden-private-67851-neither.rs (100%) rename tests/rustdoc/{ => private}/doc-hidden-private-67851-private.rs (100%) rename tests/rustdoc/{ => private}/empty-impl-block-private-with-doc.rs (100%) rename tests/rustdoc/{ => private}/empty-impl-block-private.rs (100%) rename tests/rustdoc/{ => private}/empty-mod-private.rs (100%) rename tests/rustdoc/{ => private}/enum-variant-private-46767.rs (100%) rename tests/rustdoc/{ => private}/files-creation-private.rs (100%) rename tests/rustdoc/{ => private}/hidden-private.rs (100%) rename tests/rustdoc/{ => private}/inline-private-with-intermediate-doc-hidden.rs (100%) rename tests/rustdoc/{ => private}/inner-private-110422.rs (100%) rename tests/rustdoc/{ => private}/macro-document-private-duplicate.rs (100%) rename tests/rustdoc/{ => private}/macro-document-private.rs (100%) rename tests/rustdoc/{ => private}/macro-private-not-documented.rs (100%) rename tests/rustdoc/{ => private}/missing-private-inlining-109258.rs (100%) rename tests/rustdoc/{ => private}/private-fields-tuple-struct.rs (100%) rename tests/rustdoc/{ => private}/private-non-local-fields-2.rs (100%) rename tests/rustdoc/{ => private}/private-non-local-fields.rs (100%) rename tests/rustdoc/{ => private}/private-type-alias.rs (100%) rename tests/rustdoc/{ => private}/private-type-cycle-110629.rs (100%) rename tests/rustdoc/{ => private}/private-use-decl-macro-47038.rs (100%) rename tests/rustdoc/{ => private}/private-use.rs (100%) rename tests/rustdoc/{ => private}/public-impl-mention-private-generic-46380-2.rs (100%) rename tests/rustdoc/{ => private}/traits-in-bodies-private.rs (100%) diff --git a/tests/rustdoc/doc-hidden-private-67851-both.rs b/tests/rustdoc/private/doc-hidden-private-67851-both.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-both.rs rename to tests/rustdoc/private/doc-hidden-private-67851-both.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-hidden.rs b/tests/rustdoc/private/doc-hidden-private-67851-hidden.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-hidden.rs rename to tests/rustdoc/private/doc-hidden-private-67851-hidden.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-neither.rs b/tests/rustdoc/private/doc-hidden-private-67851-neither.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-neither.rs rename to tests/rustdoc/private/doc-hidden-private-67851-neither.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-private.rs b/tests/rustdoc/private/doc-hidden-private-67851-private.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-private.rs rename to tests/rustdoc/private/doc-hidden-private-67851-private.rs diff --git a/tests/rustdoc/empty-impl-block-private-with-doc.rs b/tests/rustdoc/private/empty-impl-block-private-with-doc.rs similarity index 100% rename from tests/rustdoc/empty-impl-block-private-with-doc.rs rename to tests/rustdoc/private/empty-impl-block-private-with-doc.rs diff --git a/tests/rustdoc/empty-impl-block-private.rs b/tests/rustdoc/private/empty-impl-block-private.rs similarity index 100% rename from tests/rustdoc/empty-impl-block-private.rs rename to tests/rustdoc/private/empty-impl-block-private.rs diff --git a/tests/rustdoc/empty-mod-private.rs b/tests/rustdoc/private/empty-mod-private.rs similarity index 100% rename from tests/rustdoc/empty-mod-private.rs rename to tests/rustdoc/private/empty-mod-private.rs diff --git a/tests/rustdoc/enum-variant-private-46767.rs b/tests/rustdoc/private/enum-variant-private-46767.rs similarity index 100% rename from tests/rustdoc/enum-variant-private-46767.rs rename to tests/rustdoc/private/enum-variant-private-46767.rs diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/private/files-creation-private.rs similarity index 100% rename from tests/rustdoc/files-creation-private.rs rename to tests/rustdoc/private/files-creation-private.rs diff --git a/tests/rustdoc/hidden-private.rs b/tests/rustdoc/private/hidden-private.rs similarity index 100% rename from tests/rustdoc/hidden-private.rs rename to tests/rustdoc/private/hidden-private.rs diff --git a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs similarity index 100% rename from tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs rename to tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs diff --git a/tests/rustdoc/inner-private-110422.rs b/tests/rustdoc/private/inner-private-110422.rs similarity index 100% rename from tests/rustdoc/inner-private-110422.rs rename to tests/rustdoc/private/inner-private-110422.rs diff --git a/tests/rustdoc/macro-document-private-duplicate.rs b/tests/rustdoc/private/macro-document-private-duplicate.rs similarity index 100% rename from tests/rustdoc/macro-document-private-duplicate.rs rename to tests/rustdoc/private/macro-document-private-duplicate.rs diff --git a/tests/rustdoc/macro-document-private.rs b/tests/rustdoc/private/macro-document-private.rs similarity index 100% rename from tests/rustdoc/macro-document-private.rs rename to tests/rustdoc/private/macro-document-private.rs diff --git a/tests/rustdoc/macro-private-not-documented.rs b/tests/rustdoc/private/macro-private-not-documented.rs similarity index 100% rename from tests/rustdoc/macro-private-not-documented.rs rename to tests/rustdoc/private/macro-private-not-documented.rs diff --git a/tests/rustdoc/missing-private-inlining-109258.rs b/tests/rustdoc/private/missing-private-inlining-109258.rs similarity index 100% rename from tests/rustdoc/missing-private-inlining-109258.rs rename to tests/rustdoc/private/missing-private-inlining-109258.rs diff --git a/tests/rustdoc/private-fields-tuple-struct.rs b/tests/rustdoc/private/private-fields-tuple-struct.rs similarity index 100% rename from tests/rustdoc/private-fields-tuple-struct.rs rename to tests/rustdoc/private/private-fields-tuple-struct.rs diff --git a/tests/rustdoc/private-non-local-fields-2.rs b/tests/rustdoc/private/private-non-local-fields-2.rs similarity index 100% rename from tests/rustdoc/private-non-local-fields-2.rs rename to tests/rustdoc/private/private-non-local-fields-2.rs diff --git a/tests/rustdoc/private-non-local-fields.rs b/tests/rustdoc/private/private-non-local-fields.rs similarity index 100% rename from tests/rustdoc/private-non-local-fields.rs rename to tests/rustdoc/private/private-non-local-fields.rs diff --git a/tests/rustdoc/private-type-alias.rs b/tests/rustdoc/private/private-type-alias.rs similarity index 100% rename from tests/rustdoc/private-type-alias.rs rename to tests/rustdoc/private/private-type-alias.rs diff --git a/tests/rustdoc/private-type-cycle-110629.rs b/tests/rustdoc/private/private-type-cycle-110629.rs similarity index 100% rename from tests/rustdoc/private-type-cycle-110629.rs rename to tests/rustdoc/private/private-type-cycle-110629.rs diff --git a/tests/rustdoc/private-use-decl-macro-47038.rs b/tests/rustdoc/private/private-use-decl-macro-47038.rs similarity index 100% rename from tests/rustdoc/private-use-decl-macro-47038.rs rename to tests/rustdoc/private/private-use-decl-macro-47038.rs diff --git a/tests/rustdoc/private-use.rs b/tests/rustdoc/private/private-use.rs similarity index 100% rename from tests/rustdoc/private-use.rs rename to tests/rustdoc/private/private-use.rs diff --git a/tests/rustdoc/public-impl-mention-private-generic-46380-2.rs b/tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs similarity index 100% rename from tests/rustdoc/public-impl-mention-private-generic-46380-2.rs rename to tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs diff --git a/tests/rustdoc/traits-in-bodies-private.rs b/tests/rustdoc/private/traits-in-bodies-private.rs similarity index 100% rename from tests/rustdoc/traits-in-bodies-private.rs rename to tests/rustdoc/private/traits-in-bodies-private.rs From d1f4a0bcb60ab868c496ca72a28b48ac0a4128af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:40:02 +0200 Subject: [PATCH 247/302] Created `tests/rustdoc/macro` subfolder to limit number of files at the top level --- .../auxiliary/external-macro-src.rs | 0 .../macro/auxiliary/issue-99221-aux.rs | 20 +++++++++++++++++++ .../auxiliary/macro_pub_in_module.rs | 0 .../auxiliary/pub-use-extern-macros.rs | 0 .../{ => macro}/compiler-derive-proc-macro.rs | 0 .../const-rendering-macros-33302.rs | 0 tests/rustdoc/{ => macro}/decl_macro.rs | 0 tests/rustdoc/{ => macro}/decl_macro_priv.rs | 0 tests/rustdoc/{ => macro}/doc-proc-macro.rs | 0 .../rustdoc/{ => macro}/external-macro-src.rs | 0 .../{ => macro}/macro-const-display-115295.rs | 0 .../{ => macro}/macro-doc-comment-23812.rs | 0 .../macro-export-crate-root-108231.rs | 0 ...o-generated-macro.macro_linebreak_pre.html | 0 ...o-generated-macro.macro_morestuff_pre.html | 0 .../{ => macro}/macro-generated-macro.rs | 0 .../macro-higher-kinded-function.rs | 0 tests/rustdoc/{ => macro}/macro-ice-16019.rs | 0 .../{ => macro}/macro-in-async-block.rs | 0 tests/rustdoc/{ => macro}/macro-in-closure.rs | 0 .../rustdoc/{ => macro}/macro-indirect-use.rs | 0 .../{ => macro}/macro_pub_in_module.rs | 0 .../{ => macro}/macro_rules-matchers.rs | 0 tests/rustdoc/{ => macro}/macros.rs | 0 .../multiple-macro-rules-w-same-name-99221.rs | 0 ...macro-rules-w-same-name-submodule-99221.rs | 0 tests/rustdoc/{ => macro}/proc-macro.rs | 0 .../{ => macro}/pub-use-extern-macros.rs | 0 .../rustdoc/{ => macro}/rustc-macro-crate.rs | 0 29 files changed, 20 insertions(+) rename tests/rustdoc/{ => macro}/auxiliary/external-macro-src.rs (100%) create mode 100644 tests/rustdoc/macro/auxiliary/issue-99221-aux.rs rename tests/rustdoc/{ => macro}/auxiliary/macro_pub_in_module.rs (100%) rename tests/rustdoc/{ => macro}/auxiliary/pub-use-extern-macros.rs (100%) rename tests/rustdoc/{ => macro}/compiler-derive-proc-macro.rs (100%) rename tests/rustdoc/{ => macro}/const-rendering-macros-33302.rs (100%) rename tests/rustdoc/{ => macro}/decl_macro.rs (100%) rename tests/rustdoc/{ => macro}/decl_macro_priv.rs (100%) rename tests/rustdoc/{ => macro}/doc-proc-macro.rs (100%) rename tests/rustdoc/{ => macro}/external-macro-src.rs (100%) rename tests/rustdoc/{ => macro}/macro-const-display-115295.rs (100%) rename tests/rustdoc/{ => macro}/macro-doc-comment-23812.rs (100%) rename tests/rustdoc/{ => macro}/macro-export-crate-root-108231.rs (100%) rename tests/rustdoc/{ => macro}/macro-generated-macro.macro_linebreak_pre.html (100%) rename tests/rustdoc/{ => macro}/macro-generated-macro.macro_morestuff_pre.html (100%) rename tests/rustdoc/{ => macro}/macro-generated-macro.rs (100%) rename tests/rustdoc/{ => macro}/macro-higher-kinded-function.rs (100%) rename tests/rustdoc/{ => macro}/macro-ice-16019.rs (100%) rename tests/rustdoc/{ => macro}/macro-in-async-block.rs (100%) rename tests/rustdoc/{ => macro}/macro-in-closure.rs (100%) rename tests/rustdoc/{ => macro}/macro-indirect-use.rs (100%) rename tests/rustdoc/{ => macro}/macro_pub_in_module.rs (100%) rename tests/rustdoc/{ => macro}/macro_rules-matchers.rs (100%) rename tests/rustdoc/{ => macro}/macros.rs (100%) rename tests/rustdoc/{ => macro}/multiple-macro-rules-w-same-name-99221.rs (100%) rename tests/rustdoc/{ => macro}/multiple-macro-rules-w-same-name-submodule-99221.rs (100%) rename tests/rustdoc/{ => macro}/proc-macro.rs (100%) rename tests/rustdoc/{ => macro}/pub-use-extern-macros.rs (100%) rename tests/rustdoc/{ => macro}/rustc-macro-crate.rs (100%) diff --git a/tests/rustdoc/auxiliary/external-macro-src.rs b/tests/rustdoc/macro/auxiliary/external-macro-src.rs similarity index 100% rename from tests/rustdoc/auxiliary/external-macro-src.rs rename to tests/rustdoc/macro/auxiliary/external-macro-src.rs diff --git a/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs b/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs new file mode 100644 index 000000000000..e061e42b29db --- /dev/null +++ b/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs @@ -0,0 +1,20 @@ +pub struct Option; +impl Option { + pub fn unwrap(self) {} +} + +mod macros { + use crate::Option; + /// [`Option::unwrap`] + #[macro_export] + macro_rules! print { + () => () + } +} + +mod structs { + use crate::Option; + /// [`Option::unwrap`] + pub struct Print; +} +pub use structs::Print; diff --git a/tests/rustdoc/auxiliary/macro_pub_in_module.rs b/tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/auxiliary/macro_pub_in_module.rs rename to tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs diff --git a/tests/rustdoc/auxiliary/pub-use-extern-macros.rs b/tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/auxiliary/pub-use-extern-macros.rs rename to tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs diff --git a/tests/rustdoc/compiler-derive-proc-macro.rs b/tests/rustdoc/macro/compiler-derive-proc-macro.rs similarity index 100% rename from tests/rustdoc/compiler-derive-proc-macro.rs rename to tests/rustdoc/macro/compiler-derive-proc-macro.rs diff --git a/tests/rustdoc/const-rendering-macros-33302.rs b/tests/rustdoc/macro/const-rendering-macros-33302.rs similarity index 100% rename from tests/rustdoc/const-rendering-macros-33302.rs rename to tests/rustdoc/macro/const-rendering-macros-33302.rs diff --git a/tests/rustdoc/decl_macro.rs b/tests/rustdoc/macro/decl_macro.rs similarity index 100% rename from tests/rustdoc/decl_macro.rs rename to tests/rustdoc/macro/decl_macro.rs diff --git a/tests/rustdoc/decl_macro_priv.rs b/tests/rustdoc/macro/decl_macro_priv.rs similarity index 100% rename from tests/rustdoc/decl_macro_priv.rs rename to tests/rustdoc/macro/decl_macro_priv.rs diff --git a/tests/rustdoc/doc-proc-macro.rs b/tests/rustdoc/macro/doc-proc-macro.rs similarity index 100% rename from tests/rustdoc/doc-proc-macro.rs rename to tests/rustdoc/macro/doc-proc-macro.rs diff --git a/tests/rustdoc/external-macro-src.rs b/tests/rustdoc/macro/external-macro-src.rs similarity index 100% rename from tests/rustdoc/external-macro-src.rs rename to tests/rustdoc/macro/external-macro-src.rs diff --git a/tests/rustdoc/macro-const-display-115295.rs b/tests/rustdoc/macro/macro-const-display-115295.rs similarity index 100% rename from tests/rustdoc/macro-const-display-115295.rs rename to tests/rustdoc/macro/macro-const-display-115295.rs diff --git a/tests/rustdoc/macro-doc-comment-23812.rs b/tests/rustdoc/macro/macro-doc-comment-23812.rs similarity index 100% rename from tests/rustdoc/macro-doc-comment-23812.rs rename to tests/rustdoc/macro/macro-doc-comment-23812.rs diff --git a/tests/rustdoc/macro-export-crate-root-108231.rs b/tests/rustdoc/macro/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/macro-export-crate-root-108231.rs rename to tests/rustdoc/macro/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html similarity index 100% rename from tests/rustdoc/macro-generated-macro.macro_linebreak_pre.html rename to tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html diff --git a/tests/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html similarity index 100% rename from tests/rustdoc/macro-generated-macro.macro_morestuff_pre.html rename to tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html diff --git a/tests/rustdoc/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs similarity index 100% rename from tests/rustdoc/macro-generated-macro.rs rename to tests/rustdoc/macro/macro-generated-macro.rs diff --git a/tests/rustdoc/macro-higher-kinded-function.rs b/tests/rustdoc/macro/macro-higher-kinded-function.rs similarity index 100% rename from tests/rustdoc/macro-higher-kinded-function.rs rename to tests/rustdoc/macro/macro-higher-kinded-function.rs diff --git a/tests/rustdoc/macro-ice-16019.rs b/tests/rustdoc/macro/macro-ice-16019.rs similarity index 100% rename from tests/rustdoc/macro-ice-16019.rs rename to tests/rustdoc/macro/macro-ice-16019.rs diff --git a/tests/rustdoc/macro-in-async-block.rs b/tests/rustdoc/macro/macro-in-async-block.rs similarity index 100% rename from tests/rustdoc/macro-in-async-block.rs rename to tests/rustdoc/macro/macro-in-async-block.rs diff --git a/tests/rustdoc/macro-in-closure.rs b/tests/rustdoc/macro/macro-in-closure.rs similarity index 100% rename from tests/rustdoc/macro-in-closure.rs rename to tests/rustdoc/macro/macro-in-closure.rs diff --git a/tests/rustdoc/macro-indirect-use.rs b/tests/rustdoc/macro/macro-indirect-use.rs similarity index 100% rename from tests/rustdoc/macro-indirect-use.rs rename to tests/rustdoc/macro/macro-indirect-use.rs diff --git a/tests/rustdoc/macro_pub_in_module.rs b/tests/rustdoc/macro/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro_pub_in_module.rs rename to tests/rustdoc/macro/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro_rules-matchers.rs b/tests/rustdoc/macro/macro_rules-matchers.rs similarity index 100% rename from tests/rustdoc/macro_rules-matchers.rs rename to tests/rustdoc/macro/macro_rules-matchers.rs diff --git a/tests/rustdoc/macros.rs b/tests/rustdoc/macro/macros.rs similarity index 100% rename from tests/rustdoc/macros.rs rename to tests/rustdoc/macro/macros.rs diff --git a/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs b/tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs rename to tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs diff --git a/tests/rustdoc/multiple-macro-rules-w-same-name-submodule-99221.rs b/tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs similarity index 100% rename from tests/rustdoc/multiple-macro-rules-w-same-name-submodule-99221.rs rename to tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs diff --git a/tests/rustdoc/proc-macro.rs b/tests/rustdoc/macro/proc-macro.rs similarity index 100% rename from tests/rustdoc/proc-macro.rs rename to tests/rustdoc/macro/proc-macro.rs diff --git a/tests/rustdoc/pub-use-extern-macros.rs b/tests/rustdoc/macro/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/pub-use-extern-macros.rs rename to tests/rustdoc/macro/pub-use-extern-macros.rs diff --git a/tests/rustdoc/rustc-macro-crate.rs b/tests/rustdoc/macro/rustc-macro-crate.rs similarity index 100% rename from tests/rustdoc/rustc-macro-crate.rs rename to tests/rustdoc/macro/rustc-macro-crate.rs From be71d8b24f1aebe9c45279d95a76db8fa6a62574 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 16:42:18 +0200 Subject: [PATCH 248/302] Created `tests/rustdoc/doc-cfg` subfolder to limit number of files at the top level --- tests/rustdoc/{ => doc-cfg}/doc-cfg-hide.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-implicit-gate.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-implicit.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-inherit-from-module-79201.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-simplification.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-target-feature.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg-traits.rs | 0 tests/rustdoc/{ => doc-cfg}/doc-cfg.rs | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-hide.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-implicit-gate.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-implicit.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-inherit-from-module-79201.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-simplification.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-target-feature.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg-traits.rs (100%) rename tests/rustdoc/{ => doc-cfg}/doc-cfg.rs (100%) diff --git a/tests/rustdoc/doc-cfg-hide.rs b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs similarity index 100% rename from tests/rustdoc/doc-cfg-hide.rs rename to tests/rustdoc/doc-cfg/doc-cfg-hide.rs diff --git a/tests/rustdoc/doc-cfg-implicit-gate.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs similarity index 100% rename from tests/rustdoc/doc-cfg-implicit-gate.rs rename to tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs diff --git a/tests/rustdoc/doc-cfg-implicit.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs similarity index 100% rename from tests/rustdoc/doc-cfg-implicit.rs rename to tests/rustdoc/doc-cfg/doc-cfg-implicit.rs diff --git a/tests/rustdoc/doc-cfg-inherit-from-module-79201.rs b/tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs similarity index 100% rename from tests/rustdoc/doc-cfg-inherit-from-module-79201.rs rename to tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs diff --git a/tests/rustdoc/doc-cfg-simplification.rs b/tests/rustdoc/doc-cfg/doc-cfg-simplification.rs similarity index 100% rename from tests/rustdoc/doc-cfg-simplification.rs rename to tests/rustdoc/doc-cfg/doc-cfg-simplification.rs diff --git a/tests/rustdoc/doc-cfg-target-feature.rs b/tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs similarity index 100% rename from tests/rustdoc/doc-cfg-target-feature.rs rename to tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs diff --git a/tests/rustdoc/doc-cfg-traits.rs b/tests/rustdoc/doc-cfg/doc-cfg-traits.rs similarity index 100% rename from tests/rustdoc/doc-cfg-traits.rs rename to tests/rustdoc/doc-cfg/doc-cfg-traits.rs diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg/doc-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg.rs rename to tests/rustdoc/doc-cfg/doc-cfg.rs From b84f4cc39e99f801dcd37125dffa67eb796c85b8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:01:08 +0200 Subject: [PATCH 249/302] Created `tests/rustdoc/impl` subfolder to limit number of files at the top level --- tests/rustdoc/{ => constant}/assoc-consts-underscore.rs | 0 tests/rustdoc/{ => constant}/assoc-consts-version.rs | 0 tests/rustdoc/{ => constant}/assoc-consts.rs | 0 tests/rustdoc/{ => constant}/associated-consts.rs | 0 tests/rustdoc/{ => constant}/const-display.rs | 0 tests/rustdoc/{ => constant}/const-doc.rs | 0 tests/rustdoc/{ => constant}/const-effect-param.rs | 0 tests/rustdoc/{ => constant}/const-underscore.rs | 0 tests/rustdoc/{ => constant}/const-value-display.rs | 0 tests/rustdoc/{ => constant}/const.rs | 0 .../document-item-with-associated-const-in-where-clause.rs | 0 tests/rustdoc/{ => constant}/generic-const-items.rs | 0 tests/rustdoc/{ => constant}/generic_const_exprs.rs | 0 tests/rustdoc/{ => constant}/glob-shadowing-const.rs | 0 .../{ => constant}/hide-complex-unevaluated-const-arguments.rs | 0 tests/rustdoc/{ => constant}/hide-complex-unevaluated-consts.rs | 0 .../{ => constant}/ice-associated-const-equality-105952.rs | 0 tests/rustdoc/{ => constant}/legacy-const-generic.rs | 0 tests/rustdoc/{ => constant}/link-assoc-const.rs | 0 tests/rustdoc/{ => constant}/redirect-const.rs | 0 tests/rustdoc/{ => constant}/rfc-2632-const-trait-impl.rs | 0 tests/rustdoc/{ => constant}/show-const-contents.rs | 0 .../{ => impl}/auxiliary/cross-crate-hidden-impl-parameter.rs | 0 tests/rustdoc/{ => impl}/auxiliary/extern-impl-trait.rs | 0 tests/rustdoc/{ => impl}/auxiliary/incoherent-impl-types.rs | 0 tests/rustdoc/{ => impl}/auxiliary/issue-100204-aux.rs | 0 tests/rustdoc/{ => impl}/auxiliary/issue-17476.rs | 0 tests/rustdoc/{ => impl}/auxiliary/issue-21092.rs | 0 tests/rustdoc/{ => impl}/auxiliary/issue-22025.rs | 0 tests/rustdoc/{ => impl}/auxiliary/issue-53689.rs | 0 tests/rustdoc/{ => impl}/auxiliary/precise-capturing.rs | 0 tests/rustdoc/{ => impl}/auxiliary/real_gimli.rs | 0 tests/rustdoc/{ => impl}/auxiliary/realcore.rs | 0 tests/rustdoc/{ => impl}/auxiliary/rustdoc-default-impl.rs | 0 .../rustdoc/{ => impl}/auxiliary/rustdoc-impl-parts-crosscrate.rs | 0 tests/rustdoc/{ => impl}/blanket-impl-29503.rs | 0 tests/rustdoc/{ => impl}/blanket-impl-78673.rs | 0 tests/rustdoc/{ => impl}/cross-crate-hidden-impl-parameter.rs | 0 tests/rustdoc/{ => impl}/deduplicate-glob-import-impl-21474.rs | 0 tests/rustdoc/{ => impl}/deduplicate-trait-impl-22025.rs | 0 tests/rustdoc/{ => impl}/default-impl.rs | 0 tests/rustdoc/{ => impl}/deprecated-impls.rs | 0 tests/rustdoc/{ => impl}/doc-hidden-trait-implementors-33069.rs | 0 tests/rustdoc/{ => impl}/doc_auto_cfg_nested_impl.rs | 0 tests/rustdoc/{ => impl}/duplicated_impl.rs | 0 tests/rustdoc/{ => impl}/empty-impl-block.rs | 0 tests/rustdoc/{ => impl}/empty-impls.rs | 0 tests/rustdoc/{ => impl}/extern-impl-trait.rs | 0 tests/rustdoc/{ => impl}/extern-impl.rs | 0 tests/rustdoc/{ => impl}/foreign-implementors-js-43701.rs | 0 tests/rustdoc/{ => impl}/generic-impl.rs | 0 tests/rustdoc/{ => impl}/hidden-implementors-90781.rs | 0 tests/rustdoc/{ => impl}/hidden-impls.rs | 0 tests/rustdoc/{ => impl}/hidden-trait-struct-impls.rs | 0 .../{ => impl}/hide-mut-methods-if-no-derefmut-impl-74083.rs | 0 tests/rustdoc/{ => impl}/impl-alias-substituted.rs | 0 tests/rustdoc/{ => impl}/impl-assoc-type-21092.rs | 0 tests/rustdoc/{ => impl}/impl-associated-items-order.rs | 0 tests/rustdoc/{ => impl}/impl-associated-items-sidebar.rs | 0 tests/rustdoc/{ => impl}/impl-blanket-53689.rs | 0 tests/rustdoc/{ => impl}/impl-box.rs | 0 tests/rustdoc/{ => impl}/impl-disambiguation.rs | 0 tests/rustdoc/{ => impl}/impl-everywhere.rs | 0 tests/rustdoc/{ => impl}/impl-in-const-block.rs | 0 tests/rustdoc/{ => impl}/impl-on-ty-alias-issue-119015.rs | 0 tests/rustdoc/{ => impl}/impl-parts-crosscrate.rs | 0 tests/rustdoc/{ => impl}/impl-parts.rs | 0 tests/rustdoc/{ => impl}/impl-ref-20175.rs | 0 tests/rustdoc/{ => impl}/impl-trait-43869.rs | 0 tests/rustdoc/{ => impl}/impl-trait-alias.rs | 0 tests/rustdoc/{ => impl}/impl-trait-precise-capturing.rs | 0 tests/rustdoc/{ => impl}/impl-type-parameter-33592.rs | 0 tests/rustdoc/{ => impl}/implementor-stable-version.rs | 0 tests/rustdoc/{ => impl}/implementors-unstable-75588.rs | 0 .../rustdoc/{ => impl}/inline-impl-through-glob-import-100204.rs | 0 tests/rustdoc/{ => impl}/manual_impl.rs | 0 tests/rustdoc/{ => impl}/method-link-foreign-trait-impl-17476.rs | 0 tests/rustdoc/{ => impl}/module-impls.rs | 0 tests/rustdoc/{ => impl}/must_implement_one_of.rs | 0 tests/rustdoc/{ => impl}/negative-impl-no-items.rs | 0 tests/rustdoc/{ => impl}/negative-impl-sidebar.rs | 0 tests/rustdoc/{ => impl}/negative-impl.rs | 0 tests/rustdoc/{ => impl}/return-impl-trait.rs | 0 tests/rustdoc/{ => impl}/rustc-incoherent-impls.rs | 0 tests/rustdoc/{ => impl}/same-crate-hidden-impl-parameter.rs | 0 tests/rustdoc/{ => impl}/sidebar-trait-impl-disambiguate-78701.rs | 0 tests/rustdoc/{ => impl}/struct-implementations-title.rs | 0 tests/rustdoc/{ => impl}/trait-impl.rs | 0 .../{ => impl}/trait-implementations-duplicate-self-45584.rs | 0 tests/rustdoc/{ => impl}/underscore-type-in-trait-impl-96381.rs | 0 tests/rustdoc/{ => impl}/universal-impl-trait.rs | 0 tests/rustdoc/{ => impl}/unneeded-trait-implementations-title.rs | 0 92 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => constant}/assoc-consts-underscore.rs (100%) rename tests/rustdoc/{ => constant}/assoc-consts-version.rs (100%) rename tests/rustdoc/{ => constant}/assoc-consts.rs (100%) rename tests/rustdoc/{ => constant}/associated-consts.rs (100%) rename tests/rustdoc/{ => constant}/const-display.rs (100%) rename tests/rustdoc/{ => constant}/const-doc.rs (100%) rename tests/rustdoc/{ => constant}/const-effect-param.rs (100%) rename tests/rustdoc/{ => constant}/const-underscore.rs (100%) rename tests/rustdoc/{ => constant}/const-value-display.rs (100%) rename tests/rustdoc/{ => constant}/const.rs (100%) rename tests/rustdoc/{ => constant}/document-item-with-associated-const-in-where-clause.rs (100%) rename tests/rustdoc/{ => constant}/generic-const-items.rs (100%) rename tests/rustdoc/{ => constant}/generic_const_exprs.rs (100%) rename tests/rustdoc/{ => constant}/glob-shadowing-const.rs (100%) rename tests/rustdoc/{ => constant}/hide-complex-unevaluated-const-arguments.rs (100%) rename tests/rustdoc/{ => constant}/hide-complex-unevaluated-consts.rs (100%) rename tests/rustdoc/{ => constant}/ice-associated-const-equality-105952.rs (100%) rename tests/rustdoc/{ => constant}/legacy-const-generic.rs (100%) rename tests/rustdoc/{ => constant}/link-assoc-const.rs (100%) rename tests/rustdoc/{ => constant}/redirect-const.rs (100%) rename tests/rustdoc/{ => constant}/rfc-2632-const-trait-impl.rs (100%) rename tests/rustdoc/{ => constant}/show-const-contents.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/cross-crate-hidden-impl-parameter.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/extern-impl-trait.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/incoherent-impl-types.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/issue-100204-aux.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/issue-17476.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/issue-21092.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/issue-22025.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/issue-53689.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/precise-capturing.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/real_gimli.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/realcore.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/rustdoc-default-impl.rs (100%) rename tests/rustdoc/{ => impl}/auxiliary/rustdoc-impl-parts-crosscrate.rs (100%) rename tests/rustdoc/{ => impl}/blanket-impl-29503.rs (100%) rename tests/rustdoc/{ => impl}/blanket-impl-78673.rs (100%) rename tests/rustdoc/{ => impl}/cross-crate-hidden-impl-parameter.rs (100%) rename tests/rustdoc/{ => impl}/deduplicate-glob-import-impl-21474.rs (100%) rename tests/rustdoc/{ => impl}/deduplicate-trait-impl-22025.rs (100%) rename tests/rustdoc/{ => impl}/default-impl.rs (100%) rename tests/rustdoc/{ => impl}/deprecated-impls.rs (100%) rename tests/rustdoc/{ => impl}/doc-hidden-trait-implementors-33069.rs (100%) rename tests/rustdoc/{ => impl}/doc_auto_cfg_nested_impl.rs (100%) rename tests/rustdoc/{ => impl}/duplicated_impl.rs (100%) rename tests/rustdoc/{ => impl}/empty-impl-block.rs (100%) rename tests/rustdoc/{ => impl}/empty-impls.rs (100%) rename tests/rustdoc/{ => impl}/extern-impl-trait.rs (100%) rename tests/rustdoc/{ => impl}/extern-impl.rs (100%) rename tests/rustdoc/{ => impl}/foreign-implementors-js-43701.rs (100%) rename tests/rustdoc/{ => impl}/generic-impl.rs (100%) rename tests/rustdoc/{ => impl}/hidden-implementors-90781.rs (100%) rename tests/rustdoc/{ => impl}/hidden-impls.rs (100%) rename tests/rustdoc/{ => impl}/hidden-trait-struct-impls.rs (100%) rename tests/rustdoc/{ => impl}/hide-mut-methods-if-no-derefmut-impl-74083.rs (100%) rename tests/rustdoc/{ => impl}/impl-alias-substituted.rs (100%) rename tests/rustdoc/{ => impl}/impl-assoc-type-21092.rs (100%) rename tests/rustdoc/{ => impl}/impl-associated-items-order.rs (100%) rename tests/rustdoc/{ => impl}/impl-associated-items-sidebar.rs (100%) rename tests/rustdoc/{ => impl}/impl-blanket-53689.rs (100%) rename tests/rustdoc/{ => impl}/impl-box.rs (100%) rename tests/rustdoc/{ => impl}/impl-disambiguation.rs (100%) rename tests/rustdoc/{ => impl}/impl-everywhere.rs (100%) rename tests/rustdoc/{ => impl}/impl-in-const-block.rs (100%) rename tests/rustdoc/{ => impl}/impl-on-ty-alias-issue-119015.rs (100%) rename tests/rustdoc/{ => impl}/impl-parts-crosscrate.rs (100%) rename tests/rustdoc/{ => impl}/impl-parts.rs (100%) rename tests/rustdoc/{ => impl}/impl-ref-20175.rs (100%) rename tests/rustdoc/{ => impl}/impl-trait-43869.rs (100%) rename tests/rustdoc/{ => impl}/impl-trait-alias.rs (100%) rename tests/rustdoc/{ => impl}/impl-trait-precise-capturing.rs (100%) rename tests/rustdoc/{ => impl}/impl-type-parameter-33592.rs (100%) rename tests/rustdoc/{ => impl}/implementor-stable-version.rs (100%) rename tests/rustdoc/{ => impl}/implementors-unstable-75588.rs (100%) rename tests/rustdoc/{ => impl}/inline-impl-through-glob-import-100204.rs (100%) rename tests/rustdoc/{ => impl}/manual_impl.rs (100%) rename tests/rustdoc/{ => impl}/method-link-foreign-trait-impl-17476.rs (100%) rename tests/rustdoc/{ => impl}/module-impls.rs (100%) rename tests/rustdoc/{ => impl}/must_implement_one_of.rs (100%) rename tests/rustdoc/{ => impl}/negative-impl-no-items.rs (100%) rename tests/rustdoc/{ => impl}/negative-impl-sidebar.rs (100%) rename tests/rustdoc/{ => impl}/negative-impl.rs (100%) rename tests/rustdoc/{ => impl}/return-impl-trait.rs (100%) rename tests/rustdoc/{ => impl}/rustc-incoherent-impls.rs (100%) rename tests/rustdoc/{ => impl}/same-crate-hidden-impl-parameter.rs (100%) rename tests/rustdoc/{ => impl}/sidebar-trait-impl-disambiguate-78701.rs (100%) rename tests/rustdoc/{ => impl}/struct-implementations-title.rs (100%) rename tests/rustdoc/{ => impl}/trait-impl.rs (100%) rename tests/rustdoc/{ => impl}/trait-implementations-duplicate-self-45584.rs (100%) rename tests/rustdoc/{ => impl}/underscore-type-in-trait-impl-96381.rs (100%) rename tests/rustdoc/{ => impl}/universal-impl-trait.rs (100%) rename tests/rustdoc/{ => impl}/unneeded-trait-implementations-title.rs (100%) diff --git a/tests/rustdoc/assoc-consts-underscore.rs b/tests/rustdoc/constant/assoc-consts-underscore.rs similarity index 100% rename from tests/rustdoc/assoc-consts-underscore.rs rename to tests/rustdoc/constant/assoc-consts-underscore.rs diff --git a/tests/rustdoc/assoc-consts-version.rs b/tests/rustdoc/constant/assoc-consts-version.rs similarity index 100% rename from tests/rustdoc/assoc-consts-version.rs rename to tests/rustdoc/constant/assoc-consts-version.rs diff --git a/tests/rustdoc/assoc-consts.rs b/tests/rustdoc/constant/assoc-consts.rs similarity index 100% rename from tests/rustdoc/assoc-consts.rs rename to tests/rustdoc/constant/assoc-consts.rs diff --git a/tests/rustdoc/associated-consts.rs b/tests/rustdoc/constant/associated-consts.rs similarity index 100% rename from tests/rustdoc/associated-consts.rs rename to tests/rustdoc/constant/associated-consts.rs diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/constant/const-display.rs similarity index 100% rename from tests/rustdoc/const-display.rs rename to tests/rustdoc/constant/const-display.rs diff --git a/tests/rustdoc/const-doc.rs b/tests/rustdoc/constant/const-doc.rs similarity index 100% rename from tests/rustdoc/const-doc.rs rename to tests/rustdoc/constant/const-doc.rs diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/constant/const-effect-param.rs similarity index 100% rename from tests/rustdoc/const-effect-param.rs rename to tests/rustdoc/constant/const-effect-param.rs diff --git a/tests/rustdoc/const-underscore.rs b/tests/rustdoc/constant/const-underscore.rs similarity index 100% rename from tests/rustdoc/const-underscore.rs rename to tests/rustdoc/constant/const-underscore.rs diff --git a/tests/rustdoc/const-value-display.rs b/tests/rustdoc/constant/const-value-display.rs similarity index 100% rename from tests/rustdoc/const-value-display.rs rename to tests/rustdoc/constant/const-value-display.rs diff --git a/tests/rustdoc/const.rs b/tests/rustdoc/constant/const.rs similarity index 100% rename from tests/rustdoc/const.rs rename to tests/rustdoc/constant/const.rs diff --git a/tests/rustdoc/document-item-with-associated-const-in-where-clause.rs b/tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs similarity index 100% rename from tests/rustdoc/document-item-with-associated-const-in-where-clause.rs rename to tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs diff --git a/tests/rustdoc/generic-const-items.rs b/tests/rustdoc/constant/generic-const-items.rs similarity index 100% rename from tests/rustdoc/generic-const-items.rs rename to tests/rustdoc/constant/generic-const-items.rs diff --git a/tests/rustdoc/generic_const_exprs.rs b/tests/rustdoc/constant/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/generic_const_exprs.rs rename to tests/rustdoc/constant/generic_const_exprs.rs diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/constant/glob-shadowing-const.rs similarity index 100% rename from tests/rustdoc/glob-shadowing-const.rs rename to tests/rustdoc/constant/glob-shadowing-const.rs diff --git a/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs b/tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs similarity index 100% rename from tests/rustdoc/hide-complex-unevaluated-const-arguments.rs rename to tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs diff --git a/tests/rustdoc/hide-complex-unevaluated-consts.rs b/tests/rustdoc/constant/hide-complex-unevaluated-consts.rs similarity index 100% rename from tests/rustdoc/hide-complex-unevaluated-consts.rs rename to tests/rustdoc/constant/hide-complex-unevaluated-consts.rs diff --git a/tests/rustdoc/ice-associated-const-equality-105952.rs b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs similarity index 100% rename from tests/rustdoc/ice-associated-const-equality-105952.rs rename to tests/rustdoc/constant/ice-associated-const-equality-105952.rs diff --git a/tests/rustdoc/legacy-const-generic.rs b/tests/rustdoc/constant/legacy-const-generic.rs similarity index 100% rename from tests/rustdoc/legacy-const-generic.rs rename to tests/rustdoc/constant/legacy-const-generic.rs diff --git a/tests/rustdoc/link-assoc-const.rs b/tests/rustdoc/constant/link-assoc-const.rs similarity index 100% rename from tests/rustdoc/link-assoc-const.rs rename to tests/rustdoc/constant/link-assoc-const.rs diff --git a/tests/rustdoc/redirect-const.rs b/tests/rustdoc/constant/redirect-const.rs similarity index 100% rename from tests/rustdoc/redirect-const.rs rename to tests/rustdoc/constant/redirect-const.rs diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs similarity index 100% rename from tests/rustdoc/rfc-2632-const-trait-impl.rs rename to tests/rustdoc/constant/rfc-2632-const-trait-impl.rs diff --git a/tests/rustdoc/show-const-contents.rs b/tests/rustdoc/constant/show-const-contents.rs similarity index 100% rename from tests/rustdoc/show-const-contents.rs rename to tests/rustdoc/constant/show-const-contents.rs diff --git a/tests/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/auxiliary/extern-impl-trait.rs b/tests/rustdoc/impl/auxiliary/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/auxiliary/extern-impl-trait.rs rename to tests/rustdoc/impl/auxiliary/extern-impl-trait.rs diff --git a/tests/rustdoc/auxiliary/incoherent-impl-types.rs b/tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs similarity index 100% rename from tests/rustdoc/auxiliary/incoherent-impl-types.rs rename to tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs diff --git a/tests/rustdoc/auxiliary/issue-100204-aux.rs b/tests/rustdoc/impl/auxiliary/issue-100204-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-100204-aux.rs rename to tests/rustdoc/impl/auxiliary/issue-100204-aux.rs diff --git a/tests/rustdoc/auxiliary/issue-17476.rs b/tests/rustdoc/impl/auxiliary/issue-17476.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-17476.rs rename to tests/rustdoc/impl/auxiliary/issue-17476.rs diff --git a/tests/rustdoc/auxiliary/issue-21092.rs b/tests/rustdoc/impl/auxiliary/issue-21092.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-21092.rs rename to tests/rustdoc/impl/auxiliary/issue-21092.rs diff --git a/tests/rustdoc/auxiliary/issue-22025.rs b/tests/rustdoc/impl/auxiliary/issue-22025.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-22025.rs rename to tests/rustdoc/impl/auxiliary/issue-22025.rs diff --git a/tests/rustdoc/auxiliary/issue-53689.rs b/tests/rustdoc/impl/auxiliary/issue-53689.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-53689.rs rename to tests/rustdoc/impl/auxiliary/issue-53689.rs diff --git a/tests/rustdoc/auxiliary/precise-capturing.rs b/tests/rustdoc/impl/auxiliary/precise-capturing.rs similarity index 100% rename from tests/rustdoc/auxiliary/precise-capturing.rs rename to tests/rustdoc/impl/auxiliary/precise-capturing.rs diff --git a/tests/rustdoc/auxiliary/real_gimli.rs b/tests/rustdoc/impl/auxiliary/real_gimli.rs similarity index 100% rename from tests/rustdoc/auxiliary/real_gimli.rs rename to tests/rustdoc/impl/auxiliary/real_gimli.rs diff --git a/tests/rustdoc/auxiliary/realcore.rs b/tests/rustdoc/impl/auxiliary/realcore.rs similarity index 100% rename from tests/rustdoc/auxiliary/realcore.rs rename to tests/rustdoc/impl/auxiliary/realcore.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-default-impl.rs b/tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-default-impl.rs rename to tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs rename to tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs diff --git a/tests/rustdoc/blanket-impl-29503.rs b/tests/rustdoc/impl/blanket-impl-29503.rs similarity index 100% rename from tests/rustdoc/blanket-impl-29503.rs rename to tests/rustdoc/impl/blanket-impl-29503.rs diff --git a/tests/rustdoc/blanket-impl-78673.rs b/tests/rustdoc/impl/blanket-impl-78673.rs similarity index 100% rename from tests/rustdoc/blanket-impl-78673.rs rename to tests/rustdoc/impl/blanket-impl-78673.rs diff --git a/tests/rustdoc/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/deduplicate-glob-import-impl-21474.rs b/tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs similarity index 100% rename from tests/rustdoc/deduplicate-glob-import-impl-21474.rs rename to tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs diff --git a/tests/rustdoc/deduplicate-trait-impl-22025.rs b/tests/rustdoc/impl/deduplicate-trait-impl-22025.rs similarity index 100% rename from tests/rustdoc/deduplicate-trait-impl-22025.rs rename to tests/rustdoc/impl/deduplicate-trait-impl-22025.rs diff --git a/tests/rustdoc/default-impl.rs b/tests/rustdoc/impl/default-impl.rs similarity index 100% rename from tests/rustdoc/default-impl.rs rename to tests/rustdoc/impl/default-impl.rs diff --git a/tests/rustdoc/deprecated-impls.rs b/tests/rustdoc/impl/deprecated-impls.rs similarity index 100% rename from tests/rustdoc/deprecated-impls.rs rename to tests/rustdoc/impl/deprecated-impls.rs diff --git a/tests/rustdoc/doc-hidden-trait-implementors-33069.rs b/tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs similarity index 100% rename from tests/rustdoc/doc-hidden-trait-implementors-33069.rs rename to tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs diff --git a/tests/rustdoc/doc_auto_cfg_nested_impl.rs b/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg_nested_impl.rs rename to tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs diff --git a/tests/rustdoc/duplicated_impl.rs b/tests/rustdoc/impl/duplicated_impl.rs similarity index 100% rename from tests/rustdoc/duplicated_impl.rs rename to tests/rustdoc/impl/duplicated_impl.rs diff --git a/tests/rustdoc/empty-impl-block.rs b/tests/rustdoc/impl/empty-impl-block.rs similarity index 100% rename from tests/rustdoc/empty-impl-block.rs rename to tests/rustdoc/impl/empty-impl-block.rs diff --git a/tests/rustdoc/empty-impls.rs b/tests/rustdoc/impl/empty-impls.rs similarity index 100% rename from tests/rustdoc/empty-impls.rs rename to tests/rustdoc/impl/empty-impls.rs diff --git a/tests/rustdoc/extern-impl-trait.rs b/tests/rustdoc/impl/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/extern-impl-trait.rs rename to tests/rustdoc/impl/extern-impl-trait.rs diff --git a/tests/rustdoc/extern-impl.rs b/tests/rustdoc/impl/extern-impl.rs similarity index 100% rename from tests/rustdoc/extern-impl.rs rename to tests/rustdoc/impl/extern-impl.rs diff --git a/tests/rustdoc/foreign-implementors-js-43701.rs b/tests/rustdoc/impl/foreign-implementors-js-43701.rs similarity index 100% rename from tests/rustdoc/foreign-implementors-js-43701.rs rename to tests/rustdoc/impl/foreign-implementors-js-43701.rs diff --git a/tests/rustdoc/generic-impl.rs b/tests/rustdoc/impl/generic-impl.rs similarity index 100% rename from tests/rustdoc/generic-impl.rs rename to tests/rustdoc/impl/generic-impl.rs diff --git a/tests/rustdoc/hidden-implementors-90781.rs b/tests/rustdoc/impl/hidden-implementors-90781.rs similarity index 100% rename from tests/rustdoc/hidden-implementors-90781.rs rename to tests/rustdoc/impl/hidden-implementors-90781.rs diff --git a/tests/rustdoc/hidden-impls.rs b/tests/rustdoc/impl/hidden-impls.rs similarity index 100% rename from tests/rustdoc/hidden-impls.rs rename to tests/rustdoc/impl/hidden-impls.rs diff --git a/tests/rustdoc/hidden-trait-struct-impls.rs b/tests/rustdoc/impl/hidden-trait-struct-impls.rs similarity index 100% rename from tests/rustdoc/hidden-trait-struct-impls.rs rename to tests/rustdoc/impl/hidden-trait-struct-impls.rs diff --git a/tests/rustdoc/hide-mut-methods-if-no-derefmut-impl-74083.rs b/tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs similarity index 100% rename from tests/rustdoc/hide-mut-methods-if-no-derefmut-impl-74083.rs rename to tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs diff --git a/tests/rustdoc/impl-alias-substituted.rs b/tests/rustdoc/impl/impl-alias-substituted.rs similarity index 100% rename from tests/rustdoc/impl-alias-substituted.rs rename to tests/rustdoc/impl/impl-alias-substituted.rs diff --git a/tests/rustdoc/impl-assoc-type-21092.rs b/tests/rustdoc/impl/impl-assoc-type-21092.rs similarity index 100% rename from tests/rustdoc/impl-assoc-type-21092.rs rename to tests/rustdoc/impl/impl-assoc-type-21092.rs diff --git a/tests/rustdoc/impl-associated-items-order.rs b/tests/rustdoc/impl/impl-associated-items-order.rs similarity index 100% rename from tests/rustdoc/impl-associated-items-order.rs rename to tests/rustdoc/impl/impl-associated-items-order.rs diff --git a/tests/rustdoc/impl-associated-items-sidebar.rs b/tests/rustdoc/impl/impl-associated-items-sidebar.rs similarity index 100% rename from tests/rustdoc/impl-associated-items-sidebar.rs rename to tests/rustdoc/impl/impl-associated-items-sidebar.rs diff --git a/tests/rustdoc/impl-blanket-53689.rs b/tests/rustdoc/impl/impl-blanket-53689.rs similarity index 100% rename from tests/rustdoc/impl-blanket-53689.rs rename to tests/rustdoc/impl/impl-blanket-53689.rs diff --git a/tests/rustdoc/impl-box.rs b/tests/rustdoc/impl/impl-box.rs similarity index 100% rename from tests/rustdoc/impl-box.rs rename to tests/rustdoc/impl/impl-box.rs diff --git a/tests/rustdoc/impl-disambiguation.rs b/tests/rustdoc/impl/impl-disambiguation.rs similarity index 100% rename from tests/rustdoc/impl-disambiguation.rs rename to tests/rustdoc/impl/impl-disambiguation.rs diff --git a/tests/rustdoc/impl-everywhere.rs b/tests/rustdoc/impl/impl-everywhere.rs similarity index 100% rename from tests/rustdoc/impl-everywhere.rs rename to tests/rustdoc/impl/impl-everywhere.rs diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl/impl-in-const-block.rs similarity index 100% rename from tests/rustdoc/impl-in-const-block.rs rename to tests/rustdoc/impl/impl-in-const-block.rs diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs similarity index 100% rename from tests/rustdoc/impl-on-ty-alias-issue-119015.rs rename to tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs diff --git a/tests/rustdoc/impl-parts-crosscrate.rs b/tests/rustdoc/impl/impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl-parts-crosscrate.rs rename to tests/rustdoc/impl/impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl/impl-parts.rs similarity index 100% rename from tests/rustdoc/impl-parts.rs rename to tests/rustdoc/impl/impl-parts.rs diff --git a/tests/rustdoc/impl-ref-20175.rs b/tests/rustdoc/impl/impl-ref-20175.rs similarity index 100% rename from tests/rustdoc/impl-ref-20175.rs rename to tests/rustdoc/impl/impl-ref-20175.rs diff --git a/tests/rustdoc/impl-trait-43869.rs b/tests/rustdoc/impl/impl-trait-43869.rs similarity index 100% rename from tests/rustdoc/impl-trait-43869.rs rename to tests/rustdoc/impl/impl-trait-43869.rs diff --git a/tests/rustdoc/impl-trait-alias.rs b/tests/rustdoc/impl/impl-trait-alias.rs similarity index 100% rename from tests/rustdoc/impl-trait-alias.rs rename to tests/rustdoc/impl/impl-trait-alias.rs diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl/impl-trait-precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl-trait-precise-capturing.rs rename to tests/rustdoc/impl/impl-trait-precise-capturing.rs diff --git a/tests/rustdoc/impl-type-parameter-33592.rs b/tests/rustdoc/impl/impl-type-parameter-33592.rs similarity index 100% rename from tests/rustdoc/impl-type-parameter-33592.rs rename to tests/rustdoc/impl/impl-type-parameter-33592.rs diff --git a/tests/rustdoc/implementor-stable-version.rs b/tests/rustdoc/impl/implementor-stable-version.rs similarity index 100% rename from tests/rustdoc/implementor-stable-version.rs rename to tests/rustdoc/impl/implementor-stable-version.rs diff --git a/tests/rustdoc/implementors-unstable-75588.rs b/tests/rustdoc/impl/implementors-unstable-75588.rs similarity index 100% rename from tests/rustdoc/implementors-unstable-75588.rs rename to tests/rustdoc/impl/implementors-unstable-75588.rs diff --git a/tests/rustdoc/inline-impl-through-glob-import-100204.rs b/tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs similarity index 100% rename from tests/rustdoc/inline-impl-through-glob-import-100204.rs rename to tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs diff --git a/tests/rustdoc/manual_impl.rs b/tests/rustdoc/impl/manual_impl.rs similarity index 100% rename from tests/rustdoc/manual_impl.rs rename to tests/rustdoc/impl/manual_impl.rs diff --git a/tests/rustdoc/method-link-foreign-trait-impl-17476.rs b/tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs similarity index 100% rename from tests/rustdoc/method-link-foreign-trait-impl-17476.rs rename to tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs diff --git a/tests/rustdoc/module-impls.rs b/tests/rustdoc/impl/module-impls.rs similarity index 100% rename from tests/rustdoc/module-impls.rs rename to tests/rustdoc/impl/module-impls.rs diff --git a/tests/rustdoc/must_implement_one_of.rs b/tests/rustdoc/impl/must_implement_one_of.rs similarity index 100% rename from tests/rustdoc/must_implement_one_of.rs rename to tests/rustdoc/impl/must_implement_one_of.rs diff --git a/tests/rustdoc/negative-impl-no-items.rs b/tests/rustdoc/impl/negative-impl-no-items.rs similarity index 100% rename from tests/rustdoc/negative-impl-no-items.rs rename to tests/rustdoc/impl/negative-impl-no-items.rs diff --git a/tests/rustdoc/negative-impl-sidebar.rs b/tests/rustdoc/impl/negative-impl-sidebar.rs similarity index 100% rename from tests/rustdoc/negative-impl-sidebar.rs rename to tests/rustdoc/impl/negative-impl-sidebar.rs diff --git a/tests/rustdoc/negative-impl.rs b/tests/rustdoc/impl/negative-impl.rs similarity index 100% rename from tests/rustdoc/negative-impl.rs rename to tests/rustdoc/impl/negative-impl.rs diff --git a/tests/rustdoc/return-impl-trait.rs b/tests/rustdoc/impl/return-impl-trait.rs similarity index 100% rename from tests/rustdoc/return-impl-trait.rs rename to tests/rustdoc/impl/return-impl-trait.rs diff --git a/tests/rustdoc/rustc-incoherent-impls.rs b/tests/rustdoc/impl/rustc-incoherent-impls.rs similarity index 100% rename from tests/rustdoc/rustc-incoherent-impls.rs rename to tests/rustdoc/impl/rustc-incoherent-impls.rs diff --git a/tests/rustdoc/same-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/same-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/sidebar-trait-impl-disambiguate-78701.rs b/tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs similarity index 100% rename from tests/rustdoc/sidebar-trait-impl-disambiguate-78701.rs rename to tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs diff --git a/tests/rustdoc/struct-implementations-title.rs b/tests/rustdoc/impl/struct-implementations-title.rs similarity index 100% rename from tests/rustdoc/struct-implementations-title.rs rename to tests/rustdoc/impl/struct-implementations-title.rs diff --git a/tests/rustdoc/trait-impl.rs b/tests/rustdoc/impl/trait-impl.rs similarity index 100% rename from tests/rustdoc/trait-impl.rs rename to tests/rustdoc/impl/trait-impl.rs diff --git a/tests/rustdoc/trait-implementations-duplicate-self-45584.rs b/tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs similarity index 100% rename from tests/rustdoc/trait-implementations-duplicate-self-45584.rs rename to tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs diff --git a/tests/rustdoc/underscore-type-in-trait-impl-96381.rs b/tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs similarity index 100% rename from tests/rustdoc/underscore-type-in-trait-impl-96381.rs rename to tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs diff --git a/tests/rustdoc/universal-impl-trait.rs b/tests/rustdoc/impl/universal-impl-trait.rs similarity index 100% rename from tests/rustdoc/universal-impl-trait.rs rename to tests/rustdoc/impl/universal-impl-trait.rs diff --git a/tests/rustdoc/unneeded-trait-implementations-title.rs b/tests/rustdoc/impl/unneeded-trait-implementations-title.rs similarity index 100% rename from tests/rustdoc/unneeded-trait-implementations-title.rs rename to tests/rustdoc/impl/unneeded-trait-implementations-title.rs From fa2b9227a1065f7618eb90b52f6f617a13c55b30 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:08:06 +0200 Subject: [PATCH 250/302] Created `tests/rustdoc/assoc` subfolder to limit number of files at the top level --- tests/rustdoc/{ => assoc}/assoc-fns.rs | 0 tests/rustdoc/{ => assoc}/assoc-item-cast.rs | 0 tests/rustdoc/{ => assoc}/assoc-type-bindings-20646.rs | 0 tests/rustdoc/{ => assoc}/assoc-types.rs | 0 .../{ => assoc}/auxiliary/cross-crate-hidden-assoc-trait-items.rs | 0 tests/rustdoc/{ => assoc}/auxiliary/issue-20646.rs | 0 tests/rustdoc/{ => assoc}/auxiliary/issue-20727.rs | 0 tests/rustdoc/{ => assoc}/auxiliary/normalize-assoc-item.rs | 0 tests/rustdoc/{ => assoc}/cross-crate-hidden-assoc-trait-items.rs | 0 tests/rustdoc/{ => assoc}/doc-assoc-item.rs | 0 tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bindings.rs | 0 tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds-deref.rs | 0 tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds-index.rs | 0 tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds.rs | 0 tests/rustdoc/{ => assoc}/normalize-assoc-item.rs | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => assoc}/assoc-fns.rs (100%) rename tests/rustdoc/{ => assoc}/assoc-item-cast.rs (100%) rename tests/rustdoc/{ => assoc}/assoc-type-bindings-20646.rs (100%) rename tests/rustdoc/{ => assoc}/assoc-types.rs (100%) rename tests/rustdoc/{ => assoc}/auxiliary/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/rustdoc/{ => assoc}/auxiliary/issue-20646.rs (100%) rename tests/rustdoc/{ => assoc}/auxiliary/issue-20727.rs (100%) rename tests/rustdoc/{ => assoc}/auxiliary/normalize-assoc-item.rs (100%) rename tests/rustdoc/{ => assoc}/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/rustdoc/{ => assoc}/doc-assoc-item.rs (100%) rename tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bindings.rs (100%) rename tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds-deref.rs (100%) rename tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds-index.rs (100%) rename tests/rustdoc/{ => assoc}/inline-assoc-type-20727-bounds.rs (100%) rename tests/rustdoc/{ => assoc}/normalize-assoc-item.rs (100%) diff --git a/tests/rustdoc/assoc-fns.rs b/tests/rustdoc/assoc/assoc-fns.rs similarity index 100% rename from tests/rustdoc/assoc-fns.rs rename to tests/rustdoc/assoc/assoc-fns.rs diff --git a/tests/rustdoc/assoc-item-cast.rs b/tests/rustdoc/assoc/assoc-item-cast.rs similarity index 100% rename from tests/rustdoc/assoc-item-cast.rs rename to tests/rustdoc/assoc/assoc-item-cast.rs diff --git a/tests/rustdoc/assoc-type-bindings-20646.rs b/tests/rustdoc/assoc/assoc-type-bindings-20646.rs similarity index 100% rename from tests/rustdoc/assoc-type-bindings-20646.rs rename to tests/rustdoc/assoc/assoc-type-bindings-20646.rs diff --git a/tests/rustdoc/assoc-types.rs b/tests/rustdoc/assoc/assoc-types.rs similarity index 100% rename from tests/rustdoc/assoc-types.rs rename to tests/rustdoc/assoc/assoc-types.rs diff --git a/tests/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/auxiliary/issue-20646.rs b/tests/rustdoc/assoc/auxiliary/issue-20646.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-20646.rs rename to tests/rustdoc/assoc/auxiliary/issue-20646.rs diff --git a/tests/rustdoc/auxiliary/issue-20727.rs b/tests/rustdoc/assoc/auxiliary/issue-20727.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-20727.rs rename to tests/rustdoc/assoc/auxiliary/issue-20727.rs diff --git a/tests/rustdoc/auxiliary/normalize-assoc-item.rs b/tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/auxiliary/normalize-assoc-item.rs rename to tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs diff --git a/tests/rustdoc/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/doc-assoc-item.rs b/tests/rustdoc/assoc/doc-assoc-item.rs similarity index 100% rename from tests/rustdoc/doc-assoc-item.rs rename to tests/rustdoc/assoc/doc-assoc-item.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bindings.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bindings.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds-deref.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds-deref.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds-index.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds-index.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs diff --git a/tests/rustdoc/normalize-assoc-item.rs b/tests/rustdoc/assoc/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/normalize-assoc-item.rs rename to tests/rustdoc/assoc/normalize-assoc-item.rs From 4b6bc735079bc07928efe791fecc9ec6cba81fe1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:13:39 +0200 Subject: [PATCH 251/302] Created `tests/rustdoc/enum` subfolder to limit number of files at the top level --- tests/rustdoc/{ => enum}/auxiliary/enum-variant.rs | 0 tests/rustdoc/{ => enum}/auxiliary/variant-struct.rs | 0 tests/rustdoc/{ => enum}/enum-headings.rs | 0 tests/rustdoc/{ => enum}/enum-non-exhaustive-108925.rs | 0 tests/rustdoc/{ => enum}/enum-variant-doc-hidden-field-88600.rs | 0 tests/rustdoc/{ => enum}/enum-variant-fields-heading.rs | 0 .../rustdoc/{ => enum}/enum-variant-fields-heading.variants.html | 0 tests/rustdoc/{ => enum}/enum-variant-value.rs | 0 tests/rustdoc/{ => enum}/render-enum-variant-structlike-32395.rs | 0 tests/rustdoc/{ => enum}/strip-enum-variant.no-not-shown.html | 0 tests/rustdoc/{ => enum}/strip-enum-variant.rs | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => enum}/auxiliary/enum-variant.rs (100%) rename tests/rustdoc/{ => enum}/auxiliary/variant-struct.rs (100%) rename tests/rustdoc/{ => enum}/enum-headings.rs (100%) rename tests/rustdoc/{ => enum}/enum-non-exhaustive-108925.rs (100%) rename tests/rustdoc/{ => enum}/enum-variant-doc-hidden-field-88600.rs (100%) rename tests/rustdoc/{ => enum}/enum-variant-fields-heading.rs (100%) rename tests/rustdoc/{ => enum}/enum-variant-fields-heading.variants.html (100%) rename tests/rustdoc/{ => enum}/enum-variant-value.rs (100%) rename tests/rustdoc/{ => enum}/render-enum-variant-structlike-32395.rs (100%) rename tests/rustdoc/{ => enum}/strip-enum-variant.no-not-shown.html (100%) rename tests/rustdoc/{ => enum}/strip-enum-variant.rs (100%) diff --git a/tests/rustdoc/auxiliary/enum-variant.rs b/tests/rustdoc/enum/auxiliary/enum-variant.rs similarity index 100% rename from tests/rustdoc/auxiliary/enum-variant.rs rename to tests/rustdoc/enum/auxiliary/enum-variant.rs diff --git a/tests/rustdoc/auxiliary/variant-struct.rs b/tests/rustdoc/enum/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/auxiliary/variant-struct.rs rename to tests/rustdoc/enum/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/enum-headings.rs b/tests/rustdoc/enum/enum-headings.rs similarity index 100% rename from tests/rustdoc/enum-headings.rs rename to tests/rustdoc/enum/enum-headings.rs diff --git a/tests/rustdoc/enum-non-exhaustive-108925.rs b/tests/rustdoc/enum/enum-non-exhaustive-108925.rs similarity index 100% rename from tests/rustdoc/enum-non-exhaustive-108925.rs rename to tests/rustdoc/enum/enum-non-exhaustive-108925.rs diff --git a/tests/rustdoc/enum-variant-doc-hidden-field-88600.rs b/tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs similarity index 100% rename from tests/rustdoc/enum-variant-doc-hidden-field-88600.rs rename to tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs diff --git a/tests/rustdoc/enum-variant-fields-heading.rs b/tests/rustdoc/enum/enum-variant-fields-heading.rs similarity index 100% rename from tests/rustdoc/enum-variant-fields-heading.rs rename to tests/rustdoc/enum/enum-variant-fields-heading.rs diff --git a/tests/rustdoc/enum-variant-fields-heading.variants.html b/tests/rustdoc/enum/enum-variant-fields-heading.variants.html similarity index 100% rename from tests/rustdoc/enum-variant-fields-heading.variants.html rename to tests/rustdoc/enum/enum-variant-fields-heading.variants.html diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum/enum-variant-value.rs similarity index 100% rename from tests/rustdoc/enum-variant-value.rs rename to tests/rustdoc/enum/enum-variant-value.rs diff --git a/tests/rustdoc/render-enum-variant-structlike-32395.rs b/tests/rustdoc/enum/render-enum-variant-structlike-32395.rs similarity index 100% rename from tests/rustdoc/render-enum-variant-structlike-32395.rs rename to tests/rustdoc/enum/render-enum-variant-structlike-32395.rs diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/enum/strip-enum-variant.no-not-shown.html similarity index 100% rename from tests/rustdoc/strip-enum-variant.no-not-shown.html rename to tests/rustdoc/enum/strip-enum-variant.no-not-shown.html diff --git a/tests/rustdoc/strip-enum-variant.rs b/tests/rustdoc/enum/strip-enum-variant.rs similarity index 100% rename from tests/rustdoc/strip-enum-variant.rs rename to tests/rustdoc/enum/strip-enum-variant.rs From e245c3bc6bb7d278106649be9a03fc9b374e196b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:18:50 +0200 Subject: [PATCH 252/302] Move primitive rustdoc tests into the `primitive` sub folder --- tests/rustdoc/{ => primitive}/auxiliary/issue-15318.rs | 0 tests/rustdoc/{ => primitive}/auxiliary/primitive-doc.rs | 0 tests/rustdoc/{ => primitive}/cross-crate-primitive-doc.rs | 0 tests/rustdoc/{ => primitive}/no_std-primitive.rs | 0 tests/rustdoc/{ => primitive}/primitive-link.rs | 0 .../rustdoc/{ => primitive}/primitive-raw-pointer-dox-15318-3.rs | 0 tests/rustdoc/{ => primitive}/primitive-raw-pointer-link-15318.rs | 0 .../primitive-raw-pointer-link-no-inlined-15318-2.rs | 0 tests/rustdoc/{ => primitive}/primitive-reference.rs | 0 tests/rustdoc/{ => primitive}/primitive-slice-auto-trait.rs | 0 tests/rustdoc/{ => primitive}/primitive-tuple-auto-trait.rs | 0 tests/rustdoc/{ => primitive}/primitive-tuple-variadic.rs | 0 tests/rustdoc/{ => primitive}/primitive-unit-auto-trait.rs | 0 .../search-index-primitive-inherent-method-23511.rs | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => primitive}/auxiliary/issue-15318.rs (100%) rename tests/rustdoc/{ => primitive}/auxiliary/primitive-doc.rs (100%) rename tests/rustdoc/{ => primitive}/cross-crate-primitive-doc.rs (100%) rename tests/rustdoc/{ => primitive}/no_std-primitive.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-link.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-raw-pointer-dox-15318-3.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-raw-pointer-link-15318.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-raw-pointer-link-no-inlined-15318-2.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-reference.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-slice-auto-trait.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-tuple-auto-trait.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-tuple-variadic.rs (100%) rename tests/rustdoc/{ => primitive}/primitive-unit-auto-trait.rs (100%) rename tests/rustdoc/{ => primitive}/search-index-primitive-inherent-method-23511.rs (100%) diff --git a/tests/rustdoc/auxiliary/issue-15318.rs b/tests/rustdoc/primitive/auxiliary/issue-15318.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-15318.rs rename to tests/rustdoc/primitive/auxiliary/issue-15318.rs diff --git a/tests/rustdoc/auxiliary/primitive-doc.rs b/tests/rustdoc/primitive/auxiliary/primitive-doc.rs similarity index 100% rename from tests/rustdoc/auxiliary/primitive-doc.rs rename to tests/rustdoc/primitive/auxiliary/primitive-doc.rs diff --git a/tests/rustdoc/cross-crate-primitive-doc.rs b/tests/rustdoc/primitive/cross-crate-primitive-doc.rs similarity index 100% rename from tests/rustdoc/cross-crate-primitive-doc.rs rename to tests/rustdoc/primitive/cross-crate-primitive-doc.rs diff --git a/tests/rustdoc/no_std-primitive.rs b/tests/rustdoc/primitive/no_std-primitive.rs similarity index 100% rename from tests/rustdoc/no_std-primitive.rs rename to tests/rustdoc/primitive/no_std-primitive.rs diff --git a/tests/rustdoc/primitive-link.rs b/tests/rustdoc/primitive/primitive-link.rs similarity index 100% rename from tests/rustdoc/primitive-link.rs rename to tests/rustdoc/primitive/primitive-link.rs diff --git a/tests/rustdoc/primitive-raw-pointer-dox-15318-3.rs b/tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-dox-15318-3.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs diff --git a/tests/rustdoc/primitive-raw-pointer-link-15318.rs b/tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-link-15318.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs diff --git a/tests/rustdoc/primitive-raw-pointer-link-no-inlined-15318-2.rs b/tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-link-no-inlined-15318-2.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive/primitive-reference.rs similarity index 100% rename from tests/rustdoc/primitive-reference.rs rename to tests/rustdoc/primitive/primitive-reference.rs diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive/primitive-slice-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-slice-auto-trait.rs rename to tests/rustdoc/primitive/primitive-slice-auto-trait.rs diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive/primitive-tuple-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-tuple-auto-trait.rs rename to tests/rustdoc/primitive/primitive-tuple-auto-trait.rs diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive/primitive-tuple-variadic.rs similarity index 100% rename from tests/rustdoc/primitive-tuple-variadic.rs rename to tests/rustdoc/primitive/primitive-tuple-variadic.rs diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive/primitive-unit-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-unit-auto-trait.rs rename to tests/rustdoc/primitive/primitive-unit-auto-trait.rs diff --git a/tests/rustdoc/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs similarity index 100% rename from tests/rustdoc/search-index-primitive-inherent-method-23511.rs rename to tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs From e14e19a67dcdd7437b29bd37b4aa1fde3e5fecee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:30:40 +0200 Subject: [PATCH 253/302] Created `tests/rustdoc/extern` subfolder to limit number of files at the top level --- tests/rustdoc/extern/auxiliary/empty.rs | 1 + tests/rustdoc/{ => extern}/auxiliary/extern-links.rs | 0 tests/rustdoc/{ => extern}/auxiliary/external-cross-doc.md | 0 tests/rustdoc/{ => extern}/auxiliary/external-cross.rs | 0 tests/rustdoc/{ => extern}/auxiliary/external-doc.md | 0 tests/rustdoc/{ => extern}/auxiliary/html_root.rs | 0 tests/rustdoc/{ => extern}/auxiliary/issue-30109-1.rs | 0 tests/rustdoc/{ => extern}/auxiliary/no_html_root.rs | 0 tests/rustdoc/{ => extern}/auxiliary/panic-item.rs | 0 tests/rustdoc/{ => extern}/auxiliary/pub-extern-crate.rs | 0 .../{ => extern}/auxiliary/rustdoc-extern-default-method.rs | 0 .../rustdoc/{ => extern}/auxiliary/rustdoc-extern-method.rs | 0 tests/rustdoc/extern/auxiliary/variant-struct.rs | 5 +++++ .../extern-default-method.no_href_on_anchor.html | 0 tests/rustdoc/{ => extern}/extern-default-method.rs | 0 tests/rustdoc/{ => extern}/extern-fn-22038.rs | 0 .../rustdoc/{ => extern}/extern-html-root-url-precedence.rs | 0 tests/rustdoc/{ => extern}/extern-html-root-url.rs | 0 tests/rustdoc/{ => extern}/extern-links.rs | 0 tests/rustdoc/{ => extern}/extern-method.rs | 0 tests/rustdoc/{ => extern}/external-cross.rs | 0 tests/rustdoc/{ => extern}/external-doc.rs | 0 tests/rustdoc/{ => extern}/hidden-extern-34025.rs | 0 tests/rustdoc/{ => extern}/link-extern-crate-33178.rs | 0 tests/rustdoc/{ => extern}/link-extern-crate-item-30109.rs | 0 tests/rustdoc/{ => extern}/link-extern-crate-title-33178.rs | 0 tests/rustdoc/{ => extern}/pub-extern-crate.rs | 0 tests/rustdoc/{ => extern}/unsafe-extern-blocks.rs | 0 tests/rustdoc/{ => extern}/unused-extern-crate.rs | 0 29 files changed, 6 insertions(+) create mode 100644 tests/rustdoc/extern/auxiliary/empty.rs rename tests/rustdoc/{ => extern}/auxiliary/extern-links.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/external-cross-doc.md (100%) rename tests/rustdoc/{ => extern}/auxiliary/external-cross.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/external-doc.md (100%) rename tests/rustdoc/{ => extern}/auxiliary/html_root.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/issue-30109-1.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/no_html_root.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/panic-item.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/pub-extern-crate.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/rustdoc-extern-default-method.rs (100%) rename tests/rustdoc/{ => extern}/auxiliary/rustdoc-extern-method.rs (100%) create mode 100644 tests/rustdoc/extern/auxiliary/variant-struct.rs rename tests/rustdoc/{anchors => extern}/extern-default-method.no_href_on_anchor.html (100%) rename tests/rustdoc/{ => extern}/extern-default-method.rs (100%) rename tests/rustdoc/{ => extern}/extern-fn-22038.rs (100%) rename tests/rustdoc/{ => extern}/extern-html-root-url-precedence.rs (100%) rename tests/rustdoc/{ => extern}/extern-html-root-url.rs (100%) rename tests/rustdoc/{ => extern}/extern-links.rs (100%) rename tests/rustdoc/{ => extern}/extern-method.rs (100%) rename tests/rustdoc/{ => extern}/external-cross.rs (100%) rename tests/rustdoc/{ => extern}/external-doc.rs (100%) rename tests/rustdoc/{ => extern}/hidden-extern-34025.rs (100%) rename tests/rustdoc/{ => extern}/link-extern-crate-33178.rs (100%) rename tests/rustdoc/{ => extern}/link-extern-crate-item-30109.rs (100%) rename tests/rustdoc/{ => extern}/link-extern-crate-title-33178.rs (100%) rename tests/rustdoc/{ => extern}/pub-extern-crate.rs (100%) rename tests/rustdoc/{ => extern}/unsafe-extern-blocks.rs (100%) rename tests/rustdoc/{ => extern}/unused-extern-crate.rs (100%) diff --git a/tests/rustdoc/extern/auxiliary/empty.rs b/tests/rustdoc/extern/auxiliary/empty.rs new file mode 100644 index 000000000000..d11c69f812a8 --- /dev/null +++ b/tests/rustdoc/extern/auxiliary/empty.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/tests/rustdoc/auxiliary/extern-links.rs b/tests/rustdoc/extern/auxiliary/extern-links.rs similarity index 100% rename from tests/rustdoc/auxiliary/extern-links.rs rename to tests/rustdoc/extern/auxiliary/extern-links.rs diff --git a/tests/rustdoc/auxiliary/external-cross-doc.md b/tests/rustdoc/extern/auxiliary/external-cross-doc.md similarity index 100% rename from tests/rustdoc/auxiliary/external-cross-doc.md rename to tests/rustdoc/extern/auxiliary/external-cross-doc.md diff --git a/tests/rustdoc/auxiliary/external-cross.rs b/tests/rustdoc/extern/auxiliary/external-cross.rs similarity index 100% rename from tests/rustdoc/auxiliary/external-cross.rs rename to tests/rustdoc/extern/auxiliary/external-cross.rs diff --git a/tests/rustdoc/auxiliary/external-doc.md b/tests/rustdoc/extern/auxiliary/external-doc.md similarity index 100% rename from tests/rustdoc/auxiliary/external-doc.md rename to tests/rustdoc/extern/auxiliary/external-doc.md diff --git a/tests/rustdoc/auxiliary/html_root.rs b/tests/rustdoc/extern/auxiliary/html_root.rs similarity index 100% rename from tests/rustdoc/auxiliary/html_root.rs rename to tests/rustdoc/extern/auxiliary/html_root.rs diff --git a/tests/rustdoc/auxiliary/issue-30109-1.rs b/tests/rustdoc/extern/auxiliary/issue-30109-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-30109-1.rs rename to tests/rustdoc/extern/auxiliary/issue-30109-1.rs diff --git a/tests/rustdoc/auxiliary/no_html_root.rs b/tests/rustdoc/extern/auxiliary/no_html_root.rs similarity index 100% rename from tests/rustdoc/auxiliary/no_html_root.rs rename to tests/rustdoc/extern/auxiliary/no_html_root.rs diff --git a/tests/rustdoc/auxiliary/panic-item.rs b/tests/rustdoc/extern/auxiliary/panic-item.rs similarity index 100% rename from tests/rustdoc/auxiliary/panic-item.rs rename to tests/rustdoc/extern/auxiliary/panic-item.rs diff --git a/tests/rustdoc/auxiliary/pub-extern-crate.rs b/tests/rustdoc/extern/auxiliary/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/auxiliary/pub-extern-crate.rs rename to tests/rustdoc/extern/auxiliary/pub-extern-crate.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-extern-default-method.rs b/tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-extern-default-method.rs rename to tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-extern-method.rs b/tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-extern-method.rs rename to tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs diff --git a/tests/rustdoc/extern/auxiliary/variant-struct.rs b/tests/rustdoc/extern/auxiliary/variant-struct.rs new file mode 100644 index 000000000000..0f3d2e5f1b7a --- /dev/null +++ b/tests/rustdoc/extern/auxiliary/variant-struct.rs @@ -0,0 +1,5 @@ +pub enum Foo { + Bar { + qux: (), + } +} diff --git a/tests/rustdoc/anchors/extern-default-method.no_href_on_anchor.html b/tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html similarity index 100% rename from tests/rustdoc/anchors/extern-default-method.no_href_on_anchor.html rename to tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html diff --git a/tests/rustdoc/extern-default-method.rs b/tests/rustdoc/extern/extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern-default-method.rs rename to tests/rustdoc/extern/extern-default-method.rs diff --git a/tests/rustdoc/extern-fn-22038.rs b/tests/rustdoc/extern/extern-fn-22038.rs similarity index 100% rename from tests/rustdoc/extern-fn-22038.rs rename to tests/rustdoc/extern/extern-fn-22038.rs diff --git a/tests/rustdoc/extern-html-root-url-precedence.rs b/tests/rustdoc/extern/extern-html-root-url-precedence.rs similarity index 100% rename from tests/rustdoc/extern-html-root-url-precedence.rs rename to tests/rustdoc/extern/extern-html-root-url-precedence.rs diff --git a/tests/rustdoc/extern-html-root-url.rs b/tests/rustdoc/extern/extern-html-root-url.rs similarity index 100% rename from tests/rustdoc/extern-html-root-url.rs rename to tests/rustdoc/extern/extern-html-root-url.rs diff --git a/tests/rustdoc/extern-links.rs b/tests/rustdoc/extern/extern-links.rs similarity index 100% rename from tests/rustdoc/extern-links.rs rename to tests/rustdoc/extern/extern-links.rs diff --git a/tests/rustdoc/extern-method.rs b/tests/rustdoc/extern/extern-method.rs similarity index 100% rename from tests/rustdoc/extern-method.rs rename to tests/rustdoc/extern/extern-method.rs diff --git a/tests/rustdoc/external-cross.rs b/tests/rustdoc/extern/external-cross.rs similarity index 100% rename from tests/rustdoc/external-cross.rs rename to tests/rustdoc/extern/external-cross.rs diff --git a/tests/rustdoc/external-doc.rs b/tests/rustdoc/extern/external-doc.rs similarity index 100% rename from tests/rustdoc/external-doc.rs rename to tests/rustdoc/extern/external-doc.rs diff --git a/tests/rustdoc/hidden-extern-34025.rs b/tests/rustdoc/extern/hidden-extern-34025.rs similarity index 100% rename from tests/rustdoc/hidden-extern-34025.rs rename to tests/rustdoc/extern/hidden-extern-34025.rs diff --git a/tests/rustdoc/link-extern-crate-33178.rs b/tests/rustdoc/extern/link-extern-crate-33178.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-33178.rs rename to tests/rustdoc/extern/link-extern-crate-33178.rs diff --git a/tests/rustdoc/link-extern-crate-item-30109.rs b/tests/rustdoc/extern/link-extern-crate-item-30109.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-item-30109.rs rename to tests/rustdoc/extern/link-extern-crate-item-30109.rs diff --git a/tests/rustdoc/link-extern-crate-title-33178.rs b/tests/rustdoc/extern/link-extern-crate-title-33178.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-title-33178.rs rename to tests/rustdoc/extern/link-extern-crate-title-33178.rs diff --git a/tests/rustdoc/pub-extern-crate.rs b/tests/rustdoc/extern/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/pub-extern-crate.rs rename to tests/rustdoc/extern/pub-extern-crate.rs diff --git a/tests/rustdoc/unsafe-extern-blocks.rs b/tests/rustdoc/extern/unsafe-extern-blocks.rs similarity index 100% rename from tests/rustdoc/unsafe-extern-blocks.rs rename to tests/rustdoc/extern/unsafe-extern-blocks.rs diff --git a/tests/rustdoc/unused-extern-crate.rs b/tests/rustdoc/extern/unused-extern-crate.rs similarity index 100% rename from tests/rustdoc/unused-extern-crate.rs rename to tests/rustdoc/extern/unused-extern-crate.rs From 27e39c3ac6173e4a9e9e1439bfc48f0ca1505542 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 May 2025 17:35:41 +0200 Subject: [PATCH 254/302] Created `tests/rustdoc/async` subfolder to limit number of files at the top level --- tests/rustdoc/{ => async}/async-fn-opaque-item.rs | 0 tests/rustdoc/{ => async}/async-fn.rs | 0 tests/rustdoc/{ => async}/async-move-doctest.rs | 0 tests/rustdoc/{ => async}/async-trait-sig.rs | 0 tests/rustdoc/{ => async}/async-trait.rs | 0 tests/rustdoc/{ => async}/auxiliary/async-trait-dep.rs | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{ => async}/async-fn-opaque-item.rs (100%) rename tests/rustdoc/{ => async}/async-fn.rs (100%) rename tests/rustdoc/{ => async}/async-move-doctest.rs (100%) rename tests/rustdoc/{ => async}/async-trait-sig.rs (100%) rename tests/rustdoc/{ => async}/async-trait.rs (100%) rename tests/rustdoc/{ => async}/auxiliary/async-trait-dep.rs (100%) diff --git a/tests/rustdoc/async-fn-opaque-item.rs b/tests/rustdoc/async/async-fn-opaque-item.rs similarity index 100% rename from tests/rustdoc/async-fn-opaque-item.rs rename to tests/rustdoc/async/async-fn-opaque-item.rs diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async/async-fn.rs similarity index 100% rename from tests/rustdoc/async-fn.rs rename to tests/rustdoc/async/async-fn.rs diff --git a/tests/rustdoc/async-move-doctest.rs b/tests/rustdoc/async/async-move-doctest.rs similarity index 100% rename from tests/rustdoc/async-move-doctest.rs rename to tests/rustdoc/async/async-move-doctest.rs diff --git a/tests/rustdoc/async-trait-sig.rs b/tests/rustdoc/async/async-trait-sig.rs similarity index 100% rename from tests/rustdoc/async-trait-sig.rs rename to tests/rustdoc/async/async-trait-sig.rs diff --git a/tests/rustdoc/async-trait.rs b/tests/rustdoc/async/async-trait.rs similarity index 100% rename from tests/rustdoc/async-trait.rs rename to tests/rustdoc/async/async-trait.rs diff --git a/tests/rustdoc/auxiliary/async-trait-dep.rs b/tests/rustdoc/async/auxiliary/async-trait-dep.rs similarity index 100% rename from tests/rustdoc/auxiliary/async-trait-dep.rs rename to tests/rustdoc/async/auxiliary/async-trait-dep.rs From 12d3021ef0e756490ed0adce13b66058cce75744 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 May 2025 15:47:50 +0000 Subject: [PATCH 255/302] Deeply normalize in the new solver in WF --- .../rustc_hir_analysis/src/check/wfcheck.rs | 47 +++++++++++++++---- .../bugs/wf-check-skipped.next.stderr | 13 ----- .../bugs/wf-check-skipped.rs | 5 +- .../inherent-impls-overflow.current.stderr | 8 ++-- .../inherent-impls-overflow.next.stderr | 46 ++++++++++++++++-- .../inherent-impls-overflow.rs | 8 +++- ...dont-ice-on-bad-transmute-in-typeck.stderr | 4 +- .../next-solver/issue-118950-root-region.rs | 1 + .../issue-118950-root-region.stderr | 14 +++++- .../non-wf-in-coerce-pointers.stderr | 4 +- .../ui/wf/check-wf-of-normalized-signature.rs | 24 ++++++++++ .../ui/wf/wf-normalization-sized.next.stderr | 25 +--------- tests/ui/wf/wf-normalization-sized.rs | 2 - 13 files changed, 137 insertions(+), 64 deletions(-) delete mode 100644 tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr create mode 100644 tests/ui/wf/check-wf-of-normalized-signature.rs diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index fa36fe797161..2ec14b2f018c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -76,6 +76,36 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { ) } + /// Convenience function to *deeply* normalize during wfcheck. In the old solver, + /// this just dispatches to [`WfCheckingCtxt::normalize`], but in the new solver + /// this calls `deeply_normalize` and reports errors if they are encountered. + /// + /// This function should be called in favor of `normalize` in cases where we will + /// then check the well-formedness of the type, since we only use the normalized + /// signature types for implied bounds when checking regions. + // FIXME(-Znext-solver): This should be removed when we compute implied outlives + // bounds using the unnormalized signature of the function we're checking. + fn deeply_normalize(&self, span: Span, loc: Option, value: T) -> T + where + T: TypeFoldable>, + { + if self.infcx.next_trait_solver() { + match self.ocx.deeply_normalize( + &ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)), + self.param_env, + value.clone(), + ) { + Ok(value) => value, + Err(errors) => { + self.infcx.err_ctxt().report_fulfillment_errors(errors); + value + } + } + } else { + self.normalize(span, loc, value) + } + } + fn register_wf_obligation(&self, span: Span, loc: Option, term: ty::Term<'tcx>) { let cause = traits::ObligationCause::new( span, @@ -297,7 +327,8 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() { let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { let ty = tcx.type_of(def_id).instantiate_identity(); - let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); + let item_ty = + wfcx.deeply_normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); wfcx.register_wf_obligation( hir_ty.span, Some(WellFormedLoc::Ty(def_id)), @@ -1073,7 +1104,7 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const { .. } => { let ty = tcx.type_of(item.def_id).instantiate_identity(); - let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); check_sized_if_body( wfcx, @@ -1102,7 +1133,7 @@ fn check_associated_item( } if item.defaultness(tcx).has_value() { let ty = tcx.type_of(item.def_id).instantiate_identity(); - let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); } Ok(()) @@ -1149,7 +1180,7 @@ fn check_type_defn<'tcx>( let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = tcx.hir_node_by_def_id(field_id).expect_field(); - let ty = wfcx.normalize( + let ty = wfcx.deeply_normalize( hir_ty.span, None, tcx.type_of(field.did).instantiate_identity(), @@ -1310,7 +1341,7 @@ fn check_item_type( enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id).instantiate_identity(); - let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); + let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); let forbid_unsized = match unsized_handling { UnsizedHandling::Forbid => true, @@ -1375,7 +1406,7 @@ fn check_impl<'tcx>( // other `Foo` impls are incoherent. tcx.ensure_ok().coherent_trait(trait_ref.def_id)?; let trait_span = hir_trait_ref.path.span; - let trait_ref = wfcx.normalize( + let trait_ref = wfcx.deeply_normalize( trait_span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), trait_ref, @@ -1435,7 +1466,7 @@ fn check_impl<'tcx>( } None => { let self_ty = tcx.type_of(item.owner_id).instantiate_identity(); - let self_ty = wfcx.normalize( + let self_ty = wfcx.deeply_normalize( item.span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), self_ty, @@ -1640,7 +1671,7 @@ fn check_fn_or_method<'tcx>( sig.inputs_and_output = tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| { - wfcx.normalize( + wfcx.deeply_normalize( arg_span(idx), Some(WellFormedLoc::Param { function: def_id, diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr deleted file mode 100644 index 81ace4ebb6da..000000000000 --- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0277]: the size for values of type `[u32]` cannot be known at compilation time - --> $DIR/wf-check-skipped.rs:17:25 - | -LL | fn main() -> Foo::Bar::> {} - | ^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u32]` -note: required by an implicit `Sized` bound in `Vec` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs index 52df4efd13e9..2949007d770a 100644 --- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs +++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs @@ -1,8 +1,8 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] known-bug: #100041 -//@[current] check-pass +//@ known-bug: #100041 +//@ check-pass // FIXME(inherent_associated_types): This should fail. #![feature(inherent_associated_types)] @@ -15,4 +15,3 @@ impl Foo { } fn main() -> Foo::Bar::> {} -//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.current.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.current.stderr index 05f5449dbc8b..85ac98f40501 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.current.stderr +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.current.stderr @@ -7,7 +7,7 @@ LL | type Loop = Loop; = note: in case this is a recursive type alias, consider using a struct, enum, or union instead error[E0275]: overflow normalizing the type alias `Loop` - --> $DIR/inherent-impls-overflow.rs:10:1 + --> $DIR/inherent-impls-overflow.rs:12:1 | LL | impl Loop {} | ^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | impl Loop {} = note: in case this is a recursive type alias, consider using a struct, enum, or union instead error[E0275]: overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>` - --> $DIR/inherent-impls-overflow.rs:14:17 + --> $DIR/inherent-impls-overflow.rs:17:17 | LL | type Poly0 = Poly1<(T,)>; | ^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | type Poly0 = Poly1<(T,)>; = note: in case this is a recursive type alias, consider using a struct, enum, or union instead error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` - --> $DIR/inherent-impls-overflow.rs:17:17 + --> $DIR/inherent-impls-overflow.rs:21:17 | LL | type Poly1 = Poly0<(T,)>; | ^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | type Poly1 = Poly0<(T,)>; = note: in case this is a recursive type alias, consider using a struct, enum, or union instead error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` - --> $DIR/inherent-impls-overflow.rs:21:1 + --> $DIR/inherent-impls-overflow.rs:26:1 | LL | impl Poly0<()> {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr index 4f1d339bc999..e94f29de44f0 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr @@ -1,11 +1,31 @@ error[E0271]: type mismatch resolving `Loop normalizes-to _` - --> $DIR/inherent-impls-overflow.rs:10:6 + --> $DIR/inherent-impls-overflow.rs:8:13 + | +LL | type Loop = Loop; + | ^^^^ types differ + +error[E0271]: type mismatch resolving `Loop normalizes-to _` + --> $DIR/inherent-impls-overflow.rs:12:1 + | +LL | impl Loop {} + | ^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `Loop normalizes-to _` + --> $DIR/inherent-impls-overflow.rs:12:6 | LL | impl Loop {} | ^^^^ types differ +error[E0275]: overflow evaluating the requirement `Poly1<(T,)> == _` + --> $DIR/inherent-impls-overflow.rs:17:17 + | +LL | type Poly0 = Poly1<(T,)>; + | ^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`) + error: type parameter `T` is only used recursively - --> $DIR/inherent-impls-overflow.rs:14:24 + --> $DIR/inherent-impls-overflow.rs:17:24 | LL | type Poly0 = Poly1<(T,)>; | - ^ @@ -15,8 +35,16 @@ LL | type Poly0 = Poly1<(T,)>; = help: consider removing `T` or referring to it in the body of the type alias = note: all type parameters must be used in a non-recursive way in order to constrain their variance +error[E0275]: overflow evaluating the requirement `Poly0<(T,)> == _` + --> $DIR/inherent-impls-overflow.rs:21:17 + | +LL | type Poly1 = Poly0<(T,)>; + | ^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`) + error: type parameter `T` is only used recursively - --> $DIR/inherent-impls-overflow.rs:17:24 + --> $DIR/inherent-impls-overflow.rs:21:24 | LL | type Poly1 = Poly0<(T,)>; | - ^ @@ -27,14 +55,22 @@ LL | type Poly1 = Poly0<(T,)>; = note: all type parameters must be used in a non-recursive way in order to constrain their variance error[E0275]: overflow evaluating the requirement `Poly0<()> == _` - --> $DIR/inherent-impls-overflow.rs:21:6 + --> $DIR/inherent-impls-overflow.rs:26:1 + | +LL | impl Poly0<()> {} + | ^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`) + +error[E0275]: overflow evaluating the requirement `Poly0<()> == _` + --> $DIR/inherent-impls-overflow.rs:26:6 | LL | impl Poly0<()> {} | ^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`) -error: aborting due to 4 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0271, E0275. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs index 0d5ec7d15307..b4a347cb098c 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs @@ -5,21 +5,27 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -type Loop = Loop; //[current]~ ERROR overflow normalizing the type alias `Loop` +type Loop = Loop; +//[current]~^ ERROR overflow normalizing the type alias `Loop` +//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _` impl Loop {} //[current]~^ ERROR overflow normalizing the type alias `Loop` //[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _` +//[next]~| ERROR type mismatch resolving `Loop normalizes-to _` type Poly0 = Poly1<(T,)>; //[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>` //[next]~^^ ERROR type parameter `T` is only used recursively +//[next]~| ERROR overflow evaluating the requirement type Poly1 = Poly0<(T,)>; //[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` //[next]~^^ ERROR type parameter `T` is only used recursively +//[next]~| ERROR overflow evaluating the requirement impl Poly0<()> {} //[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` //[next]~^^ ERROR overflow evaluating the requirement `Poly0<()> == _` +//[next]~| ERROR overflow evaluating the requirement fn main() {} diff --git a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr index 2d42fedae438..e1ae981b2492 100644 --- a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr +++ b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied - --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:11 + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:22 | LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs index 8fe53d6773b9..fe336766891d 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.rs +++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs @@ -19,5 +19,6 @@ impl Overlap for T {} impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} //~^ ERROR cannot find type `Missing` in this scope //~| ERROR the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied +//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied fn main() {} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index d2a58e95629a..45fa33dff52f 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -26,6 +26,18 @@ LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } +error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied + --> $DIR/issue-118950-root-region.rs:19:9 + | +LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-118950-root-region.rs:8:1 + | +LL | trait ToUnit<'a> { + | ^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied --> $DIR/issue-118950-root-region.rs:19:47 | @@ -37,7 +49,7 @@ help: consider further restricting type parameter `T` with trait `Overlap` LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap, T: Overlap fn(Assoc<'a, T>)> {} | ++++++++++++++++++++++++++++++++++++++ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0277, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr index 32a7766a638d..72be10367dac 100644 --- a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): Wf` is not satisfied - --> $DIR/non-wf-in-coerce-pointers.rs:8:17 + --> $DIR/non-wf-in-coerce-pointers.rs:8:8 | LL | f: &'static <() as Wf>::Assoc, - | ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/non-wf-in-coerce-pointers.rs:3:1 diff --git a/tests/ui/wf/check-wf-of-normalized-signature.rs b/tests/ui/wf/check-wf-of-normalized-signature.rs new file mode 100644 index 000000000000..5fda69601d99 --- /dev/null +++ b/tests/ui/wf/check-wf-of-normalized-signature.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for . +// Ensure that we check the well-formedness of `::Output` after normalizing +// the type to `()`, since we only imply outlives bounds from the normalized signature, so we +// don't know (e.g.) that `&mut T` is WF. + + +trait Mode { + type Output; + fn from_mut(_r: &mut Self::Output) -> Self::Output<&mut T>; +} + +struct Check; + +impl Mode for Check { + type Output = (); + fn from_mut(_r: &mut Self::Output) -> Self::Output<&mut T> {} +} + +fn main() {} diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr index 66c4f214415d..804dd0a252d1 100644 --- a/tests/ui/wf/wf-normalization-sized.next.stderr +++ b/tests/ui/wf/wf-normalization-sized.next.stderr @@ -8,7 +8,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:22:11 + --> $DIR/wf-normalization-sized.rs:21:11 | LL | const _: as WellUnformed>::RequestNormalize = (); | ^^^^^^^^ doesn't have a size known at compile-time @@ -17,27 +17,6 @@ LL | const _: as WellUnformed>::RequestNormalize = (); note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:19:11 - | -LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); - | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]` - = note: slice and array elements must have `Sized` type - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:22:11 - | -LL | const _: as WellUnformed>::RequestNormalize = (); - | ^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `str` -note: required by an implicit `Sized` bound in `Vec` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs index 5396cc8b32a8..e695fd93fb0e 100644 --- a/tests/ui/wf/wf-normalization-sized.rs +++ b/tests/ui/wf/wf-normalization-sized.rs @@ -18,9 +18,7 @@ impl WellUnformed for T { const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); //[next]~^ ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time -//[next]~| ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time const _: as WellUnformed>::RequestNormalize = (); //[next]~^ ERROR the size for values of type `str` cannot be known at compilation time -//[next]~| ERROR the size for values of type `str` cannot be known at compilation time fn main() {} From fa6d0d1ba263c02d1fd660c06f3918ea6e591ce7 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Sun, 4 May 2025 00:04:38 -0400 Subject: [PATCH 256/302] Use more accurate ELF flags on MIPS --- .../rustc_codegen_ssa/src/back/metadata.rs | 55 ++++++++++--------- compiler/rustc_target/src/spec/mod.rs | 9 ++- .../spec/targets/mips64_openwrt_linux_musl.rs | 1 + .../targets/mips64_unknown_linux_gnuabi64.rs | 1 + .../targets/mips64_unknown_linux_muslabi64.rs | 1 + .../mips64el_unknown_linux_gnuabi64.rs | 1 + .../mips64el_unknown_linux_muslabi64.rs | 7 ++- .../mipsisa64r6_unknown_linux_gnuabi64.rs | 1 + .../mipsisa64r6el_unknown_linux_gnuabi64.rs | 1 + 9 files changed, 50 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ebcccf1b97d9..2739f3844b53 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -270,45 +270,50 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 { pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { match architecture { - Architecture::Mips => { - let arch = match sess.target.options.cpu.as_ref() { - "mips1" => elf::EF_MIPS_ARCH_1, - "mips2" => elf::EF_MIPS_ARCH_2, + Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => { + let is_32bit = architecture == Architecture::Mips; + let mut e_flags = match sess.target.options.cpu.as_ref() { + "mips1" if is_32bit => elf::EF_MIPS_ARCH_1, + "mips2" if is_32bit => elf::EF_MIPS_ARCH_2, "mips3" => elf::EF_MIPS_ARCH_3, "mips4" => elf::EF_MIPS_ARCH_4, "mips5" => elf::EF_MIPS_ARCH_5, - s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, - _ => elf::EF_MIPS_ARCH_32R2, + "mips32r2" if is_32bit => elf::EF_MIPS_ARCH_32R2, + "mips32r6" if is_32bit => elf::EF_MIPS_ARCH_32R6, + "mips64r2" if !is_32bit => elf::EF_MIPS_ARCH_64R2, + "mips64r6" if !is_32bit => elf::EF_MIPS_ARCH_64R6, + s if s.starts_with("mips32") && !is_32bit => { + sess.dcx().fatal(format!("invalid CPU `{}` for 64-bit MIPS target", s)) + } + s if s.starts_with("mips64") && is_32bit => { + sess.dcx().fatal(format!("invalid CPU `{}` for 32-bit MIPS target", s)) + } + _ if is_32bit => elf::EF_MIPS_ARCH_32R2, + _ => elf::EF_MIPS_ARCH_64R2, }; - let mut e_flags = elf::EF_MIPS_CPIC | arch; - - // If the ABI is explicitly given, use it or default to O32. - match sess.target.options.llvm_abiname.to_lowercase().as_str() { - "n32" => e_flags |= elf::EF_MIPS_ABI2, - "o32" => e_flags |= elf::EF_MIPS_ABI_O32, - _ => e_flags |= elf::EF_MIPS_ABI_O32, + // If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS, + // which is the only option. + match sess.target.options.llvm_abiname.as_ref() { + "o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, + "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, + "n64" if !is_32bit => {} + "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, + "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"), + s if is_32bit => { + sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) + } + s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)), }; if sess.target.options.relocation_model != RelocModel::Static { - e_flags |= elf::EF_MIPS_PIC; + e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC; } if sess.target.options.cpu.contains("r6") { e_flags |= elf::EF_MIPS_NAN2008; } e_flags } - Architecture::Mips64 => { - // copied from `mips64el-linux-gnuabi64-gcc foo.c -c` - let e_flags = elf::EF_MIPS_CPIC - | elf::EF_MIPS_PIC - | if sess.target.options.cpu.contains("r6") { - elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008 - } else { - elf::EF_MIPS_ARCH_64R2 - }; - e_flags - } Architecture::Riscv32 | Architecture::Riscv64 => { // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc let mut e_flags: u32 = 0x0; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 37ea0d6e7b58..a3f36e51f32c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3567,7 +3567,14 @@ impl Target { "x86" => (Architecture::I386, None), "s390x" => (Architecture::S390x, None), "mips" | "mips32r6" => (Architecture::Mips, None), - "mips64" | "mips64r6" => (Architecture::Mips64, None), + "mips64" | "mips64r6" => ( + if self.options.llvm_abiname.as_ref() == "n32" { + Architecture::Mips64_N32 + } else { + Architecture::Mips64 + }, + None, + ), "x86_64" => ( if self.pointer_width == 32 { Architecture::X86_64_X32 diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index 71b3fbe00b2f..508abc010184 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target { abi: "abi64".into(), endian: Endian::Big, mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index b130ca29c7f0..a26350ff2250 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index 4ea7c7bff44a..fd5095030530 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -25,6 +25,7 @@ pub(crate) fn target() -> Target { mcount: "_mcount".into(), // FIXME(compiler-team#422): musl targets should be dynamically linked by default. crt_static_default: true, + llvm_abiname: "n64".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index a9afea27ef34..19bceadc6223 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index 7bdd9edda70c..aa087b1a35af 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -19,6 +19,11 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), - options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base }, + options: TargetOptions { + abi: "abi64".into(), + mcount: "_mcount".into(), + llvm_abiname: "n64".into(), + ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index 3eefa27ea04b..cdd5f6b84365 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index 0887180791c7..88879a25818b 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, From 57941afb23ef59e956d2a5ef6604369543edf419 Mon Sep 17 00:00:00 2001 From: smrobtzz <148004237+smrobtzz@users.noreply.github.com> Date: Mon, 5 May 2025 00:21:14 -0400 Subject: [PATCH 257/302] Apply suggestions from code review Co-authored-by: Jubilee --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 13 ++++++++++++- compiler/rustc_target/src/spec/mod.rs | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 2739f3844b53..ec46c71b0e40 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -271,6 +271,8 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 { pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { match architecture { Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => { + // "N32" indicates an "ILP32" data model on a 64-bit MIPS CPU + // like SPARC's "v8+", x86_64's "x32", or the watchOS "arm64_32". let is_32bit = architecture == Architecture::Mips; let mut e_flags = match sess.target.options.cpu.as_ref() { "mips1" if is_32bit => elf::EF_MIPS_ARCH_1, @@ -293,7 +295,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { }; // If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS, - // which is the only option. + // which is the only "true" 32-bit option that LLVM supports. match sess.target.options.llvm_abiname.as_ref() { "o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, @@ -307,6 +309,15 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { }; if sess.target.options.relocation_model != RelocModel::Static { + // PIC means position-independent code. CPIC means "calls PIC". + // CPIC was mutually exclusive with PIC according to + // the SVR4 MIPS ABI https://refspecs.linuxfoundation.org/elf/mipsabi.pdf + // and should have only appeared on static objects with dynamically calls. + // At some point someone (GCC?) decided to set CPIC even for PIC. + // Nowadays various things expect both set on the same object file + // and may even error if you mix CPIC and non-CPIC object files, + // despite that being the entire point of the CPIC ABI extension! + // As we are in Rome, we do as the Romans do. e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC; } if sess.target.options.cpu.contains("r6") { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a3f36e51f32c..303be54a6d78 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3568,6 +3568,11 @@ impl Target { "s390x" => (Architecture::S390x, None), "mips" | "mips32r6" => (Architecture::Mips, None), "mips64" | "mips64r6" => ( + // While there are currently no builtin targets + // using the N32 ABI, it is possible to specify + // it using a custom target specification. N32 + // is an ILP32 ABI like the Aarch64_Ilp32 + // and X86_64_X32 cases above and below this one. if self.options.llvm_abiname.as_ref() == "n32" { Architecture::Mips64_N32 } else { From 872387195dce76176b92b954e1ba82bfe9fba928 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 5 May 2025 19:01:06 +0200 Subject: [PATCH 258/302] Update books --- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/reference b/src/doc/reference index 3bf3402aea98..387392674d74 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 3bf3402aea982b876eb56c87da17b0685c6461d5 +Subproject commit 387392674d74656f7cb437c05a96f0c52ea8e601 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 0d7964d5b22c..8a8918c69853 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 0d7964d5b22cf920237ef1282d869564b4883b88 +Subproject commit 8a8918c698534547fa8a1a693cb3e7277f0bfb2f From 6a7996e30325e28215b318feb7cc56bcff0e2bb5 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 19 Apr 2025 11:52:18 +0200 Subject: [PATCH 259/302] Take into-account `-Zremap-path-scope` when embedding filenames --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 - compiler/rustc_session/src/config.rs | 8 +- compiler/rustc_span/src/lib.rs | 34 +++----- compiler/rustc_span/src/source_map.rs | 80 ++++++++++--------- compiler/rustc_span/src/source_map/tests.rs | 73 +++++++++++++++++ .../run-make/remap-path-prefix-dwarf/rmake.rs | 53 ++++++++++++ .../src/print_value.rs | 7 ++ .../remap-path-prefix-dwarf/src/some_value.rs | 6 ++ tests/run-make/remap-path-prefix/rmake.rs | 6 +- 9 files changed, 205 insertions(+), 64 deletions(-) create mode 100644 tests/run-make/remap-path-prefix-dwarf/src/print_value.rs create mode 100644 tests/run-make/remap-path-prefix-dwarf/src/some_value.rs diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ea61d1b40a6..e4cf58fccda2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -551,8 +551,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match source_file.name { FileName::Real(ref original_file_name) => { - // FIXME: This should probably to conditionally remapped under - // a RemapPathScopeComponents but which one? let adapted_file_name = source_map .path_mapping() .to_embeddable_absolute_path(original_file_name.clone(), working_directory); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e2d36f6a4e2f..ccb1e9509604 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,8 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{ - FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym, + FileName, FileNameDisplayPreference, FileNameEmbeddablePreference, RealFileName, + SourceFileHashAlgorithm, Symbol, sym, }; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple, @@ -1316,6 +1317,11 @@ fn file_path_mapping( } else { FileNameDisplayPreference::Local }, + if unstable_opts.remap_path_scope.is_all() { + FileNameEmbeddablePreference::RemappedOnly + } else { + FileNameEmbeddablePreference::LocalAndRemapped + }, ) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9722031f209b..6fcf77e31a22 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -224,7 +224,7 @@ pub fn with_metavar_spans(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { // FIXME: We should use this enum or something like it to get rid of the // use of magic `/rust/1.x/...` paths across the board. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)] pub enum RealFileName { LocalPath(PathBuf), /// For remapped paths (namely paths into libstd that have been mapped @@ -250,28 +250,6 @@ impl Hash for RealFileName { } } -// This is functionally identical to #[derive(Encodable)], with the exception of -// an added assert statement -impl Encodable for RealFileName { - fn encode(&self, encoder: &mut S) { - match *self { - RealFileName::LocalPath(ref local_path) => { - encoder.emit_u8(0); - local_path.encode(encoder); - } - - RealFileName::Remapped { ref local_path, ref virtual_name } => { - encoder.emit_u8(1); - // For privacy and build reproducibility, we must not embed host-dependant path - // in artifacts if they have been remapped by --remap-path-prefix - assert!(local_path.is_none()); - local_path.encode(encoder); - virtual_name.encode(encoder); - } - } - } -} - impl RealFileName { /// Returns the path suitable for reading from the file system on the local host, /// if this information exists. @@ -368,6 +346,16 @@ impl From for FileName { } } +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub enum FileNameEmbeddablePreference { + /// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`. + /// + /// Otherwise embed the local-path into the `virtual_path`. + RemappedOnly, + /// Embed the original path as well as its remapped `virtual_path` component if available. + LocalAndRemapped, +} + #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] pub enum FileNameDisplayPreference { /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 0273bb040f43..8a3644163caf 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1108,18 +1108,28 @@ pub fn get_source_map() -> Option> { pub struct FilePathMapping { mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, } impl FilePathMapping { pub fn empty() -> FilePathMapping { - FilePathMapping::new(Vec::new(), FileNameDisplayPreference::Local) + FilePathMapping::new( + Vec::new(), + FileNameDisplayPreference::Local, + FileNameEmbeddablePreference::RemappedOnly, + ) } pub fn new( mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, ) -> FilePathMapping { - FilePathMapping { mapping, filename_display_for_diagnostics } + FilePathMapping { + mapping, + filename_display_for_diagnostics, + filename_embeddable_preference, + } } /// Applies any path prefix substitution as defined by the mapping. @@ -1217,11 +1227,13 @@ impl FilePathMapping { ) -> RealFileName { match file_path { // Anything that's already remapped we don't modify, except for erasing - // the `local_path` portion. - RealFileName::Remapped { local_path: _, virtual_name } => { + // the `local_path` portion (if desired). + RealFileName::Remapped { local_path, virtual_name } => { RealFileName::Remapped { - // We do not want any local path to be exported into metadata - local_path: None, + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path, + }, // We use the remapped name verbatim, even if it looks like a relative // path. The assumption is that the user doesn't want us to further // process paths that have gone through remapping. @@ -1231,12 +1243,18 @@ impl FilePathMapping { RealFileName::LocalPath(unmapped_file_path) => { // If no remapping has been applied yet, try to do so - let (new_path, was_remapped) = self.map_prefix(unmapped_file_path); + let (new_path, was_remapped) = self.map_prefix(&unmapped_file_path); if was_remapped { // It was remapped, so don't modify further return RealFileName::Remapped { - local_path: None, virtual_name: new_path.into_owned(), + // But still provide the local path if desired + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path) + } + }, }; } @@ -1252,17 +1270,23 @@ impl FilePathMapping { match working_directory { RealFileName::LocalPath(unmapped_working_dir_abs) => { - let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel); + let unmapped_file_path_abs = + unmapped_working_dir_abs.join(unmapped_file_path_rel); // Although neither `working_directory` nor the file name were subject // to path remapping, the concatenation between the two may be. Hence // we need to do a remapping here. - let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs); + let (file_path_abs, was_remapped) = + self.map_prefix(&unmapped_file_path_abs); if was_remapped { RealFileName::Remapped { - // Erase the actual path - local_path: None, virtual_name: file_path_abs.into_owned(), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path_abs) + } + }, } } else { // No kind of remapping applied to this path, so @@ -1271,15 +1295,20 @@ impl FilePathMapping { } } RealFileName::Remapped { - local_path: _, + local_path, virtual_name: remapped_working_dir_abs, } => { // If working_directory has been remapped, then we emit // Remapped variant as the expanded path won't be valid RealFileName::Remapped { - local_path: None, virtual_name: Path::new(remapped_working_dir_abs) - .join(unmapped_file_path_rel), + .join(&unmapped_file_path_rel), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path + .as_ref() + .map(|local_path| local_path.join(unmapped_file_path_rel)), + }, } } } @@ -1287,27 +1316,6 @@ impl FilePathMapping { } } - /// Expand a relative path to an absolute path **without** remapping taken into account. - /// - /// The resulting `RealFileName` will have its `virtual_path` portion erased if - /// possible (i.e. if there's also a remapped path). - pub fn to_local_embeddable_absolute_path( - &self, - file_path: RealFileName, - working_directory: &RealFileName, - ) -> RealFileName { - let file_path = file_path.local_path_if_available(); - if file_path.is_absolute() { - // No remapping has applied to this path and it is absolute, - // so the working directory cannot influence it either, so - // we are done. - return RealFileName::LocalPath(file_path.to_path_buf()); - } - debug_assert!(file_path.is_relative()); - let working_directory = working_directory.local_path_if_available(); - RealFileName::LocalPath(Path::new(working_directory).join(file_path)) - } - /// Attempts to (heuristically) reverse a prefix mapping. /// /// Returns [`Some`] if there is exactly one mapping where the "to" part is diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 957f55e39138..589c2a363548 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -305,6 +305,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -316,6 +317,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -327,6 +329,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -338,6 +341,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -351,6 +355,7 @@ fn path_prefix_remapping_expand_to_absolute() { let mapping = &FilePathMapping::new( vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); let working_directory = path("/foo"); let working_directory = RealFileName::Remapped { @@ -448,6 +453,71 @@ fn path_prefix_remapping_expand_to_absolute() { ); } +#[test] +fn path_prefix_remapping_expand_to_absolute_and_local() { + // "virtual" working directory is relative path + let mapping = &FilePathMapping::new( + vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], + FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::LocalAndRemapped, + ); + let working_directory = path("/foo"); + let working_directory = RealFileName::Remapped { + local_path: Some(working_directory.clone()), + virtual_name: mapping.map_prefix(working_directory).0.into_owned(), + }; + + assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); + + // Unmapped absolute path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/foo/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/foo/src/main.rs")), + virtual_name: path("FOO/src/main.rs") + } + ); + + // Unmapped absolute path with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/bar/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped absolute path, with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs"), + }, + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped relative path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }, + &working_directory + ), + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } + ); +} + #[test] fn path_prefix_remapping_reverse() { // Ignores options without alphanumeric chars. @@ -455,6 +525,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/")), (path("def"), path("."))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None); @@ -466,6 +537,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def"), path("/redacted"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None); @@ -476,6 +548,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def/ghi"), path("/fake/dir"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!( diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs index ede1d6157425..3d6ca014fc2a 100644 --- a/tests/run-make/remap-path-prefix-dwarf/rmake.rs +++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs @@ -91,6 +91,59 @@ fn main() { )), dwarf_test: DwarfDump::ParentTest, }); + + check_dwarf_deps("macro", DwarfDump::AvoidSrcPath); + check_dwarf_deps("diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("macro,diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("object", DwarfDump::ContainsSrcPath); +} + +#[track_caller] +fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) { + // build some_value.rs + let mut rustc_sm = rustc(); + rustc_sm.input(cwd().join("src/some_value.rs")); + rustc_sm.arg("-Cdebuginfo=2"); + rustc_sm.arg(format!("-Zremap-path-scope={}", scope)); + rustc_sm.arg("--remap-path-prefix"); + rustc_sm.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_sm.arg("-Csplit-debuginfo=off"); + rustc_sm.run(); + + // build print_value.rs + let print_value_rlib = rust_lib_name(&format!("print_value.{scope}")); + let mut rustc_pv = rustc(); + rustc_pv.input(cwd().join("src/print_value.rs")); + rustc_pv.output(&print_value_rlib); + rustc_pv.arg("-Cdebuginfo=2"); + rustc_pv.arg(format!("-Zremap-path-scope={}", scope)); + rustc_pv.arg("--remap-path-prefix"); + rustc_pv.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_pv.arg("-Csplit-debuginfo=off"); + rustc_pv.run(); + + match dwarf_test { + DwarfDump::AvoidSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_not_contains("REMAPPED/src/some_value.rs") + .assert_stdout_not_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains("REMAPPED/REMAPPED") + .assert_stdout_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_contains(cwd().join("src/print_value.rs").display().to_string()); + } + DwarfDump::ContainsSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_contains("REMAPPED/src/some_value.rs") + .assert_stdout_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_not_contains(cwd().join("src/print_value.rs").display().to_string()); + } + _ => unreachable!(), + } } #[track_caller] diff --git a/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs new file mode 100644 index 000000000000..f7653025ba5a --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +extern crate some_value; + +pub fn print_value() { + println!("{}", some_value::get_some_value()); +} diff --git a/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs new file mode 100644 index 000000000000..aa95a1bdf73b --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs @@ -0,0 +1,6 @@ +#![crate_type = "rlib"] + +#[inline] +pub fn get_some_value() -> i32 { + 42 +} diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index aeb30e72d5bf..b4f7f4769b5b 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -47,10 +47,10 @@ fn main() { out_object.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_macro.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_diagobj.run(); rmeta_contains("/the/aux/lib.rs"); rmeta_not_contains("auxiliary"); @@ -58,6 +58,7 @@ fn main() { //FIXME(Oneirical): These could be generalized into run_make_support // helper functions. +#[track_caller] fn rmeta_contains(expected: &str) { // Normalize to account for path differences in Windows. if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { @@ -69,6 +70,7 @@ fn rmeta_contains(expected: &str) { } } +#[track_caller] fn rmeta_not_contains(expected: &str) { // Normalize to account for path differences in Windows. if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { From 7fc84ac964b45955cc9beb7ec269d3d06a3591ab Mon Sep 17 00:00:00 2001 From: Skgland Date: Mon, 5 May 2025 20:40:44 +0200 Subject: [PATCH 260/302] expand comment --- .../type-inference/regression-issue-81317.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/ui/type-inference/regression-issue-81317.rs b/tests/ui/type-inference/regression-issue-81317.rs index 50deb013d4b1..39c91948426b 100644 --- a/tests/ui/type-inference/regression-issue-81317.rs +++ b/tests/ui/type-inference/regression-issue-81317.rs @@ -1,4 +1,33 @@ // Regression test for #81317: type can no longer be infered as of 1.49 +// +// The problem is that the xor operator and the index.into() each have two candidate impls that could apply +// { S as BitXor, S as BitXor<&'a S> } for xor and +// { T::I as Into, T::I as Into } for index.into() +// previously inference was able to infer that the only valid combination was +// S as BitXor and T::I as Into +// +// after rust-lang/rust#73905 this is no longer infered +// +// the error message could be better e.g. when iv is unused or has an an explicitly specified type S +// there is currently the following help message +// +// error[E0284]: type annotations needed +// --> src/main.rs:13:24 +// | +// 42 | let iv = S ^ index.into(); +// | - ^^^^ +// | | +// | type must be known at this point +// | +// = note: cannot satisfy `>::Output == _` +// help: try using a fully qualified path to specify the expected types +// | +// 42 - let iv = S ^ index.into(); +// 42 + let iv = S ^ <::I as Into>::into(index); +// +// this is better as it's actually sufficent to fix the problem, +// while just specifying the type of iv as currently suggested is insufficent +// //@ check-fail use std::ops::BitXor; From aeab2819f650d180eb0e7238ff8a0733af70b3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 5 May 2025 20:49:09 +0200 Subject: [PATCH 261/302] Tweak index chunk allocation --- .../rustc_query_system/src/dep_graph/serialized.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 648823edb189..b5eda7b04a7f 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -572,14 +572,18 @@ impl EncoderState { #[inline] fn next_index(&self, local: &mut LocalEncoderState) -> DepNodeIndex { if local.remaining_node_index == 0 { - let count = 256; + const COUNT: u32 = 256; - // We assume that there won't be enough active threads to overflow u64 from u32::MAX here. - assert!(self.next_node_index.load(Ordering::Relaxed) <= u32::MAX as u64); + // We assume that there won't be enough active threads to overflow `u64` from `u32::MAX` here. + // This can exceed u32::MAX by at most `N` * `COUNT` where `N` is the thread pool count since + // `try_into().unwrap()` will make threads panic when `self.next_node_index` exceeds u32::MAX. local.next_node_index = - self.next_node_index.fetch_add(count, Ordering::Relaxed).try_into().unwrap(); + self.next_node_index.fetch_add(COUNT as u64, Ordering::Relaxed).try_into().unwrap(); - local.remaining_node_index = count as u32; + // Check that we'll stay within `u32` + local.next_node_index.checked_add(COUNT).unwrap(); + + local.remaining_node_index = COUNT; } DepNodeIndex::from_u32(local.next_node_index) From e1e8857d544b743419a8caddb7f4b5e0fb9610f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 5 May 2025 21:01:43 +0200 Subject: [PATCH 262/302] Add some comments about thread local indices --- compiler/rustc_query_system/src/dep_graph/serialized.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index b5eda7b04a7f..b01f65a5e454 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -12,7 +12,7 @@ //! node and edge count are stored at the end of the file, all the arrays can be //! pre-allocated with the right length. //! -//! The encoding of the de-pgraph is generally designed around the fact that fixed-size +//! The encoding of the dep-graph is generally designed around the fact that fixed-size //! reads of encoded data are generally faster than variable-sized reads. Ergo we adopt //! essentially the same varint encoding scheme used in the rmeta format; the edge lists //! for each node on the graph store a 2-bit integer which is the number of bytes per edge @@ -34,6 +34,10 @@ //! [`DepKind`], number of edges, and bytes per edge are all bit-packed together, if they fit. //! If the number of edges in this node does not fit in the bits available in the header, we //! store it directly after the header with leb128. +//! +//! Dep-graph indices are bulk allocated to threads inside `LocalEncoderState`. Having threads +//! own these indices helps avoid races when they are conditionally used when marking nodes green. +//! It also reduces congestion on the shared index count. use std::cell::RefCell; use std::cmp::max; From c0dfa44c485bb8a7a30f2b4b69827028b3d55c98 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 May 2025 17:19:23 +0000 Subject: [PATCH 263/302] Be a bit more relaxed about not yet constrained infer vars in closure upvar analysis --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 49 +++++++------------ tests/crashes/131758.rs | 11 ----- tests/ui/closures/opaque-upvar.rs | 19 +++++++ ...arg-constrained-after-closure-inference.rs | 16 ++++++ 4 files changed, 54 insertions(+), 41 deletions(-) delete mode 100644 tests/crashes/131758.rs create mode 100644 tests/ui/closures/opaque-upvar.rs create mode 100644 tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 17e13ec0a376..3493d359028d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -158,7 +158,7 @@ pub trait TypeInformationCtxt<'tcx> { fn resolve_vars_if_possible>>(&self, t: T) -> T; - fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; + fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error; @@ -191,8 +191,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.infcx.resolve_vars_if_possible(t) } - fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - (**self).try_structurally_resolve_type(sp, ty) + fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + (**self).structurally_resolve_type(sp, ty) } fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error { @@ -236,7 +236,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { self.0.maybe_typeck_results().expect("expected typeck results") } - fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { // FIXME: Maybe need to normalize here. ty } @@ -776,7 +776,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // Select just those fields of the `with` // expression that will actually be used - match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() { + match self.cx.structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() { ty::Adt(adt, args) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() { @@ -1176,7 +1176,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// two operations: a dereference to reach the array data and then an index to /// jump forward to the relevant item. impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { - fn resolve_type_vars_or_bug( + fn expect_and_resolve_type( &self, id: HirId, ty: Option>, @@ -1185,12 +1185,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Some(ty) => { let ty = self.cx.resolve_vars_if_possible(ty); self.cx.error_reported_in_ty(ty)?; - if ty.is_ty_var() { - debug!("resolve_type_vars_or_bug: infer var from {:?}", ty); - Err(self.cx.report_bug(self.cx.tcx().hir_span(id), "encountered type variable")) - } else { - Ok(ty) - } + Ok(ty) } None => { // FIXME: We shouldn't be relying on the infcx being tainted. @@ -1201,15 +1196,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } fn node_ty(&self, hir_id: HirId) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) + self.expect_and_resolve_type(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) } fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) + self.expect_and_resolve_type(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) } fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug( + self.expect_and_resolve_type( expr.hir_id, self.cx.typeck_results().expr_ty_adjusted_opt(expr), ) @@ -1264,10 +1259,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. - match self - .cx - .try_structurally_resolve_type(pat.span, base_ty) - .builtin_deref(false) + match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false) { Some(ty) => Ok(ty), None => { @@ -1513,10 +1505,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx if node_ty != place_ty && self .cx - .try_structurally_resolve_type( - self.cx.tcx().hir_span(base_place.hir_id), - place_ty, - ) + .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty) .is_impl_trait() { projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); @@ -1538,7 +1527,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let base_ty = self.expr_ty_adjusted(base)?; let ty::Ref(region, _, mutbl) = - *self.cx.try_structurally_resolve_type(base.span, base_ty).kind() + *self.cx.structurally_resolve_type(base.span, base_ty).kind() else { span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); }; @@ -1556,7 +1545,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let base_curr_ty = base_place.place.ty(); let deref_ty = match self .cx - .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) + .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) .builtin_deref(true) { Some(ty) => ty, @@ -1584,7 +1573,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ) -> Result { let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id); - let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { + let ty::Adt(adt_def, _) = self.cx.structurally_resolve_type(span, ty).kind() else { return Err(self .cx .report_bug(span, "struct or tuple struct pattern not applied to an ADT")); @@ -1616,7 +1605,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx span: Span, ) -> Result { let ty = self.cx.typeck_results().node_type(pat_hir_id); - match self.cx.try_structurally_resolve_type(span, ty).kind() { + match self.cx.structurally_resolve_type(span, ty).kind() { ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()), _ => { self.cx @@ -1631,7 +1620,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// Here `pat_hir_id` is the HirId of the pattern itself. fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result { let ty = self.cx.typeck_results().node_type(pat_hir_id); - match self.cx.try_structurally_resolve_type(span, ty).kind() { + match self.cx.structurally_resolve_type(span, ty).kind() { ty::Tuple(args) => Ok(args.len()), _ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")), } @@ -1820,7 +1809,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx PatKind::Slice(before, ref slice, after) => { let Some(element_ty) = self .cx - .try_structurally_resolve_type(pat.span, place_with_id.place.ty()) + .structurally_resolve_type(pat.span, place_with_id.place.ty()) .builtin_index() else { debug!("explicit index of non-indexable type {:?}", place_with_id); @@ -1890,7 +1879,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { - if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() { + if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need // to assume that more cases will be added to the variant in the future. This mean // that we should handle non-exhaustive SingleVariant the same way we would handle diff --git a/tests/crashes/131758.rs b/tests/crashes/131758.rs deleted file mode 100644 index 942c5fd7a502..000000000000 --- a/tests/crashes/131758.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #131758 -#![feature(unboxed_closures)] -trait Foo {} - -impl> Foo for T {} - -fn baz(_: T) {} - -fn main() { - baz(|x| ()); -} diff --git a/tests/ui/closures/opaque-upvar.rs b/tests/ui/closures/opaque-upvar.rs new file mode 100644 index 000000000000..90e7c9ccb465 --- /dev/null +++ b/tests/ui/closures/opaque-upvar.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// This is only an issue in the new solver, but I'm testing it in both solvers for now. +// This has to do with the fact that the recursive `walk_dir` is a revealing use, which has not +// yet been constrained from the defining use by the time that closure signature inference is +// performed. We don't really care, though, since anywhere we structurally match on a type in +// upvar analysis, we already call `structurally_resolve_type` right before `.kind()`. + +fn walk_dir(cb: &()) -> impl Sized { + || { + let fut = walk_dir(cb); + }; +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs b/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs new file mode 100644 index 000000000000..343a27616d1d --- /dev/null +++ b/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs @@ -0,0 +1,16 @@ +#![feature(unboxed_closures)] + +//@ check-pass + +// Regression test for #131758. We only know the type of `x` after closure upvar +// inference is done, even if we don't need to structurally resolve the type of `x`. + +trait Foo {} + +impl> Foo for T {} + +fn baz(_: T) {} + +fn main() { + baz(|x| ()); +} From fb8784585eece42a22c782bb01c1c2f188f70505 Mon Sep 17 00:00:00 2001 From: Skgland Date: Mon, 5 May 2025 21:09:31 +0200 Subject: [PATCH 264/302] fix tidy and bless test --- tests/ui/type-inference/regression-issue-81317.rs | 12 +++++++----- .../ui/type-inference/regression-issue-81317.stderr | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/ui/type-inference/regression-issue-81317.rs b/tests/ui/type-inference/regression-issue-81317.rs index 39c91948426b..0b1266e6a0fd 100644 --- a/tests/ui/type-inference/regression-issue-81317.rs +++ b/tests/ui/type-inference/regression-issue-81317.rs @@ -1,6 +1,7 @@ // Regression test for #81317: type can no longer be infered as of 1.49 // -// The problem is that the xor operator and the index.into() each have two candidate impls that could apply +// The problem is that the xor operator and the index.into() call +// each have two candidate impls that could apply // { S as BitXor, S as BitXor<&'a S> } for xor and // { T::I as Into, T::I as Into } for index.into() // previously inference was able to infer that the only valid combination was @@ -8,13 +9,14 @@ // // after rust-lang/rust#73905 this is no longer infered // -// the error message could be better e.g. when iv is unused or has an an explicitly specified type S +// the error message could be better e.g. +// when iv is unused or has an an explicitly specified type S // there is currently the following help message // // error[E0284]: type annotations needed // --> src/main.rs:13:24 // | -// 42 | let iv = S ^ index.into(); +// 44 | let iv = S ^ index.into(); // | - ^^^^ // | | // | type must be known at this point @@ -22,8 +24,8 @@ // = note: cannot satisfy `>::Output == _` // help: try using a fully qualified path to specify the expected types // | -// 42 - let iv = S ^ index.into(); -// 42 + let iv = S ^ <::I as Into>::into(index); +// 44 - let iv = S ^ index.into(); +// 44 + let iv = S ^ <::I as Into>::into(index); // // this is better as it's actually sufficent to fix the problem, // while just specifying the type of iv as currently suggested is insufficent diff --git a/tests/ui/type-inference/regression-issue-81317.stderr b/tests/ui/type-inference/regression-issue-81317.stderr index d018a2c48545..fcd3fca06e18 100644 --- a/tests/ui/type-inference/regression-issue-81317.stderr +++ b/tests/ui/type-inference/regression-issue-81317.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/regression-issue-81317.rs:13:9 + --> $DIR/regression-issue-81317.rs:44:9 | LL | let iv = S ^ index.into(); | ^^ From 292aea50d876af5ca77d3c0233c836ff240d3bca Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 5 May 2025 15:13:40 -0700 Subject: [PATCH 265/302] Update mdbook to 0.4.49 This is a routine update to pull in some fixes and updates. Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-0449 --- src/tools/rustbook/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 81e0f6d572be..3b5b31bed14a 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -938,9 +938,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.48" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1" +checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index a0b220c3557d..10fde31306df 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.48" +version = "0.4.49" default-features = false features = ["search"] From a3d5562fcf7f67491d55588ac3279bfade9dadcd Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 22 Apr 2025 16:30:48 +1000 Subject: [PATCH 266/302] bootstrap: Add check/test/run steps for src/tools/coverage-dump This also causes the coverage-dump unit tests to run in CI and `./x test` by default. --- src/bootstrap/src/core/build_steps/check.rs | 67 +++++++++++++++++++++ src/bootstrap/src/core/build_steps/run.rs | 28 +++++++++ src/bootstrap/src/core/build_steps/test.rs | 1 + src/bootstrap/src/core/builder/mod.rs | 2 + src/tools/coverage-dump/src/parser/tests.rs | 4 -- 5 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index ae9511b78674..fa848c492b4d 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -527,3 +527,70 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false }); + +/// Check step for the `coverage-dump` bootstrap tool. The coverage-dump tool +/// is used internally by coverage tests. +/// +/// FIXME(Zalathar): This is temporarily separate from the other tool check +/// steps so that it can use the stage 0 compiler instead of `top_stage`, +/// without introducing conflicts with the stage 0 redesign (#119899). +/// +/// After the stage 0 redesign lands, we can look into using the stage 0 +/// compiler to check all bootstrap tools (#139170). +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct CoverageDump; + +impl CoverageDump { + const PATH: &str = "src/tools/coverage-dump"; +} + +impl Step for CoverageDump { + type Output = (); + + /// Most contributors won't care about coverage-dump, so don't make their + /// check builds slower unless they opt in and check it explicitly. + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path(Self::PATH) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self {}); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // Make sure we haven't forgotten any fields, if there are any. + let Self {} = self; + let display_name = "coverage-dump"; + let host = builder.config.build; + let target = host; + let mode = Mode::ToolBootstrap; + + let compiler = builder.compiler(0, host); + let cargo = prepare_tool_cargo( + builder, + compiler, + mode, + target, + builder.kind, + Self::PATH, + SourceType::InTree, + &[], + ); + + let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target)) + .with_prefix(&format!("{display_name}-check")); + + let _guard = builder.msg_tool( + builder.kind, + mode, + display_name, + compiler.stage, + &compiler.host, + &target, + ); + run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + } +} diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 5cacd5b99147..7ff385052940 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -392,3 +392,31 @@ impl Step for CyclicStep { builder.ensure(CyclicStep { n: self.n.saturating_sub(1) }) } } + +/// Step to manually run the coverage-dump tool (`./x run coverage-dump`). +/// +/// The coverage-dump tool is an internal detail of coverage tests, so this run +/// step is only needed when testing coverage-dump manually. +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] +pub struct CoverageDump; + +impl Step for CoverageDump { + type Output = (); + + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/coverage-dump") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self {}); + } + + fn run(self, builder: &Builder<'_>) { + let mut cmd = builder.tool_cmd(Tool::CoverageDump); + cmd.args(&builder.config.free_args); + cmd.run(builder); + } +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a7a3b5a878c3..29fb576f5740 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -54,6 +54,7 @@ impl Step for CrateBootstrap { run.path("src/tools/jsondoclint") .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") + .path("src/tools/coverage-dump") // We want `./x test tidy` to _run_ the tidy tool, not its tests. // So we need a separate alias to test the tidy tool itself. .alias("tidyselftest") diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 6469bb5f2722..15dc3380a39a 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -961,6 +961,7 @@ impl<'a> Builder<'a> { check::RunMakeSupport, check::Compiletest, check::FeaturesStatusDump, + check::CoverageDump, ), Kind::Test => describe!( crate::core::build_steps::toolstate::ToolStateCheck, @@ -1114,6 +1115,7 @@ impl<'a> Builder<'a> { run::UnicodeTableGenerator, run::FeaturesStatusDump, run::CyclicStep, + run::CoverageDump, ), Kind::Setup => { describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) diff --git a/src/tools/coverage-dump/src/parser/tests.rs b/src/tools/coverage-dump/src/parser/tests.rs index a673606b9c4c..506b0a6200bb 100644 --- a/src/tools/coverage-dump/src/parser/tests.rs +++ b/src/tools/coverage-dump/src/parser/tests.rs @@ -1,9 +1,5 @@ use super::unescape_llvm_string_contents; -// WARNING: These tests don't necessarily run in CI, and were mainly used to -// help track down problems when originally developing this tool. -// (The tool is still tested indirectly by snapshot tests that rely on it.) - // Tests for `unescape_llvm_string_contents`: #[test] From 89319f2e128379a96943de2be347ec09a80abca4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 23 Apr 2025 17:36:01 +1000 Subject: [PATCH 267/302] coverage-dump: Extract some common code to an `llvm_utils` submodule --- src/tools/coverage-dump/src/covfun.rs | 3 +- src/tools/coverage-dump/src/llvm_utils.rs | 46 +++++++++++++++++++ .../src/{parser => llvm_utils}/tests.rs | 0 src/tools/coverage-dump/src/main.rs | 1 + src/tools/coverage-dump/src/parser.rs | 34 -------------- src/tools/coverage-dump/src/prf_names.rs | 15 +----- 6 files changed, 51 insertions(+), 48 deletions(-) create mode 100644 src/tools/coverage-dump/src/llvm_utils.rs rename src/tools/coverage-dump/src/{parser => llvm_utils}/tests.rs (100%) diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 82ebd33d0d1c..458fd680429a 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -5,7 +5,8 @@ use std::sync::OnceLock; use anyhow::{Context, anyhow}; use regex::Regex; -use crate::parser::{Parser, unescape_llvm_string_contents}; +use crate::llvm_utils::unescape_llvm_string_contents; +use crate::parser::Parser; pub(crate) fn dump_covfun_mappings( llvm_ir: &str, diff --git a/src/tools/coverage-dump/src/llvm_utils.rs b/src/tools/coverage-dump/src/llvm_utils.rs new file mode 100644 index 000000000000..017fdbec0fc2 --- /dev/null +++ b/src/tools/coverage-dump/src/llvm_utils.rs @@ -0,0 +1,46 @@ +use std::sync::OnceLock; + +use regex::bytes; + +#[cfg(test)] +mod tests; + +/// Given the raw contents of a string literal in LLVM IR assembly, decodes any +/// backslash escapes and returns a vector containing the resulting byte string. +pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec { + let escape_re = { + static RE: OnceLock = OnceLock::new(); + // LLVM IR supports two string escapes: `\\` and `\xx`. + RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap()) + }; + + fn u8_from_hex_digits(digits: &[u8]) -> u8 { + // We know that the input contains exactly 2 hex digits, so these calls + // should never fail. + assert_eq!(digits.len(), 2); + let digits = std::str::from_utf8(digits).unwrap(); + u8::from_str_radix(digits, 16).unwrap() + } + + escape_re + .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| { + let byte = match captures.get(1) { + None => b'\\', + Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()), + }; + [byte] + }) + .into_owned() +} + +/// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to +/// 64 bits as a way to associate data stored in different tables/sections. +pub(crate) fn truncated_md5(bytes: &[u8]) -> u64 { + use md5::{Digest, Md5}; + let mut hasher = Md5::new(); + hasher.update(bytes); + let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap(); + // The truncated hash is explicitly little-endian, regardless of host + // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) + u64::from_le_bytes(hash) +} diff --git a/src/tools/coverage-dump/src/parser/tests.rs b/src/tools/coverage-dump/src/llvm_utils/tests.rs similarity index 100% rename from src/tools/coverage-dump/src/parser/tests.rs rename to src/tools/coverage-dump/src/llvm_utils/tests.rs diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs index b21e3e292f2b..6408b97a06fd 100644 --- a/src/tools/coverage-dump/src/main.rs +++ b/src/tools/coverage-dump/src/main.rs @@ -1,4 +1,5 @@ mod covfun; +mod llvm_utils; mod parser; mod prf_names; diff --git a/src/tools/coverage-dump/src/parser.rs b/src/tools/coverage-dump/src/parser.rs index 0bd4abdae3ef..f26a57b43b33 100644 --- a/src/tools/coverage-dump/src/parser.rs +++ b/src/tools/coverage-dump/src/parser.rs @@ -1,38 +1,4 @@ -#[cfg(test)] -mod tests; - -use std::sync::OnceLock; - use anyhow::ensure; -use regex::bytes; - -/// Given the raw contents of a string literal in LLVM IR assembly, decodes any -/// backslash escapes and returns a vector containing the resulting byte string. -pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec { - let escape_re = { - static RE: OnceLock = OnceLock::new(); - // LLVM IR supports two string escapes: `\\` and `\xx`. - RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap()) - }; - - fn u8_from_hex_digits(digits: &[u8]) -> u8 { - // We know that the input contains exactly 2 hex digits, so these calls - // should never fail. - assert_eq!(digits.len(), 2); - let digits = std::str::from_utf8(digits).unwrap(); - u8::from_str_radix(digits, 16).unwrap() - } - - escape_re - .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| { - let byte = match captures.get(1) { - None => b'\\', - Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()), - }; - [byte] - }) - .into_owned() -} pub(crate) struct Parser<'a> { rest: &'a [u8], diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs index 96d097c79a31..fe193efd8e5f 100644 --- a/src/tools/coverage-dump/src/prf_names.rs +++ b/src/tools/coverage-dump/src/prf_names.rs @@ -4,7 +4,8 @@ use std::sync::OnceLock; use anyhow::{anyhow, ensure}; use regex::Regex; -use crate::parser::{Parser, unescape_llvm_string_contents}; +use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents}; +use crate::parser::Parser; /// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names` /// entries, decodes them, and creates a table that maps name hash values to @@ -25,18 +26,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result u64 { - use md5::{Digest, Md5}; - let mut hasher = Md5::new(); - hasher.update(bytes); - let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap(); - // The truncated hash is explicitly little-endian, regardless of host - // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) - u64::from_le_bytes(hash) - } - fn demangle_if_able(symbol_name_bytes: &[u8]) -> anyhow::Result { // In practice, raw symbol names should always be ASCII. let symbol_name_str = std::str::from_utf8(symbol_name_bytes)?; From bc3f0e326a5ef77bb4e3531db5190109d8e2420b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 23 Apr 2025 17:47:01 +1000 Subject: [PATCH 268/302] coverage-dump: Extract a common parser method for maybe-compressed bytes --- src/tools/coverage-dump/src/llvm_utils.rs | 39 +++++++++++++++++++++++ src/tools/coverage-dump/src/prf_names.rs | 25 ++------------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/tools/coverage-dump/src/llvm_utils.rs b/src/tools/coverage-dump/src/llvm_utils.rs index 017fdbec0fc2..92322b256a82 100644 --- a/src/tools/coverage-dump/src/llvm_utils.rs +++ b/src/tools/coverage-dump/src/llvm_utils.rs @@ -1,7 +1,11 @@ +use std::borrow::Cow; use std::sync::OnceLock; +use anyhow::{anyhow, ensure}; use regex::bytes; +use crate::parser::Parser; + #[cfg(test)] mod tests; @@ -44,3 +48,38 @@ pub(crate) fn truncated_md5(bytes: &[u8]) -> u64 { // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) u64::from_le_bytes(hash) } + +impl<'a> Parser<'a> { + /// Reads a sequence of: + /// - Length of uncompressed data in bytes, as ULEB128 + /// - Length of compressed data in bytes (or 0), as ULEB128 + /// - The indicated number of compressed or uncompressed bytes + /// + /// If the number of compressed bytes is 0, the subsequent bytes are + /// uncompressed. Otherwise, the subsequent bytes are compressed, and will + /// be decompressed. + /// + /// Returns the uncompressed bytes that were read directly or decompressed. + pub(crate) fn read_chunk_to_uncompressed_bytes(&mut self) -> anyhow::Result> { + let uncompressed_len = self.read_uleb128_usize()?; + let compressed_len = self.read_uleb128_usize()?; + + if compressed_len == 0 { + // The bytes are uncompressed, so read them directly. + let uncompressed_bytes = self.read_n_bytes(uncompressed_len)?; + Ok(Cow::Borrowed(uncompressed_bytes)) + } else { + // The bytes are compressed, so read and decompress them. + let compressed_bytes = self.read_n_bytes(compressed_len)?; + + let uncompressed_bytes = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit( + compressed_bytes, + uncompressed_len, + ) + .map_err(|e| anyhow!("{e:?}"))?; + ensure!(uncompressed_bytes.len() == uncompressed_len); + + Ok(Cow::Owned(uncompressed_bytes)) + } + } +} diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs index fe193efd8e5f..f9ab35deba50 100644 --- a/src/tools/coverage-dump/src/prf_names.rs +++ b/src/tools/coverage-dump/src/prf_names.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::sync::OnceLock; -use anyhow::{anyhow, ensure}; use regex::Regex; use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents}; @@ -43,26 +42,8 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result anyhow::Result Date: Tue, 22 Apr 2025 21:49:57 +1000 Subject: [PATCH 269/302] coverage-dump: Include filenames hash in covfun line data --- Cargo.lock | 1 + src/tools/coverage-dump/Cargo.toml | 1 + src/tools/coverage-dump/src/covfun.rs | 73 +++++++++++++-------- src/tools/coverage-dump/src/covfun/tests.rs | 53 +++++++++++++++ 4 files changed, 102 insertions(+), 26 deletions(-) create mode 100644 src/tools/coverage-dump/src/covfun/tests.rs diff --git a/Cargo.lock b/Cargo.lock index bbd3f33d7bd3..b5fc86f50fe4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -777,6 +777,7 @@ name = "coverage-dump" version = "0.1.0" dependencies = [ "anyhow", + "itertools", "leb128", "md-5", "miniz_oxide 0.7.4", diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index 7f14286b5d0c..6f92ac50d963 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.71" +itertools = "0.12" leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.7.1" diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 458fd680429a..4c0ce2058225 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -1,13 +1,17 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Write as _}; -use std::sync::OnceLock; +use std::sync::LazyLock; -use anyhow::{Context, anyhow}; +use anyhow::{Context, anyhow, ensure}; +use itertools::Itertools; use regex::Regex; use crate::llvm_utils::unescape_llvm_string_contents; use crate::parser::Parser; +#[cfg(test)] +mod tests; + pub(crate) fn dump_covfun_mappings( llvm_ir: &str, function_names: &HashMap, @@ -16,9 +20,12 @@ pub(crate) fn dump_covfun_mappings( // each entry with its (demangled) name. let mut covfun_entries = llvm_ir .lines() - .filter_map(covfun_line_data) - .map(|line_data| (function_names.get(&line_data.name_hash).map(String::as_str), line_data)) - .collect::>(); + .filter(|line| is_covfun_line(line)) + .map(parse_covfun_line) + .map_ok(|line_data| { + (function_names.get(&line_data.name_hash).map(String::as_str), line_data) + }) + .collect::, _>>()?; covfun_entries.sort_by(|a, b| { // Sort entries primarily by name, to help make the order consistent // across platforms and relatively insensitive to changes. @@ -108,36 +115,50 @@ pub(crate) fn dump_covfun_mappings( Ok(()) } +#[derive(Debug, PartialEq, Eq)] struct CovfunLineData { - name_hash: u64, is_used: bool, + name_hash: u64, + filenames_hash: u64, payload: Vec, } -/// Checks a line of LLVM IR assembly to see if it contains an `__llvm_covfun` -/// entry, and if so extracts relevant data in a `CovfunLineData`. -fn covfun_line_data(line: &str) -> Option { - let re = { - // We cheat a little bit and match variable names `@__covrec_[HASH]u` - // rather than the section name, because the section name is harder to - // extract and differs across Linux/Windows/macOS. We also extract the - // symbol name hash from the variable name rather than the data, since - // it's easier and both should match. - static RE: OnceLock = OnceLock::new(); - RE.get_or_init(|| { - Regex::new( - r#"^@__covrec_(?[0-9A-Z]+)(?u)? = .*\[[0-9]+ x i8\] c"(?[^"]*)".*$"#, - ) - .unwrap() - }) - }; +fn is_covfun_line(line: &str) -> bool { + line.starts_with("@__covrec_") +} - let captures = re.captures(line)?; - let name_hash = u64::from_str_radix(&captures["name_hash"], 16).unwrap(); +/// Given a line of LLVM IR assembly that should contain an `__llvm_covfun` +/// entry, parses it to extract relevant data in a `CovfunLineData`. +fn parse_covfun_line(line: &str) -> anyhow::Result { + ensure!(is_covfun_line(line)); + + // We cheat a little bit and match variable names `@__covrec_[HASH]u` + // rather than the section name, because the section name is harder to + // extract and differs across Linux/Windows/macOS. + const RE_STRING: &str = r#"(?x)^ + @__covrec_[0-9A-Z]+(?u)? + \ = \ # (trailing space) + .* + <\{ + \ i64 \ (? -? [0-9]+), + \ i32 \ -? [0-9]+, # (length of payload; currently unused) + \ i64 \ -? [0-9]+, # (source hash; currently unused) + \ i64 \ (? -? [0-9]+), + \ \[ [0-9]+ \ x \ i8 \] \ c"(?[^"]*)" + \ # (trailing space) + }> + .*$ + "#; + static RE: LazyLock = LazyLock::new(|| Regex::new(RE_STRING).unwrap()); + + let captures = + RE.captures(line).with_context(|| format!("couldn't parse covfun line: {line:?}"))?; let is_used = captures.name("is_used").is_some(); + let name_hash = i64::from_str_radix(&captures["name_hash"], 10).unwrap() as u64; + let filenames_hash = i64::from_str_radix(&captures["filenames_hash"], 10).unwrap() as u64; let payload = unescape_llvm_string_contents(&captures["payload"]); - Some(CovfunLineData { name_hash, is_used, payload }) + Ok(CovfunLineData { is_used, name_hash, filenames_hash, payload }) } // Extra parser methods only needed when parsing `covfun` payloads. diff --git a/src/tools/coverage-dump/src/covfun/tests.rs b/src/tools/coverage-dump/src/covfun/tests.rs new file mode 100644 index 000000000000..1ce833784bd4 --- /dev/null +++ b/src/tools/coverage-dump/src/covfun/tests.rs @@ -0,0 +1,53 @@ +use super::{CovfunLineData, parse_covfun_line}; + +/// Integers in LLVM IR are not inherently signed/unsigned, and the text format tends +/// to emit them in signed form, so this helper function converts `i64` to `u64`. +fn as_u64(x: i64) -> u64 { + x as u64 +} + +#[test] +fn parse_covfun_line_data() { + struct Case { + line: &'static str, + expected: CovfunLineData, + } + let cases = &[ + // Copied from `trivial.ll`: + Case { + line: r#"@__covrec_49A9BAAE5F896E81u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 5307978893922758273, i32 9, i64 445092354169400020, i64 6343436898695299756, [9 x i8] c"\01\01\00\01\01\03\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(5307978893922758273), + filenames_hash: as_u64(6343436898695299756), + payload: b"\x01\x01\x00\x01\x01\x03\x01\x00\x0D".to_vec(), + }, + }, + // Copied from `on-off-sandwich.ll`: + Case { + line: r#"@__covrec_D0CE53C5E64F319Au = linkonce_odr hidden constant <{ i64, i32, i64, i64, [14 x i8] }> <{ i64 -3400688559180533350, i32 14, i64 7307957714577672185, i64 892196767019953100, [14 x i8] c"\01\01\00\02\01\10\05\02\10\01\07\05\00\06" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(-3400688559180533350), + filenames_hash: as_u64(892196767019953100), + payload: b"\x01\x01\x00\x02\x01\x10\x05\x02\x10\x01\x07\x05\x00\x06".to_vec(), + }, + }, + // Copied from `no-core.ll`: + Case { + line: r#"@__covrec_F8016FC82D46106u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 1116917981370409222, i32 9, i64 -8857254680411629915, i64 -3625186110715410276, [9 x i8] c"\01\01\00\01\01\0C\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(1116917981370409222), + filenames_hash: as_u64(-3625186110715410276), + payload: b"\x01\x01\x00\x01\x01\x0C\x01\x00\x0D".to_vec(), + }, + }, + ]; + + for &Case { line, ref expected } in cases { + println!("- {line}"); + let line_data = parse_covfun_line(line).map_err(|e| e.to_string()); + assert_eq!(line_data.as_ref(), Ok(expected)); + } +} From 041b2b2c982edb6e36a7d80081d040dbaf388a2b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 24 Apr 2025 13:47:13 +1000 Subject: [PATCH 270/302] coverage-dump: Make filenames available to covfun record dumping Actually printing the filenames is deferred to a subsequent commit that will simultaneously bless all affected tests. --- src/tools/coverage-dump/src/covfun.rs | 11 +++- src/tools/coverage-dump/src/covmap.rs | 75 +++++++++++++++++++++++++++ src/tools/coverage-dump/src/main.rs | 4 +- 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 src/tools/coverage-dump/src/covmap.rs diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 4c0ce2058225..d3744d3bf807 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -2,10 +2,11 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Write as _}; use std::sync::LazyLock; -use anyhow::{Context, anyhow, ensure}; +use anyhow::{Context, anyhow, bail, ensure}; use itertools::Itertools; use regex::Regex; +use crate::covmap::FilenameTables; use crate::llvm_utils::unescape_llvm_string_contents; use crate::parser::Parser; @@ -14,6 +15,7 @@ mod tests; pub(crate) fn dump_covfun_mappings( llvm_ir: &str, + filename_tables: &FilenameTables, function_names: &HashMap, ) -> anyhow::Result<()> { // Extract function coverage entries from the LLVM IR assembly, and associate @@ -49,7 +51,12 @@ pub(crate) fn dump_covfun_mappings( println!("Number of files: {num_files}"); for i in 0..num_files { - let global_file_id = parser.read_uleb128_u32()?; + let global_file_id = parser.read_uleb128_usize()?; + let &CovfunLineData { filenames_hash, .. } = line_data; + #[expect(unused)] // Removed later in this PR. + let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else { + bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}"); + }; println!("- file {i} => global file {global_file_id}"); } diff --git a/src/tools/coverage-dump/src/covmap.rs b/src/tools/coverage-dump/src/covmap.rs new file mode 100644 index 000000000000..2246ca2d5757 --- /dev/null +++ b/src/tools/coverage-dump/src/covmap.rs @@ -0,0 +1,75 @@ +use std::collections::HashMap; +use std::sync::LazyLock; + +use anyhow::{Context, ensure}; +use regex::Regex; + +use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents}; +use crate::parser::Parser; + +#[derive(Debug, Default)] +pub(crate) struct FilenameTables { + map: HashMap>, +} + +impl FilenameTables { + pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> { + let table = self.map.get(&filenames_hash)?; + let filename = table.get(global_file_id)?; + Some(filename) + } +} + +struct CovmapLineData { + payload: Vec, +} + +pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result { + let mut map = HashMap::default(); + + for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) { + let CovmapLineData { payload } = parse_covmap_line(line)?; + + let mut parser = Parser::new(&payload); + let n_filenames = parser.read_uleb128_usize()?; + let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?; + parser.ensure_empty()?; + + let mut filenames_table = vec![]; + + let mut parser = Parser::new(&uncompressed_bytes); + for _ in 0..n_filenames { + let len = parser.read_uleb128_usize()?; + let bytes = parser.read_n_bytes(len)?; + let filename = str::from_utf8(bytes)?; + filenames_table.push(filename.to_owned()); + } + + let filenames_hash = truncated_md5(&payload); + map.insert(filenames_hash, filenames_table); + } + + Ok(FilenameTables { map }) +} + +fn is_covmap_line(line: &str) -> bool { + line.starts_with("@__llvm_coverage_mapping ") +} + +fn parse_covmap_line(line: &str) -> anyhow::Result { + ensure!(is_covmap_line(line)); + + const RE_STRING: &str = r#"(?x)^ + @__llvm_coverage_mapping \ = + .* + \[ [0-9]+ \ x \ i8 \] \ c"(?[^"]*)" + .*$ + "#; + static RE: LazyLock = LazyLock::new(|| Regex::new(RE_STRING).unwrap()); + + let captures = + RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?; + let payload = unescape_llvm_string_contents(&captures["payload"]); + + Ok(CovmapLineData { payload }) +} diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs index 6408b97a06fd..2c76d2f24602 100644 --- a/src/tools/coverage-dump/src/main.rs +++ b/src/tools/coverage-dump/src/main.rs @@ -1,4 +1,5 @@ mod covfun; +mod covmap; mod llvm_utils; mod parser; mod prf_names; @@ -18,8 +19,9 @@ fn main() -> anyhow::Result<()> { let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?; let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?; + let filename_tables = covmap::make_filename_tables(&llvm_ir)?; let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?; - crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?; + crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?; Ok(()) } From c53a76743c01afa356ae5301bc1b35044354da7a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 24 Apr 2025 17:36:50 +1000 Subject: [PATCH 271/302] coverage-dump: Dump filenames instead of global file IDs (and bless) --- src/tools/coverage-dump/src/covfun.rs | 3 +- tests/coverage/abort.cov-map | 4 +- tests/coverage/assert-ne.cov-map | 2 +- tests/coverage/assert.cov-map | 4 +- tests/coverage/assert_not.cov-map | 2 +- tests/coverage/async.cov-map | 50 +++++++++---------- tests/coverage/async2.cov-map | 12 ++--- tests/coverage/async_block.cov-map | 4 +- tests/coverage/async_closure.cov-map | 12 ++--- tests/coverage/attr/impl.cov-map | 6 +-- tests/coverage/attr/module.cov-map | 6 +-- tests/coverage/attr/nested.cov-map | 4 +- tests/coverage/attr/off-on-sandwich.cov-map | 6 +-- .../coverage/attr/trait-impl-inherit.cov-map | 2 +- tests/coverage/await_ready.cov-map | 4 +- tests/coverage/bad_counter_ids.cov-map | 16 +++--- tests/coverage/bench.cov-map | 2 +- tests/coverage/branch/generics.cov-map | 6 +-- tests/coverage/branch/guard.cov-map | 2 +- tests/coverage/branch/if-let.cov-map | 4 +- tests/coverage/branch/if.cov-map | 8 +-- tests/coverage/branch/lazy-boolean.cov-map | 8 +-- tests/coverage/branch/let-else.cov-map | 2 +- tests/coverage/branch/match-arms.cov-map | 6 +-- tests/coverage/branch/match-trivial.cov-map | 4 +- tests/coverage/branch/no-mir-spans.cov-map | 8 +-- tests/coverage/branch/while.cov-map | 8 +-- tests/coverage/closure.cov-map | 42 ++++++++-------- tests/coverage/closure_bug.cov-map | 10 ++-- tests/coverage/closure_macro.cov-map | 6 +-- tests/coverage/closure_macro_async.cov-map | 8 +-- tests/coverage/closure_unit_return.cov-map | 8 +-- tests/coverage/condition/conditions.cov-map | 14 +++--- tests/coverage/conditions.cov-map | 2 +- tests/coverage/continue.cov-map | 2 +- tests/coverage/coroutine.cov-map | 6 +-- tests/coverage/coverage_attr_closure.cov-map | 8 +-- tests/coverage/dead_code.cov-map | 6 +-- tests/coverage/drop_trait.cov-map | 4 +- tests/coverage/fn_sig_into_try.cov-map | 8 +-- tests/coverage/generic-unused-impl.cov-map | 4 +- tests/coverage/generics.cov-map | 10 ++-- tests/coverage/holes.cov-map | 10 ++-- tests/coverage/if.cov-map | 2 +- tests/coverage/if_else.cov-map | 2 +- tests/coverage/if_not.cov-map | 2 +- tests/coverage/ignore_run.cov-map | 2 +- tests/coverage/inline-dead.cov-map | 8 +-- tests/coverage/inline.cov-map | 14 +++--- tests/coverage/inner_items.cov-map | 8 +-- tests/coverage/issue-83601.cov-map | 2 +- tests/coverage/issue-84561.cov-map | 12 ++--- tests/coverage/issue-85461.cov-map | 2 +- tests/coverage/issue-93054.cov-map | 6 +-- tests/coverage/lazy_boolean.cov-map | 2 +- tests/coverage/let_else_loop.cov-map | 6 +-- tests/coverage/long_and_wide.cov-map | 8 +-- tests/coverage/loop-break.cov-map | 2 +- tests/coverage/loop_break_value.cov-map | 2 +- tests/coverage/loops_branches.cov-map | 6 +-- tests/coverage/macro_in_closure.cov-map | 4 +- tests/coverage/macro_name_span.cov-map | 4 +- tests/coverage/match_or_pattern.cov-map | 2 +- tests/coverage/mcdc/condition-limit.cov-map | 2 +- tests/coverage/mcdc/if.cov-map | 14 +++--- .../coverage/mcdc/inlined_expressions.cov-map | 2 +- tests/coverage/mcdc/nested_if.cov-map | 8 +-- tests/coverage/mcdc/non_control_flow.cov-map | 14 +++--- tests/coverage/nested_loops.cov-map | 2 +- tests/coverage/no-core.cov-map | 2 +- tests/coverage/no_cov_crate.cov-map | 14 +++--- tests/coverage/no_spans.cov-map | 4 +- tests/coverage/no_spans_if_not.cov-map | 4 +- tests/coverage/overflow.cov-map | 4 +- tests/coverage/panic_unwind.cov-map | 4 +- tests/coverage/partial_eq.cov-map | 4 +- tests/coverage/simple_loop.cov-map | 2 +- tests/coverage/simple_match.cov-map | 2 +- tests/coverage/sort_groups.cov-map | 12 ++--- tests/coverage/test_harness.cov-map | 4 +- tests/coverage/tight_inf_loop.cov-map | 2 +- tests/coverage/trivial.cov-map | 2 +- tests/coverage/try_error_result.cov-map | 12 ++--- tests/coverage/unicode.cov-map | 6 +-- tests/coverage/unreachable.cov-map | 6 +-- tests/coverage/unused.cov-map | 14 +++--- tests/coverage/unused_mod.cov-map | 4 +- tests/coverage/uses_crate.cov-map | 10 ++-- tests/coverage/uses_inline_crate.cov-map | 12 ++--- tests/coverage/while.cov-map | 2 +- tests/coverage/while_early_ret.cov-map | 2 +- tests/coverage/yield.cov-map | 6 +-- 92 files changed, 307 insertions(+), 308 deletions(-) diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index d3744d3bf807..1cc9f4dc5d6a 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -53,11 +53,10 @@ pub(crate) fn dump_covfun_mappings( for i in 0..num_files { let global_file_id = parser.read_uleb128_usize()?; let &CovfunLineData { filenames_hash, .. } = line_data; - #[expect(unused)] // Removed later in this PR. let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else { bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}"); }; - println!("- file {i} => global file {global_file_id}"); + println!("- file {i} => {filename}"); } let num_expressions = parser.read_uleb128_u32()?; diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 26536caeba52..4021537392b9 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,7 +1,7 @@ Function name: abort::main Raw bytes (83): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 0d, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/abort.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) @@ -36,7 +36,7 @@ Highest counter ID seen: c4 Function name: abort::might_abort Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/abort.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 diff --git a/tests/coverage/assert-ne.cov-map b/tests/coverage/assert-ne.cov-map index 27d4b0382dec..4bee7d7b97c7 100644 --- a/tests/coverage/assert-ne.cov-map +++ b/tests/coverage/assert-ne.cov-map @@ -1,7 +1,7 @@ Function name: assert_ne::main Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 15, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert-ne.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index 903cccfe9cbc..e7ee91979711 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -1,7 +1,7 @@ Function name: assert::main Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 09, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -28,7 +28,7 @@ Highest counter ID seen: c3 Function name: assert::might_fail_assert Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map index 3aef4274edc3..d3ef867a8a82 100644 --- a/tests/coverage/assert_not.cov-map +++ b/tests/coverage/assert_not.cov-map @@ -1,7 +1,7 @@ Function name: assert_not::main Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 11, 01, 02, 05, 00, 13, 01, 01, 05, 00, 13, 01, 01, 05, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert_not.rs Number of expressions: 0 Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 17) diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 521562f6b912..8d8dd2430571 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -1,7 +1,7 @@ Function name: async::c Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 1) to (start + 0, 25) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: async::c::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -24,7 +24,7 @@ Highest counter ID seen: c1 Function name: async::d Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 1) to (start + 0, 20) @@ -33,7 +33,7 @@ Highest counter ID seen: c0 Function name: async::d::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 20) to (start + 0, 25) @@ -42,7 +42,7 @@ Highest counter ID seen: c0 Function name: async::e (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 1) to (start + 0, 20) @@ -51,7 +51,7 @@ Highest counter ID seen: (none) Function name: async::e::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 20) to (start + 0, 25) @@ -60,7 +60,7 @@ Highest counter ID seen: (none) Function name: async::f Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 20) @@ -69,7 +69,7 @@ Highest counter ID seen: c0 Function name: async::f::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 20) to (start + 0, 25) @@ -78,7 +78,7 @@ Highest counter ID seen: c0 Function name: async::foo (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 1) to (start + 0, 30) @@ -87,7 +87,7 @@ Highest counter ID seen: (none) Function name: async::foo::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 1e, 00, 2d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 30) to (start + 0, 45) @@ -96,7 +96,7 @@ Highest counter ID seen: (none) Function name: async::g Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 1) to (start + 0, 23) @@ -105,7 +105,7 @@ Highest counter ID seen: c0 Function name: async::g::{closure#0} (unused) Raw bytes (59): 0x[01, 01, 00, 0b, 00, 1b, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 11 - Code(Zero) at (prev + 27, 23) to (start + 1, 12) @@ -124,7 +124,7 @@ Highest counter ID seen: (none) Function name: async::h Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 16] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 22) @@ -133,7 +133,7 @@ Highest counter ID seen: c0 Function name: async::h::{closure#0} (unused) Raw bytes (39): 0x[01, 01, 00, 07, 00, 23, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 7 - Code(Zero) at (prev + 35, 22) to (start + 3, 12) @@ -148,7 +148,7 @@ Highest counter ID seen: (none) Function name: async::i Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 44, 1) to (start + 0, 19) @@ -157,7 +157,7 @@ Highest counter ID seen: c0 Function name: async::i::{closure#0} Raw bytes (65): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0b, 01, 2c, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(4), rhs = Counter(5) @@ -182,7 +182,7 @@ Highest counter ID seen: c5 Function name: async::j Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 37, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) @@ -205,7 +205,7 @@ Highest counter ID seen: c2 Function name: async::j::c Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 39, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -219,7 +219,7 @@ Highest counter ID seen: c1 Function name: async::j::d Raw bytes (9): 0x[01, 01, 00, 01, 01, 40, 05, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 64, 5) to (start + 0, 23) @@ -228,7 +228,7 @@ Highest counter ID seen: c0 Function name: async::j::f Raw bytes (9): 0x[01, 01, 00, 01, 01, 41, 05, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 65, 5) to (start + 0, 23) @@ -237,7 +237,7 @@ Highest counter ID seen: c0 Function name: async::k (unused) Raw bytes (29): 0x[01, 01, 00, 05, 00, 49, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 5 - Code(Zero) at (prev + 73, 1) to (start + 1, 12) @@ -250,7 +250,7 @@ Highest counter ID seen: (none) Function name: async::l Raw bytes (33): 0x[01, 01, 02, 01, 07, 05, 09, 05, 01, 51, 01, 01, 0c, 02, 02, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -266,7 +266,7 @@ Highest counter ID seen: c2 Function name: async::m Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 89, 1) to (start + 0, 25) @@ -275,7 +275,7 @@ Highest counter ID seen: c0 Function name: async::m::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 59, 19, 00, 22] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 89, 25) to (start + 0, 34) @@ -284,7 +284,7 @@ Highest counter ID seen: (none) Function name: async::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 08, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 91, 1) to (start + 8, 2) diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index c2a0645ee9a8..43ec9f397bd9 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -1,7 +1,7 @@ Function name: async2::async_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 15, 1) to (start + 0, 23) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 17, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 15, 23) to (start + 3, 9) @@ -22,7 +22,7 @@ Highest counter ID seen: c0 Function name: async2::async_func_just_println Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 36) @@ -31,7 +31,7 @@ Highest counter ID seen: c0 Function name: async2::async_func_just_println::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 24, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 36) to (start + 2, 2) @@ -40,7 +40,7 @@ Highest counter ID seen: c0 Function name: async2::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 07, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 1) to (start + 7, 2) @@ -49,7 +49,7 @@ Highest counter ID seen: c0 Function name: async2::non_async_func Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 01, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 7, 1) to (start + 3, 9) diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map index d9196f446f13..9e76bb981ffe 100644 --- a/tests/coverage/async_block.cov-map +++ b/tests/coverage/async_block.cov-map @@ -1,7 +1,7 @@ Function name: async_block::main Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 22, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 6 @@ -19,7 +19,7 @@ Highest counter ID seen: c1 Function name: async_block::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index a4ef0ceeb6df..10b6db0fc713 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -1,7 +1,7 @@ Function name: async_closure::call_once:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2b] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 43) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: async_closure::call_once::::{closure#0} Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 06, 2b, 01, 0e, 02, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 2 @@ -22,7 +22,7 @@ Highest counter ID seen: c0 Function name: async_closure::main Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 01, 16, 01, 02, 05, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 10, 1) to (start + 1, 22) @@ -32,7 +32,7 @@ Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) @@ -42,7 +42,7 @@ Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) @@ -52,7 +52,7 @@ Highest counter ID seen: c0 Function name: async_closure::main::{closure#0}::{closure#0}:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map index 8a23c082082e..ad24dfb63229 100644 --- a/tests/coverage/attr/impl.cov-map +++ b/tests/coverage/attr/impl.cov-map @@ -1,7 +1,7 @@ Function name: ::off_on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 05, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 15, 5) to (start + 0, 19) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: ::on_inherit (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 23, 5) to (start + 0, 23) @@ -19,7 +19,7 @@ Highest counter ID seen: (none) Function name: ::on_on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 05, 00, 12] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 26, 5) to (start + 0, 18) diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map index 81e20a2c2649..eba24da0dd1e 100644 --- a/tests/coverage/attr/module.cov-map +++ b/tests/coverage/attr/module.cov-map @@ -1,7 +1,7 @@ Function name: module::off::on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 0d, 05, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 13, 5) to (start + 0, 15) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: module::on::inherit (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 05, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 5) to (start + 0, 20) @@ -19,7 +19,7 @@ Highest counter ID seen: (none) Function name: module::on::on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 05, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 24, 5) to (start + 0, 15) diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map index 138b3159ea5c..a831340bce5e 100644 --- a/tests/coverage/attr/nested.cov-map +++ b/tests/coverage/attr/nested.cov-map @@ -1,7 +1,7 @@ Function name: nested::closure_expr Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 01, 01, 0f, 01, 0b, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 64, 1) to (start + 1, 15) @@ -11,7 +11,7 @@ Highest counter ID seen: c0 Function name: nested::closure_tail Raw bytes (14): 0x[01, 01, 00, 02, 01, 4f, 01, 01, 0f, 01, 11, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 79, 1) to (start + 1, 15) diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index c55c5897d8ba..d26f06bb81f5 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -1,7 +1,7 @@ Function name: off_on_sandwich::dense_a::dense_b Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 10, 01, 07, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 16, 5) to (start + 2, 16) @@ -11,7 +11,7 @@ Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 15, 01, 0b, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 34, 9) to (start + 2, 21) @@ -21,7 +21,7 @@ Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 19, 01, 07, 0d, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 37, 13) to (start + 2, 25) diff --git a/tests/coverage/attr/trait-impl-inherit.cov-map b/tests/coverage/attr/trait-impl-inherit.cov-map index eab9f926bb77..b3e875785926 100644 --- a/tests/coverage/attr/trait-impl-inherit.cov-map +++ b/tests/coverage/attr/trait-impl-inherit.cov-map @@ -1,7 +1,7 @@ Function name: ::f Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/trait-impl-inherit.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/await_ready.cov-map index 61fd4c7814d8..7bff6a4a7748 100644 --- a/tests/coverage/await_ready.cov-map +++ b/tests/coverage/await_ready.cov-map @@ -1,7 +1,7 @@ Function name: await_ready::await_ready Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/await_ready.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 30) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: await_ready::await_ready::{closure#0} Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 0e, 1e, 03, 0f, 02, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/await_ready.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 2 diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index f08a70a899d0..2ef299307261 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,7 +1,7 @@ Function name: bad_counter_ids::eq_bad Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 0f, 00, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 36, 1) to (start + 2, 15) @@ -11,7 +11,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::eq_bad_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) @@ -22,7 +22,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 0f, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) @@ -32,7 +32,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) @@ -43,7 +43,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 0f, 00, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 46, 1) to (start + 2, 15) @@ -53,7 +53,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) @@ -64,7 +64,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 0f, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 26, 1) to (start + 2, 15) @@ -74,7 +74,7 @@ Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) diff --git a/tests/coverage/bench.cov-map b/tests/coverage/bench.cov-map index 9ee6510f6904..1707957fddc1 100644 --- a/tests/coverage/bench.cov-map +++ b/tests/coverage/bench.cov-map @@ -1,7 +1,7 @@ Function name: bench::my_bench Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bench.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39) diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map index 656890634ff4..50e6eedb676f 100644 --- a/tests/coverage/branch/generics.cov-map +++ b/tests/coverage/branch/generics.cov-map @@ -1,7 +1,7 @@ Function name: generics::print_size::<()> Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 5 @@ -18,7 +18,7 @@ Highest counter ID seen: c1 Function name: generics::print_size:: Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 5 @@ -35,7 +35,7 @@ Highest counter ID seen: c1 Function name: generics::print_size:: Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 5 diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index 46533df00f71..c1a275b34a3f 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,7 +1,7 @@ Function name: guard::branch_match_guard Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 0e, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/guard.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(1), rhs = Counter(3) - expression 1 operands: lhs = Counter(2), rhs = Counter(1) diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index 7f6b174615a9..a79232233013 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -1,7 +1,7 @@ Function name: if_let::if_let Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if-let.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 7 @@ -21,7 +21,7 @@ Highest counter ID seen: c1 Function name: if_let::if_let_chain Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if-let.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 1d40f032aa87..64b13fcfaa1e 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -1,7 +1,7 @@ Function name: if::branch_and Raw bytes (54): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 2b, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -25,7 +25,7 @@ Highest counter ID seen: c2 Function name: if::branch_not Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -70,7 +70,7 @@ Highest counter ID seen: c4 Function name: if::branch_not_as Raw bytes (90): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0e, 01, 1d, 01, 01, 0e, 01, 03, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -106,7 +106,7 @@ Highest counter ID seen: c3 Function name: if::branch_or Raw bytes (60): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 08, 01, 35, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add) diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index 5d4fc57eb8f7..b01ca5c94dff 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -1,7 +1,7 @@ Function name: lazy_boolean::branch_and Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 13, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -18,7 +18,7 @@ Highest counter ID seen: c1 Function name: lazy_boolean::branch_or Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 1b, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -36,7 +36,7 @@ Highest counter ID seen: c1 Function name: lazy_boolean::chain Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -93,7 +93,7 @@ Highest counter ID seen: c6 Function name: lazy_boolean::nested_mixed Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 13 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 78507a326388..2af5e919f4c9 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,7 +1,7 @@ Function name: let_else::let_else Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let-else.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 7 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index ef71d12c8af1..3f753f14eb5b 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,7 +1,7 @@ Function name: match_arms::guards Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 0e, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-arms.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(5), rhs = Counter(1) - expression 1 operands: lhs = Counter(6), rhs = Counter(2) @@ -38,7 +38,7 @@ Highest counter ID seen: c8 Function name: match_arms::match_arms Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-arms.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) @@ -57,7 +57,7 @@ Highest counter ID seen: c3 Function name: match_arms::or_patterns Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-arms.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) diff --git a/tests/coverage/branch/match-trivial.cov-map b/tests/coverage/branch/match-trivial.cov-map index 1b0c6d12e3dc..dd05ae4e345f 100644 --- a/tests/coverage/branch/match-trivial.cov-map +++ b/tests/coverage/branch/match-trivial.cov-map @@ -1,7 +1,7 @@ Function name: match_trivial::_uninhabited (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-trivial.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 1) to (start + 1, 14) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: match_trivial::trivial Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 0e, 01, 03, 0b, 05, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-trivial.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map index 8fb44ef30fdb..d28e6a580085 100644 --- a/tests/coverage/branch/no-mir-spans.cov-map +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -1,7 +1,7 @@ Function name: no_mir_spans::while_cond Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 11, 20, 02, 01, 04, 0b, 00, 10] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 @@ -14,7 +14,7 @@ Highest counter ID seen: c0 Function name: no_mir_spans::while_cond_not Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 15, 20, 02, 01, 04, 0b, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 @@ -27,7 +27,7 @@ Highest counter ID seen: c0 Function name: no_mir_spans::while_op_and Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 13, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(2), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) @@ -46,7 +46,7 @@ Highest counter ID seen: c1 Function name: no_mir_spans::while_op_or Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(2), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Expression(2, Add) diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index 67746af051b6..e5fda26822e2 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -1,7 +1,7 @@ Function name: while::while_cond Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 0c, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 6 @@ -19,7 +19,7 @@ Highest counter ID seen: c1 Function name: while::while_cond_not Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 15, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 6 @@ -37,7 +37,7 @@ Highest counter ID seen: c1 Function name: while::while_op_and Raw bytes (58): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 08, 01, 1e, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(1), rhs = Counter(0) @@ -63,7 +63,7 @@ Highest counter ID seen: c2 Function name: while::while_op_or Raw bytes (56): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 08, 01, 29, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 2d784ba09b60..096be9ea78a0 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,7 +1,7 @@ Function name: closure::main Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0d, 1b, 01, 1a, 05, 02, 0a, 01, 0c, 05, 11, 1b, 01, 1e, 05, 02, 0a, 01, 0c, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 24 @@ -35,7 +35,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -49,7 +49,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#10} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 155, 7) to (start + 0, 33) @@ -58,7 +58,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#11} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9f, 01, 07, 00, 21] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 159, 7) to (start + 0, 33) @@ -67,7 +67,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#12} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 01, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 167, 1) to (start + 0, 23) @@ -76,7 +76,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#13} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, ac, 01, 0d, 02, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 172, 13) to (start + 2, 14) @@ -85,7 +85,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#14} Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 @@ -98,7 +98,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#15} Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -114,7 +114,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#16} Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 @@ -127,7 +127,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#17} Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -143,7 +143,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#18} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -157,7 +157,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -171,7 +171,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#1} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -185,7 +185,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#2} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -199,7 +199,7 @@ Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 129, 5) to (start + 1, 20) @@ -211,7 +211,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#4} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 89, 01, 35, 00, 43] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 137, 53) to (start + 0, 67) @@ -220,7 +220,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#5} Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 3d, 00, 4f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 140, 61) to (start + 0, 79) @@ -229,7 +229,7 @@ Highest counter ID seen: c0 Function name: closure::main::{closure#6} Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 41, 00, 57] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 141, 65) to (start + 0, 87) @@ -238,7 +238,7 @@ Highest counter ID seen: c0 Function name: closure::main::{closure#7} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 3b, 00, 51] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 142, 59) to (start + 0, 81) @@ -247,7 +247,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#8} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 93, 01, 3b, 00, 55] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 147, 59) to (start + 0, 85) @@ -256,7 +256,7 @@ Highest counter ID seen: (none) Function name: closure::main::{closure#9} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 95, 01, 38, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 149, 56) to (start + 2, 6) diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 40a8bdf9c1d6..8355cbf352b3 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,7 +1,7 @@ Function name: closure_bug::main Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -34,7 +34,7 @@ Highest counter ID seen: c4 Function name: closure_bug::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -48,7 +48,7 @@ Highest counter ID seen: c1 Function name: closure_bug::main::{closure#1} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -62,7 +62,7 @@ Highest counter ID seen: c1 Function name: closure_bug::main::{closure#2} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -76,7 +76,7 @@ Highest counter ID seen: c1 Function name: closure_bug::main::{closure#3} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 9dd99c8fab3f..c624896a720a 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -1,7 +1,7 @@ Function name: closure_macro::load_configuration_files Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: closure_macro::main Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -27,7 +27,7 @@ Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 2548754d754c..77bf31de8bd8 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -1,7 +1,7 @@ Function name: closure_macro_async::load_configuration_files Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: closure_macro_async::test Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 00, 2b] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 37, 1) to (start + 0, 43) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: closure_macro_async::test::{closure#0} Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 25, 2b, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 @@ -36,7 +36,7 @@ Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map index 9a66e0b0e772..c75119019fc8 100644 --- a/tests/coverage/closure_unit_return.cov-map +++ b/tests/coverage/closure_unit_return.cov-map @@ -1,7 +1,7 @@ Function name: closure_unit_return::explicit_unit Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 01, 01, 10, 01, 05, 05, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 16) @@ -11,7 +11,7 @@ Highest counter ID seen: c0 Function name: closure_unit_return::explicit_unit::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 08, 16, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 8, 22) to (start + 2, 6) @@ -20,7 +20,7 @@ Highest counter ID seen: (none) Function name: closure_unit_return::implicit_unit Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 10, 01, 05, 05, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 16, 1) to (start + 1, 16) @@ -30,7 +30,7 @@ Highest counter ID seen: c0 Function name: closure_unit_return::implicit_unit::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 17, 22) to (start + 2, 6) diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index c34075a0bcfc..1bcf045b8942 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -1,7 +1,7 @@ Function name: conditions::assign_3_and_or Raw bytes (65): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 1c, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -30,7 +30,7 @@ Highest counter ID seen: c3 Function name: conditions::assign_3_or_and Raw bytes (63): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 09, 01, 17, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) @@ -58,7 +58,7 @@ Highest counter ID seen: c3 Function name: conditions::assign_and Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 0d, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -79,7 +79,7 @@ Highest counter ID seen: c2 Function name: conditions::assign_or Raw bytes (49): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 07, 01, 12, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) @@ -102,7 +102,7 @@ Highest counter ID seen: c2 Function name: conditions::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) @@ -111,7 +111,7 @@ Highest counter ID seen: c0 Function name: conditions::func_call Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -132,7 +132,7 @@ Highest counter ID seen: c2 Function name: conditions::simple_assign Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 2d12f4bf7744..86a317948132 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,7 +1,7 @@ Function name: conditions::main Raw bytes (533): 0x[01, 01, 47, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 97, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 97, 01, 15, 0d, 11, 19, 45, 19, 8f, 01, 45, 49, 8f, 01, 4d, 45, 49, 19, 8b, 01, 8f, 01, 4d, 45, 49, 97, 01, db, 01, 0d, 11, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, db, 01, 1d, 15, 19, 21, 39, 21, d3, 01, 39, 3d, d3, 01, 41, 39, 3d, 21, cf, 01, d3, 01, 41, 39, 3d, db, 01, 97, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, 97, 02, 25, 1d, 21, 29, 2d, 29, 8f, 02, 2d, 31, 8f, 02, 35, 2d, 31, 29, 8b, 02, 8f, 02, 35, 2d, 31, 97, 02, 9b, 02, 1d, 21, 25, 29, 44, 01, 03, 01, 02, 0c, 01, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 01, 0a, 06, 02, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 01, 12, 2a, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 03, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 97, 01, 03, 08, 00, 0c, 97, 01, 01, 0d, 01, 10, 97, 01, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 97, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 6a, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 72, 00, 21, 00, 2e, 76, 00, 32, 00, 40, 8b, 01, 00, 41, 02, 0e, 86, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 92, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, db, 01, 02, 09, 01, 0c, db, 01, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 97, 02, 02, 09, 00, 0a, db, 01, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, ae, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, b6, 01, 00, 1d, 00, 2a, ba, 01, 00, 2e, 00, 3c, cf, 01, 00, 3d, 02, 0a, ca, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, d6, 01, 02, 0d, 02, 0f, 9b, 02, 05, 09, 00, 0a, 97, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, ea, 01, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, f2, 01, 00, 1d, 00, 2a, f6, 01, 00, 2e, 00, 3c, 8b, 02, 00, 3d, 02, 0a, 86, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, 92, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 71 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index d926741cbcb3..a8077a32df7d 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -1,7 +1,7 @@ Function name: continue::main Raw bytes (198): 0x[01, 01, 16, 05, 01, 05, 0b, 01, 09, 0d, 01, 0d, 1f, 01, 11, 0d, 1f, 01, 11, 15, 01, 15, 2b, 01, 19, 1d, 01, 1d, 37, 01, 21, 25, 01, 25, 43, 01, 29, 25, 01, 2d, 01, 53, 2d, 01, 31, 2d, 01, 1e, 01, 03, 01, 03, 12, 05, 04, 0e, 00, 13, 02, 01, 0f, 00, 16, 09, 02, 11, 00, 19, 06, 02, 12, 04, 0e, 0d, 06, 0e, 00, 13, 0e, 01, 0f, 00, 16, 1a, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 1a, 03, 09, 00, 0e, 15, 02, 0e, 00, 13, 22, 01, 0f, 00, 16, 19, 01, 15, 02, 0e, 26, 04, 11, 00, 19, 19, 03, 09, 00, 0e, 1d, 02, 0e, 00, 13, 2e, 01, 0c, 00, 13, 21, 01, 0d, 00, 15, 32, 01, 0a, 01, 0e, 25, 03, 0e, 00, 13, 46, 01, 0f, 00, 16, 3e, 01, 16, 02, 0e, 29, 03, 12, 02, 0e, 46, 04, 09, 00, 0e, 2d, 02, 0e, 00, 13, 31, 01, 0f, 00, 16, 56, 01, 16, 02, 0e, 4e, 04, 11, 00, 16, 56, 03, 09, 00, 0e, 01, 02, 0d, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/continue.rs Number of expressions: 22 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index fee32376d831..0ce915538638 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -1,7 +1,7 @@ Function name: coroutine::get_u32 Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -15,7 +15,7 @@ Highest counter ID seen: c1 Function name: coroutine::main Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -36,7 +36,7 @@ Highest counter ID seen: c3 Function name: coroutine::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map index fb861996a0d2..e029a3b4643e 100644 --- a/tests/coverage/coverage_attr_closure.cov-map +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -1,7 +1,7 @@ Function name: coverage_attr_closure::GLOBAL_CLOSURE_ON::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 0f, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 6, 15) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_off::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 13, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 29, 19) to (start + 2, 6) @@ -19,7 +19,7 @@ Highest counter ID seen: (none) Function name: coverage_attr_closure::contains_closures_on Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 01, 1a, 01, 05, 09, 00, 1b, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 26) @@ -30,7 +30,7 @@ Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 17, 19) to (start + 2, 6) diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index 897372fe0b5e..4cb311428a18 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -1,7 +1,7 @@ Function name: dead_code::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -15,7 +15,7 @@ Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 15, 1) to (start + 7, 15) @@ -27,7 +27,7 @@ Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 3, 1) to (start + 7, 15) diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map index 16facf2eddf2..a52ebd87aa82 100644 --- a/tests/coverage/drop_trait.cov-map +++ b/tests/coverage/drop_trait.cov-map @@ -1,7 +1,7 @@ Function name: ::drop Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/drop_trait.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: drop_trait::main Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 01, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/drop_trait.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12) diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map index 6d6034928c9a..465baa7f7f9b 100644 --- a/tests/coverage/fn_sig_into_try.cov-map +++ b/tests/coverage/fn_sig_into_try.cov-map @@ -1,7 +1,7 @@ Function name: fn_sig_into_try::a Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 05, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: fn_sig_into_try::b Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15) @@ -22,7 +22,7 @@ Highest counter ID seen: c0 Function name: fn_sig_into_try::c Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23) @@ -34,7 +34,7 @@ Highest counter ID seen: c0 Function name: fn_sig_into_try::d Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15) diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map index 5878de231bad..119c426965d1 100644 --- a/tests/coverage/generic-unused-impl.cov-map +++ b/tests/coverage/generic-unused-impl.cov-map @@ -1,7 +1,7 @@ Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 11, 5) to (start + 3, 6) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: generic_unused_impl::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13) diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map index bc5661afdc19..92c6ad01e300 100644 --- a/tests/coverage/generics.cov-map +++ b/tests/coverage/generics.cov-map @@ -1,7 +1,7 @@ Function name: as core::ops::drop::Drop>::drop Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: >::set_strength Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: as core::ops::drop::Drop>::drop Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) @@ -28,7 +28,7 @@ Highest counter ID seen: c0 Function name: >::set_strength Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) @@ -37,7 +37,7 @@ Highest counter ID seen: c0 Function name: generics::main Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 01, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12) diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 6e2d243e8dd2..5298c2d92d5d 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -1,7 +1,7 @@ Function name: ::_method (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 2b, 09, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 43, 9) to (start + 0, 29) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: holes::main Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 06, 27, 01, 13, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 Number of file 0 mappings: 13 - Code(Counter(0)) at (prev + 8, 1) to (start + 1, 17) @@ -31,7 +31,7 @@ Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 05, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 31, 5) to (start + 0, 23) @@ -40,7 +40,7 @@ Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 09, 02, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 24, 9) to (start + 2, 10) @@ -49,7 +49,7 @@ Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 4b, 09, 02, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 75, 9) to (start + 2, 10) diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index a77ba8194a44..611dd2ef08d5 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,7 +1,7 @@ Function name: if::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map index 194ad6ca71f8..35096d859502 100644 --- a/tests/coverage/if_else.cov-map +++ b/tests/coverage/if_else.cov-map @@ -1,7 +1,7 @@ Function name: if_else::main Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if_else.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index f47139ce5a48..0fd35c55e3e5 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,7 +1,7 @@ Function name: if_not::if_not Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if_not.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) diff --git a/tests/coverage/ignore_run.cov-map b/tests/coverage/ignore_run.cov-map index c8ad3821e16f..a93fff71530b 100644 --- a/tests/coverage/ignore_run.cov-map +++ b/tests/coverage/ignore_run.cov-map @@ -1,7 +1,7 @@ Function name: ignore_run::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/ignore_run.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 65cefe76c29a..450fb75b7c8e 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -1,7 +1,7 @@ Function name: inline_dead::dead (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 23, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: inline_dead::live:: Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 01, 01, 09, 05, 02, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -24,7 +24,7 @@ Highest counter ID seen: c1 Function name: inline_dead::main Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 4, 1) to (start + 3, 10) @@ -34,7 +34,7 @@ Highest counter ID seen: c0 Function name: inline_dead::main::{closure#0} Raw bytes (19): 0x[01, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 7, 23) to (start + 1, 22) diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index 7264391baaf7..5aa57e15bd5c 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -1,7 +1,7 @@ Function name: inline::display:: Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 29, 01, 00, 22, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 10, 02, 00, 11, 02, 06, 01, 03, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 5 @@ -17,7 +17,7 @@ Highest counter ID seen: c1 Function name: inline::error Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 0b] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 11) @@ -26,7 +26,7 @@ Highest counter ID seen: c0 Function name: inline::length:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) @@ -35,7 +35,7 @@ Highest counter ID seen: c0 Function name: inline::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2) @@ -44,7 +44,7 @@ Highest counter ID seen: c0 Function name: inline::permutate:: Raw bytes (54): 0x[01, 01, 05, 01, 05, 0d, 09, 0d, 09, 01, 13, 05, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 0a, 01, 0d, 00, 0e, 09, 00, 12, 00, 16, 0a, 00, 17, 04, 0a, 0e, 05, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(3), rhs = Counter(2) @@ -69,7 +69,7 @@ Highest counter ID seen: c2 Function name: inline::permutations:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2) @@ -78,7 +78,7 @@ Highest counter ID seen: c0 Function name: inline::swap:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2) diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index a12cce25b643..a9e19fe53a53 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -1,7 +1,7 @@ Function name: ::default_trait_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 09, 03, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: ::trait_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: inner_items::main Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 05, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -38,7 +38,7 @@ Highest counter ID seen: c2 Function name: inner_items::main::in_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6) diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index f10231090089..4e45db836d67 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,7 +1,7 @@ Function name: issue_83601::main Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 0f, 05, 03, 09, 01, 0f, 02, 02, 05, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-83601.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 3 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 47e2922a805a..1ed5edbb8191 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -1,7 +1,7 @@ Function name: ::fmt Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 24, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -15,7 +15,7 @@ Highest counter ID seen: c1 Function name: issue_84561::main Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2) @@ -24,7 +24,7 @@ Highest counter ID seen: c0 Function name: issue_84561::test1 Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11) @@ -41,7 +41,7 @@ Highest counter ID seen: c4 Function name: issue_84561::test2 Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) @@ -52,7 +52,7 @@ Highest counter ID seen: c1 Function name: issue_84561::test2::call_print Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) @@ -61,7 +61,7 @@ Highest counter ID seen: c0 Function name: issue_84561::test3 Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 02, 13, 21, 03, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 10 - expression 0 operands: lhs = Counter(3), rhs = Counter(4) - expression 1 operands: lhs = Counter(3), rhs = Counter(5) diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/issue-85461.cov-map index 349bc2cab803..566206a7539d 100644 --- a/tests/coverage/issue-85461.cov-map +++ b/tests/coverage/issue-85461.cov-map @@ -1,7 +1,7 @@ Function name: issue_85461::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-85461.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index 38cb70a3f97a..3cb54d80e7f0 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -1,7 +1,7 @@ Function name: issue_93054::foo2 (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 1) to (start + 0, 29) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: issue_93054::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: issue_93054::make (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 1) to (start + 2, 2) diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index 3f7788da1ebc..9722b4c2a325 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,7 +1,7 @@ Function name: lazy_boolean::main Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 25, 01, 21, 01, 11, 01, 15, 01, 19, 01, 1d, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 09, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 0d, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 11, 03, 05, 00, 06, 01, 03, 09, 00, 10, 15, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 19, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 1d, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy_boolean.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(9) diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index 7789114c2395..f55e5a930b47 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -1,7 +1,7 @@ Function name: let_else_loop::_if (unused) Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Zero) at (prev + 22, 1) to (start + 1, 12) @@ -12,7 +12,7 @@ Highest counter ID seen: (none) Function name: let_else_loop::_loop_either_way (unused) Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Zero) at (prev + 15, 1) to (start + 1, 20) @@ -23,7 +23,7 @@ Highest counter ID seen: (none) Function name: let_else_loop::loopy Raw bytes (19): 0x[01, 01, 00, 03, 01, 09, 01, 01, 14, 09, 01, 1c, 00, 23, 05, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 9, 1) to (start + 1, 20) diff --git a/tests/coverage/long_and_wide.cov-map b/tests/coverage/long_and_wide.cov-map index 032b7fe102e8..c8194ccc79b3 100644 --- a/tests/coverage/long_and_wide.cov-map +++ b/tests/coverage/long_and_wide.cov-map @@ -1,7 +1,7 @@ Function name: long_and_wide::far_function Raw bytes (10): 0x[01, 01, 00, 01, 01, 96, 01, 01, 00, 15] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: long_and_wide::long_function Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: long_and_wide::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2) @@ -28,7 +28,7 @@ Highest counter ID seen: c0 Function name: long_and_wide::wide_function Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139) diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index fccc4d64395b..8edb6d06dd6d 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,7 +1,7 @@ Function name: loop_break::main Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0b, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loop-break.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 5 diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map index e48d078f6722..d16335a0a291 100644 --- a/tests/coverage/loop_break_value.cov-map +++ b/tests/coverage/loop_break_value.cov-map @@ -1,7 +1,7 @@ Function name: loop_break_value::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 0a, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loop_break_value.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 1) to (start + 10, 2) diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 2157cd6ee3f8..d414710ee9d6 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,7 +1,7 @@ Function name: ::fmt Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 14, 01, 09, 05, 01, 10, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) - expression 1 operands: lhs = Counter(0), rhs = Counter(3) @@ -35,7 +35,7 @@ Highest counter ID seen: c3 Function name: ::fmt Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -69,7 +69,7 @@ Highest counter ID seen: c3 Function name: loops_branches::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2) diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 9614154a3668..3e71ed877bf9 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -1,7 +1,7 @@ Function name: macro_in_closure::NO_BLOCK::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 1c, 00, 2d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 7, 28) to (start + 0, 45) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 1e, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 9, 30) to (start + 2, 2) diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index bd033faa5510..18b4e28b7b43 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -1,7 +1,7 @@ Function name: macro_name_span::affected_function Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 3e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_name_span.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 22, 28) to (start + 1, 62) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: macro_name_span::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_name_span.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index ae77eedfe72e..a29c712998f7 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,7 +1,7 @@ Function name: match_or_pattern::main Raw bytes (145): 0x[01, 01, 08, 01, 05, 01, 09, 01, 0d, 01, 11, 01, 15, 01, 19, 01, 1d, 01, 21, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 06, 03, 1b, 00, 1d, 09, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 0d, 00, 10, 03, 06, 0a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 0e, 01, 1b, 00, 1d, 11, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 16, 01, 1b, 00, 1d, 19, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 1d, 00, 10, 03, 06, 1a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 1e, 01, 1b, 00, 1d, 21, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match_or_pattern.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index befe8866a592..f966d754f540 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,7 +1,7 @@ Function name: condition_limit::accept_7_conditions Raw bytes (147): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 12, 01, 06, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/condition-limit.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 1b038f48429e..de4ea7790f75 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,7 +1,7 @@ Function name: if::mcdc_check_a Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 0e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -25,7 +25,7 @@ Highest counter ID seen: c2 Function name: if::mcdc_check_b Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 16, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -49,7 +49,7 @@ Highest counter ID seen: c2 Function name: if::mcdc_check_both Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 1e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -73,7 +73,7 @@ Highest counter ID seen: c2 Function name: if::mcdc_check_neither Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 06, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -97,7 +97,7 @@ Highest counter ID seen: c2 Function name: if::mcdc_check_not_tree_decision Raw bytes (85): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0a, 01, 30, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add) @@ -131,7 +131,7 @@ Highest counter ID seen: c3 Function name: if::mcdc_check_tree_decision Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0a, 01, 26, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -166,7 +166,7 @@ Highest counter ID seen: c3 Function name: if::mcdc_nested_if Raw bytes (120): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 2b, 0d, 05, 09, 0d, 11, 2b, 11, 05, 09, 01, 2b, 05, 09, 0e, 01, 3a, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 2b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 0d, 12, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 1a, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 1e, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 11 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add) diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 7d78e572a3b0..714d168cf498 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,7 +1,7 @@ Function name: inlined_expressions::inlined_instance Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 07, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inlined_expressions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index 83d0739aaf59..7232e4f89cdd 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,7 +1,7 @@ Function name: nested_if::doubly_nested_if_in_condition Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 14, 01, 0e, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) @@ -61,7 +61,7 @@ Highest counter ID seen: c6 Function name: nested_if::nested_if_in_condition Raw bytes (118): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0e, 01, 06, 01, 01, 09, 28, 06, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 10 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) @@ -105,7 +105,7 @@ Highest counter ID seen: c4 Function name: nested_if::nested_in_then_block_in_condition Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 14, 01, 21, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(6) @@ -165,7 +165,7 @@ Highest counter ID seen: c6 Function name: nested_if::nested_single_condition_decision Raw bytes (83): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0b, 01, 16, 01, 04, 09, 28, 03, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(3) diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index 48a103b2c7d7..02251e691522 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,7 +1,7 @@ Function name: non_control_flow::assign_3 Raw bytes (79): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0a, 01, 15, 01, 00, 28, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) @@ -30,7 +30,7 @@ Highest counter ID seen: c3 Function name: non_control_flow::assign_3_bis Raw bytes (81): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0a, 01, 1a, 01, 00, 2c, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -60,7 +60,7 @@ Highest counter ID seen: c3 Function name: non_control_flow::assign_and Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 0b, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -82,7 +82,7 @@ Highest counter ID seen: c2 Function name: non_control_flow::assign_or Raw bytes (62): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 08, 01, 10, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) @@ -106,7 +106,7 @@ Highest counter ID seen: c2 Function name: non_control_flow::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 24, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 36, 1) to (start + 2, 2) @@ -115,7 +115,7 @@ Highest counter ID seen: c0 Function name: non_control_flow::func_call Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -137,7 +137,7 @@ Highest counter ID seen: c2 Function name: non_control_flow::right_comb_tree Raw bytes (111): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 0e, 01, 1f, 01, 00, 41, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index e9e41bd53e78..4a35da13a847 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -1,7 +1,7 @@ Function name: nested_loops::main Raw bytes (97): 0x[01, 01, 0e, 07, 2f, 05, 11, 01, 0d, 2f, 05, 01, 0d, 27, 05, 01, 09, 33, 27, 05, 15, 01, 09, 2f, 33, 01, 0d, 05, 15, 05, 01, 0d, 01, 01, 01, 02, 1b, 05, 04, 13, 00, 20, 09, 01, 0d, 01, 18, 0d, 02, 12, 00, 17, 11, 01, 10, 00, 16, 02, 01, 11, 00, 16, 0e, 01, 0e, 03, 16, 15, 04, 11, 01, 1b, 16, 02, 15, 00, 21, 1e, 01, 18, 02, 12, 2a, 03, 0d, 00, 0e, 36, 02, 09, 00, 17, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_loops.rs Number of expressions: 14 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(11, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) diff --git a/tests/coverage/no-core.cov-map b/tests/coverage/no-core.cov-map index 3a1ca4745c73..89012b0ab917 100644 --- a/tests/coverage/no-core.cov-map +++ b/tests/coverage/no-core.cov-map @@ -1,7 +1,7 @@ Function name: no_core::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 01, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-core.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 0, 13) diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index 244b0099544b..caef09355d22 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -1,7 +1,7 @@ Function name: no_cov_crate::add_coverage_1 Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 22, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_2 Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 26, 1) to (start + 2, 2) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_not_called (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 31, 1) to (start + 2, 2) @@ -28,7 +28,7 @@ Highest counter ID seen: (none) Function name: no_cov_crate::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 4f, 01, 0b, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 79, 1) to (start + 11, 2) @@ -37,7 +37,7 @@ Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 05, 02, 22, 01, 0c, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 51, 5) to (start + 2, 34) @@ -47,7 +47,7 @@ Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered Raw bytes (14): 0x[01, 01, 00, 02, 01, 41, 05, 02, 16, 01, 0b, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 65, 5) to (start + 2, 22) @@ -57,7 +57,7 @@ Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered::inner Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 45, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 diff --git a/tests/coverage/no_spans.cov-map b/tests/coverage/no_spans.cov-map index 7f43b68fa904..992247fd520b 100644 --- a/tests/coverage/no_spans.cov-map +++ b/tests/coverage/no_spans.cov-map @@ -1,7 +1,7 @@ Function name: no_spans::affected_function Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 1c, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 26, 28) to (start + 0, 29) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: no_spans::affected_function::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 12) to (start + 0, 14) diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map index 6c389a243172..9d4fc074111f 100644 --- a/tests/coverage/no_spans_if_not.cov-map +++ b/tests/coverage/no_spans_if_not.cov-map @@ -1,7 +1,7 @@ Function name: no_spans_if_not::affected_function Raw bytes (19): 0x[01, 01, 00, 03, 01, 16, 1c, 01, 12, 01, 02, 0d, 00, 0f, 00, 02, 0d, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 22, 28) to (start + 1, 18) @@ -12,7 +12,7 @@ Highest counter ID seen: c0 Function name: no_spans_if_not::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index 1178d65de102..9bb68ee107dd 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -1,7 +1,7 @@ Function name: overflow::main Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 10, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 03, 0a, 06, 03, 13, 00, 20, 0d, 00, 21, 03, 0a, 0e, 03, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/overflow.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -28,7 +28,7 @@ Highest counter ID seen: c3 Function name: overflow::might_overflow Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 05, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/overflow.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index 18b13919fe5e..f6d1fe5b9b48 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -1,7 +1,7 @@ Function name: panic_unwind::main Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/panic_unwind.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -28,7 +28,7 @@ Highest counter ID seen: c3 Function name: panic_unwind::might_panic Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/panic_unwind.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 21c8714ac99b..02054aa444a5 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,7 +1,7 @@ Function name: ::new Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/partial_eq.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: partial_eq::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/partial_eq.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index 8e428b267d56..542c93cbfa05 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,7 +1,7 @@ Function name: simple_loop::main Raw bytes (43): 0x[01, 01, 02, 01, 05, 09, 01, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 05, 00, 06, 09, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 06, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/simple_loop.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index 15f114daa7fb..a96ddc2bb9ae 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,7 +1,7 @@ Function name: simple_match::main Raw bytes (64): 0x[01, 01, 05, 01, 05, 09, 01, 09, 01, 09, 13, 01, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 09, 05, 09, 00, 0d, 0a, 05, 0d, 00, 16, 0d, 02, 0d, 00, 0e, 0a, 02, 11, 02, 12, 0d, 04, 0d, 07, 0e, 0e, 0a, 0d, 00, 0f, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/simple_match.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 898d68171c50..b0d260efeb9a 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -1,7 +1,7 @@ Function name: sort_groups::generic_fn::<&str> Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -15,7 +15,7 @@ Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -29,7 +29,7 @@ Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -43,7 +43,7 @@ Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -57,7 +57,7 @@ Highest counter ID seen: c1 Function name: sort_groups::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 1c, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -71,7 +71,7 @@ Highest counter ID seen: c1 Function name: sort_groups::other_fn Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17) diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map index b513b3d05494..50654fb22137 100644 --- a/tests/coverage/test_harness.cov-map +++ b/tests/coverage/test_harness.cov-map @@ -1,7 +1,7 @@ Function name: test_harness::my_test Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 10] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/test_harness.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: test_harness::unused (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/test_harness.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 7, 1) to (start + 0, 15) diff --git a/tests/coverage/tight_inf_loop.cov-map b/tests/coverage/tight_inf_loop.cov-map index 77a8ffb83581..31581f0872f9 100644 --- a/tests/coverage/tight_inf_loop.cov-map +++ b/tests/coverage/tight_inf_loop.cov-map @@ -1,7 +1,7 @@ Function name: tight_inf_loop::main Raw bytes (19): 0x[01, 01, 00, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 01, 01, 06, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/tight_inf_loop.rs Number of expressions: 0 Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 13) diff --git a/tests/coverage/trivial.cov-map b/tests/coverage/trivial.cov-map index 05f64896d9ec..0064b20480f3 100644 --- a/tests/coverage/trivial.cov-map +++ b/tests/coverage/trivial.cov-map @@ -1,7 +1,7 @@ Function name: trivial::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/trivial.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index e45f3de10815..a6ecc68ab0e8 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -1,7 +1,7 @@ Function name: ::get_thing_2 Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -15,7 +15,7 @@ Highest counter ID seen: c1 Function name: ::call Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -29,7 +29,7 @@ Highest counter ID seen: c1 Function name: try_error_result::call Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -43,7 +43,7 @@ Highest counter ID seen: c1 Function name: try_error_result::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0a, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -57,7 +57,7 @@ Highest counter ID seen: c1 Function name: try_error_result::test1 Raw bytes (67): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0b, 01, 0d, 01, 02, 17, 05, 07, 09, 00, 0e, 09, 02, 09, 04, 1a, 02, 06, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -84,7 +84,7 @@ Highest counter ID seen: c2 Function name: try_error_result::test2 Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 17, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 17, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 17, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 17, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 17, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 54 - expression 0 operands: lhs = Counter(3), rhs = Counter(4) - expression 1 operands: lhs = Counter(3), rhs = Expression(15, Add) diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 29d40a055130..7ad4395491f0 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,7 +1,7 @@ Function name: unicode::main Raw bytes (53): 0x[01, 01, 02, 05, 01, 01, 0d, 09, 01, 0e, 01, 00, 0b, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(0), rhs = Counter(3) @@ -23,7 +23,7 @@ Highest counter ID seen: c3 Function name: unicode::他 (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 30, 25) to (start + 0, 37) @@ -32,7 +32,7 @@ Highest counter ID seen: (none) Function name: unicode::申し訳ございません Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index 0bc18bfcbd31..fd9a1abc8cb0 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -1,7 +1,7 @@ Function name: unreachable::UNREACHABLE_CLOSURE::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 27, 00, 45] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 14, 39) to (start + 0, 69) @@ -10,7 +10,7 @@ Highest counter ID seen: (none) Function name: unreachable::unreachable_function (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 10, 01, 01, 23] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 16, 1) to (start + 1, 35) @@ -19,7 +19,7 @@ Highest counter ID seen: (none) Function name: unreachable::unreachable_intrinsic (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 01, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 1) to (start + 1, 42) diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index c18d331ec2e0..8946b43a8bbc 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -1,7 +1,7 @@ Function name: unused::foo:: Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) @@ -21,7 +21,7 @@ Highest counter ID seen: c1 Function name: unused::foo:: Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) @@ -41,7 +41,7 @@ Highest counter ID seen: c1 Function name: unused::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2) @@ -50,7 +50,7 @@ Highest counter ID seen: c0 Function name: unused::unused_func (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 19, 1) to (start + 1, 14) @@ -62,7 +62,7 @@ Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 25, 1) to (start + 1, 14) @@ -74,7 +74,7 @@ Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 31, 1) to (start + 1, 14) @@ -86,7 +86,7 @@ Highest counter ID seen: (none) Function name: unused::unused_template_func::<_> (unused) Raw bytes (34): 0x[01, 01, 00, 06, 00, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 Number of file 0 mappings: 6 - Code(Zero) at (prev + 11, 1) to (start + 1, 18) diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map index 5e8b69fcdba9..790cd701dc3a 100644 --- a/tests/coverage/unused_mod.cov-map +++ b/tests/coverage/unused_mod.cov-map @@ -1,7 +1,7 @@ Function name: unused_mod::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused_mod.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: unused_mod::unused_module::never_called_function (unused) Raw bytes (9): 0x[01, 02, 00, 01, 00, 02, 01, 02, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/auxiliary/unused_mod_helper.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 2, 1) to (start + 2, 2) diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/uses_crate.cov-map index 5c23f8826971..238226f3d683 100644 --- a/tests/coverage/uses_crate.cov-map +++ b/tests/coverage/uses_crate.cov-map @@ -1,7 +1,7 @@ Function name: used_crate::used_from_bin_crate_and_lib_crate_generic_function::> Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) @@ -19,7 +19,7 @@ Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) @@ -28,7 +28,7 @@ Highest counter ID seen: c0 Function name: used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2) @@ -37,7 +37,7 @@ Highest counter ID seen: c0 Function name: uses_crate::main Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 07, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/uses_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 7, 2) diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index a482d20e3b4b..fd14ea341202 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -1,7 +1,7 @@ Function name: used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::> Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2) @@ -10,7 +10,7 @@ Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 01, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 @@ -24,7 +24,7 @@ Highest counter ID seen: c1 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) @@ -33,7 +33,7 @@ Highest counter ID seen: c0 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) @@ -42,7 +42,7 @@ Highest counter ID seen: c0 Function name: used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2) @@ -51,7 +51,7 @@ Highest counter ID seen: c0 Function name: uses_inline_crate::main Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 0a, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/uses_inline_crate.rs Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 10, 2) diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map index 5a6698128cbd..8ad739206297 100644 --- a/tests/coverage/while.cov-map +++ b/tests/coverage/while.cov-map @@ -1,7 +1,7 @@ Function name: while::main Raw bytes (24): 0x[01, 01, 00, 04, 01, 01, 01, 01, 10, 01, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16) diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index 69b51bf9ca34..6e3db66f97c7 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -1,7 +1,7 @@ Function name: while_early_ret::main Raw bytes (63): 0x[01, 01, 07, 0f, 05, 01, 09, 0f, 13, 01, 09, 05, 0d, 05, 01, 05, 09, 09, 01, 05, 01, 01, 1b, 05, 03, 09, 02, 0a, 09, 05, 0d, 02, 0e, 02, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0a, 04, 15, 00, 1b, 16, 03, 0a, 03, 0a, 1a, 06, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while_early_ret.rs Number of expressions: 7 - expression 0 operands: lhs = Expression(3, Add), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index bf0916e5503a..db82c9d673d1 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,7 +1,7 @@ Function name: yield::main Raw bytes (94): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 2e, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 2e, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -35,7 +35,7 @@ Highest counter ID seen: c5 Function name: yield::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) @@ -45,7 +45,7 @@ Highest counter ID seen: c1 Function name: yield::main::{closure#1} Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16) From c35914383a92d7504f3a71c390dc2ebd14bce695 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 15 Mar 2025 11:19:56 -0700 Subject: [PATCH 272/302] Consistent trait bounds for ExtractIf Debug impls --- library/alloc/src/collections/btree/map.rs | 11 +++++------ library/alloc/src/collections/btree/set.rs | 13 ++++++------- library/alloc/src/collections/linked_list.rs | 9 +++++++-- library/alloc/src/vec/extract_if.rs | 15 +++++++++++++-- library/std/src/collections/hash/map.rs | 20 +++++++++----------- library/std/src/collections/hash/set.rs | 19 ++++++++----------- tests/rustdoc-js-std/path-maxeditdistance.js | 2 +- 7 files changed, 49 insertions(+), 40 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 78b7da9d6b3e..5ca32ed741af 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1917,14 +1917,13 @@ pub struct ExtractIf< V, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, -> where - F: 'a + FnMut(&K, &mut V) -> bool, -{ +> { pred: F, inner: ExtractIfInner<'a, K, V>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } + /// Most of the implementation of ExtractIf are generic over the type /// of the predicate, thus also serving for BTreeSet::ExtractIf. pub(super) struct ExtractIfInner<'a, K, V> { @@ -1940,14 +1939,14 @@ pub(super) struct ExtractIfInner<'a, K, V> { } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl fmt::Debug for ExtractIf<'_, K, V, F> +impl fmt::Debug for ExtractIf<'_, K, V, F, A> where K: fmt::Debug, V: fmt::Debug, - F: FnMut(&K, &mut V) -> bool, + A: Allocator + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish() + f.debug_struct("ExtractIf").field("peek", &self.inner.peek()).finish_non_exhaustive() } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 7ad9e59dfede..343934680b87 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1556,10 +1556,7 @@ pub struct ExtractIf< T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, -> where - T: 'a, - F: 'a + FnMut(&T) -> bool, -{ +> { pred: F, inner: super::map::ExtractIfInner<'a, T, SetValZST>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. @@ -1567,13 +1564,15 @@ pub struct ExtractIf< } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl fmt::Debug for ExtractIf<'_, T, F, A> +impl fmt::Debug for ExtractIf<'_, T, F, A> where T: fmt::Debug, - F: FnMut(&T) -> bool, + A: Allocator + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.inner.peek().map(|(k, _)| k)).finish() + f.debug_struct("ExtractIf") + .field("peek", &self.inner.peek().map(|(k, _)| k)) + .finish_non_exhaustive() } } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index cc42a120e4fa..00e2805d11f6 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1976,9 +1976,14 @@ where } #[stable(feature = "extract_if", since = "1.87.0")] -impl fmt::Debug for ExtractIf<'_, T, F> { +impl fmt::Debug for ExtractIf<'_, T, F, A> +where + T: fmt::Debug, + A: Allocator, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.list).finish() + let peek = self.it.map(|node| unsafe { &node.as_ref().element }); + f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive() } } diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index 8a591a877964..a456d3d9e602 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -1,5 +1,5 @@ use core::ops::{Range, RangeBounds}; -use core::{ptr, slice}; +use core::{fmt, ptr, slice}; use super::Vec; use crate::alloc::{Allocator, Global}; @@ -16,7 +16,6 @@ use crate::alloc::{Allocator, Global}; /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` #[stable(feature = "extract_if", since = "1.87.0")] -#[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -108,3 +107,15 @@ impl Drop for ExtractIf<'_, T, F, A> { } } } + +#[stable(feature = "extract_if", since = "1.87.0")] +impl fmt::Debug for ExtractIf<'_, T, F, A> +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let peek = if self.idx < self.end { self.vec.get(self.idx) } else { None }; + f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive() + } +} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9ad26e5d28ec..961d6ee0665c 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -683,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "1.87.0")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1680,12 +1680,9 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct ExtractIf<'a, K, V, F> -where - F: FnMut(&K, &mut V) -> bool, -{ +pub struct ExtractIf<'a, K, V, F> { base: base::ExtractIf<'a, K, V, F>, } @@ -2297,7 +2294,7 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2314,13 +2311,14 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[stable(feature = "hash_extract_if", since = "1.87.0")] -impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Debug for ExtractIf<'_, K, V, F> where - F: FnMut(&K, &mut V) -> bool, + K: fmt::Debug, + V: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 7be000594bc5..fa2f4f0a58fe 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -308,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "1.87.0")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1390,11 +1390,8 @@ pub struct Drain<'a, K: 'a> { /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "1.87.0")] -pub struct ExtractIf<'a, K, F> -where - F: FnMut(&K) -> bool, -{ +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +pub struct ExtractIf<'a, K, F> { base: base::ExtractIf<'a, K, F>, } @@ -1673,7 +1670,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1690,13 +1687,13 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[stable(feature = "hash_extract_if", since = "1.87.0")] -impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Debug for ExtractIf<'_, K, F> where - F: FnMut(&K) -> bool, + K: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js index fd12a0564966..6989e7d6488b 100644 --- a/tests/rustdoc-js-std/path-maxeditdistance.js +++ b/tests/rustdoc-js-std/path-maxeditdistance.js @@ -13,9 +13,9 @@ const EXPECTED = [ { 'path': 'std::vec', 'name': 'IntoIter' }, { 'path': 'std::vec::Vec', 'name': 'from_iter' }, { 'path': 'std::vec::Vec', 'name': 'into_iter' }, + { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, { 'path': 'std::vec::Drain', 'name': 'into_iter' }, { 'path': 'std::vec::IntoIter', 'name': 'into_iter' }, - { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, { 'path': 'std::vec::Splice', 'name': 'into_iter' }, { 'path': 'std::collections::VecDeque', 'name': 'iter' }, { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' }, From 9e7fb67838ce06e418d078c4d04b0ff578bd1f43 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 May 2025 12:54:03 +1000 Subject: [PATCH 273/302] Rename `graph::implementation::Graph` to `LinkedGraph` --- .../{implementation => linked_graph}/mod.rs | 36 +++++++++++++------ .../{implementation => linked_graph}/tests.rs | 8 ++--- .../rustc_data_structures/src/graph/mod.rs | 2 +- .../rustc_incremental/src/assert_dep_graph.rs | 2 +- .../src/infer/lexical_region_resolve/mod.rs | 8 ++--- .../rustc_query_system/src/dep_graph/query.rs | 6 ++-- 6 files changed, 39 insertions(+), 23 deletions(-) rename compiler/rustc_data_structures/src/graph/{implementation => linked_graph}/mod.rs (88%) rename compiler/rustc_data_structures/src/graph/{implementation => linked_graph}/tests.rs (95%) diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs similarity index 88% rename from compiler/rustc_data_structures/src/graph/implementation/mod.rs rename to compiler/rustc_data_structures/src/graph/linked_graph/mod.rs index a80365938b96..ecb0095626b4 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs @@ -1,4 +1,4 @@ -//! A graph module for use in dataflow, region resolution, and elsewhere. +//! See [`LinkedGraph`]. //! //! # Interface details //! @@ -28,7 +28,23 @@ use tracing::debug; #[cfg(test)] mod tests; -pub struct Graph { +/// A concrete graph implementation that supports: +/// - Nodes and/or edges labelled with custom data types (`N` and `E` respectively). +/// - Incremental addition of new nodes/edges (but not removal). +/// - Flat storage of node/edge data in a pair of vectors. +/// - Iteration over any node's out-edges or in-edges, via linked lists +/// threaded through the node/edge data. +/// +/// # Caution +/// This is an older graph implementation that is still used by some pieces +/// of diagnostic/debugging code. New code that needs a graph data structure +/// should consider using `VecGraph` instead, or implementing its own +/// special-purpose graph with the specific features needed. +/// +/// This graph implementation predates the later [graph traits](crate::graph), +/// and does not implement those traits, so it has its own implementations of a +/// few basic graph algorithms. +pub struct LinkedGraph { nodes: Vec>, edges: Vec>, } @@ -71,13 +87,13 @@ impl NodeIndex { } } -impl Graph { - pub fn new() -> Graph { - Graph { nodes: Vec::new(), edges: Vec::new() } +impl LinkedGraph { + pub fn new() -> Self { + Self { nodes: Vec::new(), edges: Vec::new() } } - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } + pub fn with_capacity(nodes: usize, edges: usize) -> Self { + Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } } // # Simple accessors @@ -249,7 +265,7 @@ impl Graph { // # Iterators pub struct AdjacentEdges<'g, N, E> { - graph: &'g Graph, + graph: &'g LinkedGraph, direction: Direction, next: EdgeIndex, } @@ -285,7 +301,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } pub struct DepthFirstTraversal<'g, N, E> { - graph: &'g Graph, + graph: &'g LinkedGraph, stack: Vec, visited: DenseBitSet, direction: Direction, @@ -293,7 +309,7 @@ pub struct DepthFirstTraversal<'g, N, E> { impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { pub fn with_start_node( - graph: &'g Graph, + graph: &'g LinkedGraph, start_node: NodeIndex, direction: Direction, ) -> Self { diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs similarity index 95% rename from compiler/rustc_data_structures/src/graph/implementation/tests.rs rename to compiler/rustc_data_structures/src/graph/linked_graph/tests.rs index 32a6d9ec881a..357aa81a57ca 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs @@ -1,11 +1,11 @@ use tracing::debug; -use crate::graph::implementation::*; +use super::{Debug, LinkedGraph, NodeIndex}; -type TestGraph = Graph<&'static str, &'static str>; +type TestGraph = LinkedGraph<&'static str, &'static str>; fn create_graph() -> TestGraph { - let mut graph = Graph::new(); + let mut graph = LinkedGraph::new(); // Create a simple graph // @@ -56,7 +56,7 @@ fn each_edge() { } fn test_adjacent_edges( - graph: &Graph, + graph: &LinkedGraph, start_index: NodeIndex, start_data: N, expected_incoming: &[(E, N)], diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 4a1e5db6768d..20416b472b21 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -1,8 +1,8 @@ use rustc_index::Idx; pub mod dominators; -pub mod implementation; pub mod iterate; +pub mod linked_graph; mod reference; pub mod reversed; pub mod scc; diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 1b2056f541f3..0e04a2a784ec 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -38,7 +38,7 @@ use std::fs::{self, File}; use std::io::Write; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING}; +use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, NodeIndex, OUTGOING}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index e3522137d838..2185886901e5 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -3,8 +3,8 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, INCOMING, NodeIndex, OUTGOING, +use rustc_data_structures::graph::linked_graph::{ + Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING, }; use rustc_data_structures::intern::Interned; use rustc_data_structures::unord::UnordSet; @@ -118,7 +118,7 @@ struct RegionAndOrigin<'tcx> { origin: SubregionOrigin<'tcx>, } -type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>; +type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>; struct LexicalResolver<'cx, 'tcx> { region_rels: &'cx RegionRelations<'cx, 'tcx>, @@ -668,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); - let mut graph = Graph::new(); + let mut graph = LinkedGraph::new(); for _ in 0..num_vars { graph.add_node(()); diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 624f4e4578ed..724a01327aba 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -1,11 +1,11 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{Direction, Graph, INCOMING, NodeIndex}; +use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, LinkedGraph, NodeIndex}; use rustc_index::IndexVec; use super::{DepNode, DepNodeIndex}; pub struct DepGraphQuery { - pub graph: Graph, + pub graph: LinkedGraph, pub indices: FxHashMap, pub dep_index_to_index: IndexVec>, } @@ -15,7 +15,7 @@ impl DepGraphQuery { let node_count = prev_node_count + prev_node_count / 4; let edge_count = 6 * node_count; - let graph = Graph::with_capacity(node_count, edge_count); + let graph = LinkedGraph::with_capacity(node_count, edge_count); let indices = FxHashMap::default(); let dep_index_to_index = IndexVec::new(); From cbaa73beca9a7b62c6400669e47e09958e8804ab Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 6 May 2025 02:37:45 +0800 Subject: [PATCH 274/302] tests: don't ignore compiler stderr in `lib-defaults.rs` And also: - Document test intent. - Move under `link-native-libs/` instead. --- tests/ui/abi/lib-defaults.rs | 15 --------------- tests/ui/link-native-libs/lib-defaults.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) delete mode 100644 tests/ui/abi/lib-defaults.rs create mode 100644 tests/ui/link-native-libs/lib-defaults.rs diff --git a/tests/ui/abi/lib-defaults.rs b/tests/ui/abi/lib-defaults.rs deleted file mode 100644 index 2c2cad4f82dc..000000000000 --- a/tests/ui/abi/lib-defaults.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -//@ dont-check-compiler-stderr (rust-lang/rust#54222) - -//@ compile-flags: -lrust_test_helpers - -#[link(name = "rust_test_helpers", kind = "static")] -extern "C" { - pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; -} - -fn main() { - unsafe { - rust_dbg_extern_identity_u32(42); - } -} diff --git a/tests/ui/link-native-libs/lib-defaults.rs b/tests/ui/link-native-libs/lib-defaults.rs new file mode 100644 index 000000000000..4e38adb643db --- /dev/null +++ b/tests/ui/link-native-libs/lib-defaults.rs @@ -0,0 +1,17 @@ +//! By default, `-l NAME` without an explicit kind will default to dylib. However, if there's also +//! an `#[link(name = NAME, kind = KIND)]` attribute with an explicit `KIND`, it should override the +//! CLI flag. In particular, this should not result in any duplicate flag warnings from the linker. + +//@ run-pass +//@ compile-flags: -lrust_test_helpers + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; +} + +fn main() { + unsafe { + rust_dbg_extern_identity_u32(42); + } +} From 3d4737fb5e999ef66e57753e432f7f8076bc5192 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 19 Feb 2025 11:41:31 +0100 Subject: [PATCH 275/302] Remove duplicate impl of string unescape --- compiler/rustc_builtin_macros/src/format.rs | 11 +- compiler/rustc_parse_format/src/lib.rs | 812 +++++++----------- compiler/rustc_parse_format/src/tests.rs | 159 +++- .../traits/on_unimplemented_format.rs | 17 +- .../hir-def/src/expr_store/lower/asm.rs | 2 +- .../crates/hir-def/src/hir/format_args.rs | 4 +- 6 files changed, 453 insertions(+), 552 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 12654001a1e2..39f9d5f90051 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + use parse::Position::ArgumentNamed; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; @@ -335,7 +337,7 @@ fn make_format_args( return ExpandResult::Ready(Err(guar)); } - let to_span = |inner_span: parse::InnerSpan| { + let to_span = |inner_span: Range| { is_source_literal.then(|| { fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }) }) @@ -407,7 +409,7 @@ fn make_format_args( let mut placeholder_index = 0; for piece in &pieces { - match *piece { + match piece.clone() { parse::Piece::Lit(s) => { unfinished_literal.push_str(s); } @@ -417,7 +419,8 @@ fn make_format_args( unfinished_literal.clear(); } - let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s)); + let span = + parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); placeholder_index += 1; let position_span = to_span(position_span); @@ -609,7 +612,7 @@ fn make_format_args( fn invalid_placeholder_type_error( ecx: &ExtCtxt<'_>, ty: &str, - ty_span: Option, + ty_span: Option>, fmt_span: Span, ) { let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 999e71592745..9dd064aca662 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -15,50 +15,13 @@ )] // tidy-alphabetical-end +use std::ops::Range; + pub use Alignment::*; pub use Count::*; pub use Position::*; use rustc_literal_escaper::{Mode, unescape_unicode}; -// Note: copied from rustc_span -/// Range inside of a `Span` used for diagnostics when we only have access to relative positions. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct InnerSpan { - pub start: usize, - pub end: usize, -} - -impl InnerSpan { - pub fn new(start: usize, end: usize) -> InnerSpan { - InnerSpan { start, end } - } -} - -/// The location and before/after width of a character whose width has changed from its source code -/// representation -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct InnerWidthMapping { - /// Index of the character in the source - pub position: usize, - /// The inner width in characters - pub before: usize, - /// The transformed width in characters - pub after: usize, -} - -impl InnerWidthMapping { - pub fn new(position: usize, before: usize, after: usize) -> InnerWidthMapping { - InnerWidthMapping { position, before, after } - } -} - -/// Whether the input string is a literal. If yes, it contains the inner width mappings. -#[derive(Clone, PartialEq, Eq)] -enum InputStringKind { - NotALiteral, - Literal { width_mappings: Vec }, -} - /// The type of format string that we are parsing. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ParseMode { @@ -68,15 +31,6 @@ pub enum ParseMode { InlineAsm, } -#[derive(Copy, Clone)] -struct InnerOffset(usize); - -impl InnerOffset { - fn to(self, end: InnerOffset) -> InnerSpan { - InnerSpan::new(self.0, end.0) - } -} - /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Clone, Debug, PartialEq)] @@ -89,13 +43,13 @@ pub enum Piece<'a> { } /// Representation of an argument specification. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct Argument<'a> { /// Where to find this argument pub position: Position<'a>, /// The span of the position indicator. Includes any whitespace in implicit /// positions (`{ }`). - pub position_span: InnerSpan, + pub position_span: Range, /// How to format the argument pub format: FormatSpec<'a>, } @@ -125,12 +79,12 @@ impl<'a> Argument<'a> { } /// Specification for the formatting of an argument in the format string. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct FormatSpec<'a> { /// Optionally specified character to fill alignment with. pub fill: Option, /// Span of the optionally specified fill character. - pub fill_span: Option, + pub fill_span: Option>, /// Optionally specified alignment. pub align: Alignment, /// The `+` or `-` flag. @@ -144,21 +98,21 @@ pub struct FormatSpec<'a> { /// The integer precision to use. pub precision: Count<'a>, /// The span of the precision formatting flag (for diagnostics). - pub precision_span: Option, + pub precision_span: Option>, /// The string width requested for the resulting format. pub width: Count<'a>, /// The span of the width formatting flag (for diagnostics). - pub width_span: Option, + pub width_span: Option>, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. pub ty: &'a str, /// The span of the descriptor string (for diagnostics). - pub ty_span: Option, + pub ty_span: Option>, } /// Enum describing where an argument for a format can be located. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Position<'a> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), @@ -210,12 +164,12 @@ pub enum DebugHex { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. CountIs(u16), /// The count is specified by the argument with the given name. - CountIsName(&'a str, InnerSpan), + CountIsName(&'a str, Range), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. @@ -228,8 +182,8 @@ pub struct ParseError { pub description: String, pub note: Option, pub label: String, - pub span: InnerSpan, - pub secondary_label: Option<(String, InnerSpan)>, + pub span: Range, + pub secondary_label: Option<(String, Range)>, pub suggestion: Suggestion, } @@ -240,12 +194,12 @@ pub enum Suggestion { UsePositional, /// Remove `r#` from identifier: /// `format!("{r#foo}")` -> `format!("{foo}")` - RemoveRawIdent(InnerSpan), + RemoveRawIdent(Range), /// Reorder format parameter: /// `format!("{foo:?#}")` -> `format!("{foo:#?}")` /// `format!("{foo:?x}")` -> `format!("{foo:x?}")` /// `format!("{foo:?X}")` -> `format!("{foo:X?}")` - ReorderFormatParameter(InnerSpan, String), + ReorderFormatParameter(Range, String), } /// The parser structure for interpreting the input format string. This is @@ -256,92 +210,94 @@ pub enum Suggestion { /// necessary there's probably lots of room for improvement performance-wise. pub struct Parser<'a> { mode: ParseMode, + /// Input to be parsed input: &'a str, - cur: std::iter::Peekable>, + /// Tuples of the span in the code snippet (input as written before being unescaped), the pos in input, and the char in input + input_vec: Vec<(Range, usize, char)>, + /// Index into input_vec + input_vec_index: usize, /// Error messages accumulated during parsing pub errors: Vec, /// Current position of implicit positional argument pointer pub curarg: usize, - /// `Some(raw count)` when the string is "raw", used to position spans correctly - style: Option, /// Start and end byte offset of every successfully parsed argument - pub arg_places: Vec, - /// Characters whose length has been changed from their in-code representation - width_map: Vec, + pub arg_places: Vec>, /// Span of the last opening brace seen, used for error reporting - last_opening_brace: Option, - /// Whether the source string is comes from `println!` as opposed to `format!` or `print!` - append_newline: bool, + last_open_brace: Option>, /// Whether this formatting string was written directly in the source. This controls whether we /// can use spans to refer into it and give better error messages. /// N.B: This does _not_ control whether implicit argument captures can be used. pub is_source_literal: bool, + /// Index to the end of the literal snippet + end_of_snippet: usize, /// Start position of the current line. cur_line_start: usize, /// Start and end byte offset of every line of the format string. Excludes /// newline characters and leading whitespace. - pub line_spans: Vec, + pub line_spans: Vec>, } impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; fn next(&mut self) -> Option> { - if let Some(&(pos, c)) = self.cur.peek() { - match c { + if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) { + match ch { '{' => { - let curr_last_brace = self.last_opening_brace; - let byte_pos = self.to_span_index(pos); - let lbrace_end = InnerOffset(byte_pos.0 + self.to_span_width(pos)); - self.last_opening_brace = Some(byte_pos.to(lbrace_end)); - self.cur.next(); - if self.consume('{') { - self.last_opening_brace = curr_last_brace; - - Some(Piece::Lit(self.string(pos + 1))) + self.input_vec_index += 1; + if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) { + self.input_vec_index += 1; + // double open brace escape: "{{" + // next state after this is either end-of-input or seen-a-brace + Some(Piece::Lit(self.string(i))) } else { - let arg = self.argument(lbrace_end); - if let Some(rbrace_pos) = self.consume_closing_brace(&arg) { + // single open brace + self.last_open_brace = Some(start..end); + let arg = self.argument(); + if let Some(close_brace_range) = self.consume_closing_brace(&arg) { if self.is_source_literal { - let lbrace_byte_pos = self.to_span_index(pos); - let rbrace_byte_pos = self.to_span_index(rbrace_pos); - - let width = self.to_span_width(rbrace_pos); - - self.arg_places.push( - lbrace_byte_pos.to(InnerOffset(rbrace_byte_pos.0 + width)), - ); + self.arg_places.push(start..close_brace_range.end); } - } else if let Some(&(_, maybe)) = self.cur.peek() { - match maybe { + } else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { + match c { '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(maybe), - _ => self.suggest_positional_arg_instead_of_captured_arg(arg), + '<' | '^' | '>' => self.suggest_format_align(c), + _ => { + self.suggest_positional_arg_instead_of_captured_arg(arg.clone()) + } } } Some(Piece::NextArgument(Box::new(arg))) } } '}' => { - self.cur.next(); - if self.consume('}') { - Some(Piece::Lit(self.string(pos + 1))) + self.input_vec_index += 1; + if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) { + self.input_vec_index += 1; + // double close brace escape: "}}" + // next state after this is either end-of-input or start + Some(Piece::Lit(self.string(i))) } else { - let err_pos = self.to_span_index(pos); - self.err_with_note( - "unmatched `}` found", - "unmatched `}`", - "if you intended to print `}`, you can escape it using `}}`", - err_pos.to(err_pos), - ); + // error: single close brace without corresponding open brace + self.errors.push(ParseError { + description: "unmatched `}` found".into(), + note: Some( + "if you intended to print `}`, you can escape it using `}}`".into(), + ), + label: "unmatched `}`".into(), + span: start..end, + secondary_label: None, + suggestion: Suggestion::None, + }); None } } - _ => Some(Piece::Lit(self.string(pos))), + _ => Some(Piece::Lit(self.string(idx))), } } else { + // end of input if self.is_source_literal { - let span = self.span(self.cur_line_start, self.input.len()); + let span = self.cur_line_start..self.end_of_snippet; if self.line_spans.last() != Some(&span) { self.line_spans.push(span); } @@ -352,71 +308,104 @@ impl<'a> Iterator for Parser<'a> { } impl<'a> Parser<'a> { - /// Creates a new parser for the given format string + /// Creates a new parser for the given unescaped input string and + /// optional code snippet (the input as written before being unescaped), + /// where `style` is `Some(nr_hashes)` when the snippet is a raw string with that many hashes. + /// If the input comes via `println` or `panic`, then it has a newline already appended, + /// which is reflected in the `appended_newline` parameter. pub fn new( - s: &'a str, + input: &'a str, style: Option, snippet: Option, - append_newline: bool, + appended_newline: bool, mode: ParseMode, - ) -> Parser<'a> { - let input_string_kind = find_width_map_from_snippet(s, snippet, style); - let (width_map, is_source_literal) = match input_string_kind { - InputStringKind::Literal { width_mappings } => (width_mappings, true), - InputStringKind::NotALiteral => (Vec::new(), false), + ) -> Self { + let quote_offset = style.map_or(1, |nr_hashes| nr_hashes + 2); + + let (is_source_literal, end_of_snippet, pre_input_vec) = if let Some(snippet) = snippet { + if let Some(nr_hashes) = style { + // snippet is a raw string, which starts with 'r', a number of hashes, and a quote + // and ends with a quote and the same number of hashes + (true, snippet.len() - nr_hashes - 1, vec![]) + } else { + // snippet is not a raw string + if snippet.starts_with('"') { + // snippet looks like an ordinary string literal + // check whether it is the escaped version of input + let without_quotes = &snippet[1..snippet.len() - 1]; + let (mut ok, mut vec) = (true, vec![]); + let mut chars = input.chars(); + unescape_unicode(without_quotes, Mode::Str, &mut |range, res| match res { + Ok(ch) if ok && chars.next().is_some_and(|c| ch == c) => { + vec.push((range, ch)); + } + _ => { + ok = false; + vec = vec![]; + } + }); + let end = vec.last().map(|(r, _)| r.end).unwrap_or(0); + if ok { + if appended_newline { + if chars.as_str() == "\n" { + vec.push((end..end + 1, '\n')); + (true, 1 + end, vec) + } else { + (false, snippet.len(), vec![]) + } + } else if chars.as_str() == "" { + (true, 1 + end, vec) + } else { + (false, snippet.len(), vec![]) + } + } else { + (false, snippet.len(), vec![]) + } + } else { + // snippet is not a raw string and does not start with '"' + (false, snippet.len(), vec![]) + } + } + } else { + // snippet is None + (false, input.len() - if appended_newline { 1 } else { 0 }, vec![]) + }; + + let input_vec: Vec<(Range, usize, char)> = if pre_input_vec.is_empty() { + // Snippet is *not* input before unescaping, so spans pointing at it will be incorrect. + // This can happen with proc macros that respan generated literals. + input + .char_indices() + .map(|(idx, c)| { + let i = idx + quote_offset; + (i..i + c.len_utf8(), idx, c) + }) + .collect() + } else { + // Snippet is input before unescaping + input + .char_indices() + .zip(pre_input_vec) + .map(|((i, c), (r, _))| (r.start + quote_offset..r.end + quote_offset, i, c)) + .collect() }; Parser { mode, - input: s, - cur: s.char_indices().peekable(), + input, + input_vec, + input_vec_index: 0, errors: vec![], curarg: 0, - style, arg_places: vec![], - width_map, - last_opening_brace: None, - append_newline, + last_open_brace: None, is_source_literal, - cur_line_start: 0, + end_of_snippet, + cur_line_start: quote_offset, line_spans: vec![], } } - /// Notifies of an error. The message doesn't actually need to be of type - /// String, but I think it does when this eventually uses conditions so it - /// might as well start using it now. - fn err(&mut self, description: impl Into, label: impl Into, span: InnerSpan) { - self.errors.push(ParseError { - description: description.into(), - note: None, - label: label.into(), - span, - secondary_label: None, - suggestion: Suggestion::None, - }); - } - - /// Notifies of an error. The message doesn't actually need to be of type - /// String, but I think it does when this eventually uses conditions so it - /// might as well start using it now. - fn err_with_note( - &mut self, - description: impl Into, - label: impl Into, - note: impl Into, - span: InnerSpan, - ) { - self.errors.push(ParseError { - description: description.into(), - note: Some(note.into()), - label: label.into(), - span, - secondary_label: None, - suggestion: Suggestion::None, - }); - } - /// Optionally consumes the specified character. If the character is not at /// the current position, then the current iterator isn't moved and `false` is /// returned, otherwise the character is consumed and `true` is returned. @@ -428,94 +417,56 @@ impl<'a> Parser<'a> { /// the current position, then the current iterator isn't moved and `None` is /// returned, otherwise the character is consumed and the current position is /// returned. - fn consume_pos(&mut self, c: char) -> Option { - if let Some(&(pos, maybe)) = self.cur.peek() { - if c == maybe { - self.cur.next(); - return Some(pos); + fn consume_pos(&mut self, ch: char) -> Option<(Range, usize)> { + if let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { + if ch == *c { + self.input_vec_index += 1; + return Some((r.clone(), *i)); } } None } - fn remap_pos(&self, mut pos: usize) -> InnerOffset { - for width in &self.width_map { - if pos > width.position { - pos += width.before - width.after; - } else if pos == width.position && width.after == 0 { - pos += width.before; - } else { - break; - } - } - - InnerOffset(pos) - } - - fn to_span_index(&self, pos: usize) -> InnerOffset { - // This handles the raw string case, the raw argument is the number of # - // in r###"..."### (we need to add one because of the `r`). - let raw = self.style.map_or(0, |raw| raw + 1); - let pos = self.remap_pos(pos); - InnerOffset(raw + pos.0 + 1) - } - - fn to_span_width(&self, pos: usize) -> usize { - let pos = self.remap_pos(pos); - match self.width_map.iter().find(|w| w.position == pos.0) { - Some(w) => w.before, - None => 1, - } - } - - fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan { - let start = self.to_span_index(start_pos); - let end = self.to_span_index(end_pos); - start.to(end) - } - /// Forces consumption of the specified character. If the character is not /// found, an error is emitted. - fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option { + fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option> { self.ws(); - let pos; - let description; - - if let Some(&(peek_pos, maybe)) = self.cur.peek() { - if maybe == '}' { - self.cur.next(); - return Some(peek_pos); + let (range, description) = if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) + { + if *c == '}' { + self.input_vec_index += 1; + return Some(r.clone()); } - - pos = peek_pos; - description = format!("expected `}}`, found `{}`", maybe.escape_debug()); + // or r.clone()? + (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug())) } else { - description = "expected `}` but string was terminated".to_owned(); - // point at closing `"` - pos = self.input.len() - if self.append_newline { 1 } else { 0 }; - } + ( + // point at closing `"` + self.end_of_snippet..self.end_of_snippet, + "expected `}` but string was terminated".to_owned(), + ) + }; - let pos = self.to_span_index(pos); - - let label = "expected `}`".to_owned(); let (note, secondary_label) = if arg.format.fill == Some('}') { ( Some("the character `}` is interpreted as a fill character because of the `:` that precedes it".to_owned()), - arg.format.fill_span.map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)), + arg.format.fill_span.clone().map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)), ) } else { ( Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace.map(|sp| ("because of this opening brace".to_owned(), sp)), + self.last_open_brace + .clone() + .map(|sp| ("because of this opening brace".to_owned(), sp)), ) }; self.errors.push(ParseError { description, note, - label, - span: pos.to(pos), + label: "expected `}`".to_owned(), + span: range.start..range.start, secondary_label, suggestion: Suggestion::None, }); @@ -525,28 +476,30 @@ impl<'a> Parser<'a> { /// Consumes all whitespace characters until the first non-whitespace character fn ws(&mut self) { - while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {} + let rest = &self.input_vec[self.input_vec_index..]; + let step = rest.iter().position(|&(_, _, c)| !c.is_whitespace()).unwrap_or(rest.len()); + self.input_vec_index += step; } /// Parses all of a string which is to be considered a "raw literal" in a /// format string. This is everything outside of the braces. fn string(&mut self, start: usize) -> &'a str { - // we may not consume the character, peek the iterator - while let Some(&(pos, c)) = self.cur.peek() { + while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { match c { '{' | '}' => { - return &self.input[start..pos]; + return &self.input[start..*i]; } '\n' if self.is_source_literal => { - self.line_spans.push(self.span(self.cur_line_start, pos)); - self.cur_line_start = pos + 1; - self.cur.next(); + self.input_vec_index += 1; + self.line_spans.push(self.cur_line_start..r.start); + self.cur_line_start = r.end; } _ => { - if self.is_source_literal && pos == self.cur_line_start && c.is_whitespace() { - self.cur_line_start = pos + c.len_utf8(); + self.input_vec_index += 1; + if self.is_source_literal && r.start == self.cur_line_start && c.is_whitespace() + { + self.cur_line_start = r.end; } - self.cur.next(); } } } @@ -554,15 +507,13 @@ impl<'a> Parser<'a> { } /// Parses an `Argument` structure, or what's contained within braces inside the format string. - fn argument(&mut self, start: InnerOffset) -> Argument<'a> { - let pos = self.position(); + fn argument(&mut self) -> Argument<'a> { + let start_idx = self.input_vec_index; - let end = self - .cur - .clone() - .find(|(_, ch)| !ch.is_whitespace()) - .map_or(start, |(end, _)| self.to_span_index(end)); - let position_span = start.to(end); + let position = self.position(); + self.ws(); + + let end_idx = self.input_vec_index; let format = match self.mode { ParseMode::Format => self.format(), @@ -570,16 +521,15 @@ impl<'a> Parser<'a> { }; // Resolve position after parsing format spec. - let pos = match pos { - Some(position) => position, - None => { - let i = self.curarg; - self.curarg += 1; - ArgumentImplicitlyIs(i) - } - }; + let position = position.unwrap_or_else(|| { + let i = self.curarg; + self.curarg += 1; + ArgumentImplicitlyIs(i) + }); - Argument { position: pos, position_span, format } + let position_span = + self.input_vec_index2range(start_idx).start..self.input_vec_index2range(end_idx).start; + Argument { position, position_span, format } } /// Parses a positional argument for a format. This could either be an @@ -590,23 +540,26 @@ impl<'a> Parser<'a> { if let Some(i) = self.integer() { Some(ArgumentIs(i.into())) } else { - match self.cur.peek() { - Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { + match self.input_vec.get(self.input_vec_index) { + Some((range, _, c)) if rustc_lexer::is_id_start(*c) => { + let start = range.start; let word = self.word(); // Recover from `r#ident` in format strings. // FIXME: use a let chain if word == "r" { - if let Some((pos, '#')) = self.cur.peek() { - if self.input[pos + 1..] - .chars() - .next() - .is_some_and(rustc_lexer::is_id_start) + if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) { + if self + .input_vec + .get(self.input_vec_index + 1) + .is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c)) { - self.cur.next(); + self.input_vec_index += 1; + let prefix_end = r.end; let word = self.word(); - let prefix_span = self.span(lo, lo + 2); - let full_span = self.span(lo, lo + 2 + word.len()); + let prefix_span = start..prefix_end; + let full_span = + start..self.input_vec_index2range(self.input_vec_index).start; self.errors.insert(0, ParseError { description: "raw identifiers are not supported".to_owned(), note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()), @@ -622,7 +575,6 @@ impl<'a> Parser<'a> { Some(ArgumentNamed(word)) } - // This is an `ArgumentNext`. // Record the fact and do the resolution after parsing the // format spec, to make things like `{:.*}` work. @@ -631,8 +583,16 @@ impl<'a> Parser<'a> { } } - fn current_pos(&mut self) -> usize { - if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() } + fn input_vec_index2pos(&self, index: usize) -> usize { + if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() } + } + + fn input_vec_index2range(&self, index: usize) -> Range { + if let Some((r, _, _)) = self.input_vec.get(index) { + r.clone() + } else { + self.end_of_snippet..self.end_of_snippet + } } /// Parses a format specifier at the current position, returning all of the @@ -658,11 +618,11 @@ impl<'a> Parser<'a> { } // fill character - if let Some(&(idx, c)) = self.cur.peek() { - if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) { + if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) { + self.input_vec_index += 1; spec.fill = Some(c); - spec.fill_span = Some(self.span(idx, idx + 1)); - self.cur.next(); + spec.fill_span = Some(r.clone()); } } // Alignment @@ -686,14 +646,14 @@ impl<'a> Parser<'a> { // Width and precision let mut havewidth = false; - if self.consume('0') { + if let Some((range, _)) = self.consume_pos('0') { // small ambiguity with '0$' as a format string. In theory this is a // '0' flag and then an ill-formatted format string with just a '$' // and no count, but this is better if we instead interpret this as // no '0' flag and '0$' as the width instead. - if let Some(end) = self.consume_pos('$') { + if let Some((r, _)) = self.consume_pos('$') { spec.width = CountIsParam(0); - spec.width_span = Some(self.span(end - 1, end + 1)); + spec.width_span = Some(range.start..r.end); havewidth = true; } else { spec.zero_pad = true; @@ -701,15 +661,15 @@ impl<'a> Parser<'a> { } if !havewidth { - let start = self.current_pos(); - spec.width = self.count(start); + let start_idx = self.input_vec_index; + spec.width = self.count(); if spec.width != CountImplied { - let end = self.current_pos(); - spec.width_span = Some(self.span(start, end)); + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.width_span = Some(self.input_vec_index2range(start_idx).start..end); } } - if let Some(start) = self.consume_pos('.') { + if let Some((range, _)) = self.consume_pos('.') { if self.consume('*') { // Resolve `CountIsNextParam`. // We can do this immediately as `position` is resolved later. @@ -717,13 +677,13 @@ impl<'a> Parser<'a> { self.curarg += 1; spec.precision = CountIsStar(i); } else { - spec.precision = self.count(start + 1); + spec.precision = self.count(); } - let end = self.current_pos(); - spec.precision_span = Some(self.span(start, end)); + spec.precision_span = + Some(range.start..self.input_vec_index2range(self.input_vec_index).start); } - let ty_span_start = self.current_pos(); + let start_idx = self.input_vec_index; // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { @@ -739,19 +699,33 @@ impl<'a> Parser<'a> { } else { spec.ty = "X"; } - } else if self.consume('?') { + } else if let Some((range, _)) = self.consume_pos('?') { spec.ty = "?"; - if let Some(&(_, maybe)) = self.cur.peek() { - match maybe { - '#' | 'x' | 'X' => self.suggest_format_parameter(maybe), + if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) { + match c { + '#' | 'x' | 'X' => self.errors.insert( + 0, + ParseError { + description: format!("expected `}}`, found `{c}`"), + note: None, + label: "expected `'}'`".into(), + span: r.clone(), + secondary_label: None, + suggestion: Suggestion::ReorderFormatParameter( + range.start..r.end, + format!("{c}?"), + ), + }, + ), _ => (), } } } else { spec.ty = self.word(); if !spec.ty.is_empty() { - let ty_span_end = self.current_pos(); - spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); + let start = self.input_vec_index2range(start_idx).start; + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.ty_span = Some(start..end); } } spec @@ -779,11 +753,12 @@ impl<'a> Parser<'a> { return spec; } - let ty_span_start = self.current_pos(); + let start_idx = self.input_vec_index; spec.ty = self.word(); if !spec.ty.is_empty() { - let ty_span_end = self.current_pos(); - spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); + let start = self.input_vec_index2range(start_idx).start; + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.ty_span = Some(start..end); } spec @@ -792,55 +767,58 @@ impl<'a> Parser<'a> { /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self, start: usize) -> Count<'a> { + fn count(&mut self) -> Count<'a> { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { - let tmp = self.cur.clone(); + let start_idx = self.input_vec_index; let word = self.word(); if word.is_empty() { - self.cur = tmp; CountImplied - } else if let Some(end) = self.consume_pos('$') { - let name_span = self.span(start, end); - CountIsName(word, name_span) + } else if let Some((r, _)) = self.consume_pos('$') { + CountIsName(word, self.input_vec_index2range(start_idx).start..r.start) } else { - self.cur = tmp; + self.input_vec_index = start_idx; CountImplied } } } - /// Parses a word starting at the current position. A word is the same as + /// Parses a word starting at the current position. A word is the same as a /// Rust identifier, except that it can't start with `_` character. fn word(&mut self) -> &'a str { - let start = match self.cur.peek() { - Some(&(pos, c)) if rustc_lexer::is_id_start(c) => { - self.cur.next(); - pos + let index = self.input_vec_index; + match self.input_vec.get(self.input_vec_index) { + Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => { + self.input_vec_index += 1; + (r.start, i) } _ => { return ""; } }; - let mut end = None; - while let Some(&(pos, c)) = self.cur.peek() { - if rustc_lexer::is_id_continue(c) { - self.cur.next(); + let (err_end, end): (usize, usize) = loop { + if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) { + if rustc_lexer::is_id_continue(c) { + self.input_vec_index += 1; + } else { + break (r.start, i); + } } else { - end = Some(pos); - break; + break (self.end_of_snippet, self.input.len()); } - } - let end = end.unwrap_or(self.input.len()); - let word = &self.input[start..end]; + }; + + let word = &self.input[self.input_vec_index2pos(index)..end]; if word == "_" { - self.err_with_note( - "invalid argument name `_`", - "invalid argument name", - "argument name cannot be a single underscore", - self.span(start, end), - ); + self.errors.push(ParseError { + description: "invalid argument name `_`".into(), + note: Some("argument name cannot be a single underscore".into()), + label: "invalid argument name".into(), + span: self.input_vec_index2range(index).start..err_end, + secondary_label: None, + suggestion: Suggestion::None, + }); } word } @@ -849,9 +827,10 @@ impl<'a> Parser<'a> { let mut cur: u16 = 0; let mut found = false; let mut overflow = false; - let start = self.current_pos(); - while let Some(&(_, c)) = self.cur.peek() { + let start_index = self.input_vec_index; + while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { if let Some(i) = c.to_digit(10) { + self.input_vec_index += 1; let (tmp, mul_overflow) = cur.overflowing_mul(10); let (tmp, add_overflow) = tmp.overflowing_add(i as u16); if mul_overflow || add_overflow { @@ -859,40 +838,42 @@ impl<'a> Parser<'a> { } cur = tmp; found = true; - self.cur.next(); } else { break; } } if overflow { - let end = self.current_pos(); - let overflowed_int = &self.input[start..end]; - self.err( - format!( + let overflowed_int = &self.input[self.input_vec_index2pos(start_index) + ..self.input_vec_index2pos(self.input_vec_index)]; + self.errors.push(ParseError { + description: format!( "integer `{}` does not fit into the type `u16` whose range is `0..={}`", overflowed_int, u16::MAX ), - "integer out of range for `u16`", - self.span(start, end), - ); + note: None, + label: "integer out of range for `u16`".into(), + span: self.input_vec_index2range(start_index).start + ..self.input_vec_index2range(self.input_vec_index).end, + secondary_label: None, + suggestion: Suggestion::None, + }); } found.then_some(cur) } fn suggest_format_debug(&mut self) { - if let (Some(pos), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { + if let (Some((range, _)), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { let word = self.word(); - let pos = self.to_span_index(pos); self.errors.insert( 0, ParseError { description: "expected format parameter to occur after `:`".to_owned(), note: Some(format!("`?` comes after `:`, try `{}:{}` instead", word, "?")), label: "expected `?` to occur after `:`".to_owned(), - span: pos.to(pos), + span: range, secondary_label: None, suggestion: Suggestion::None, }, @@ -901,15 +882,14 @@ impl<'a> Parser<'a> { } fn suggest_format_align(&mut self, alignment: char) { - if let Some(pos) = self.consume_pos(alignment) { - let pos = self.to_span_index(pos); + if let Some((range, _)) = self.consume_pos(alignment) { self.errors.insert( 0, ParseError { description: "expected format parameter to occur after `:`".to_owned(), note: None, label: format!("expected `{}` to occur after `:`", alignment), - span: pos.to(pos), + span: range, secondary_label: None, suggestion: Suggestion::None, }, @@ -923,10 +903,8 @@ impl<'a> Parser<'a> { return; } - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); + if let Some((_range, _pos)) = self.consume_pos('.') { + let field = self.argument(); // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any // deeper nesting, or another type of expression, like method calls, are not supported if !self.consume('}') { @@ -941,10 +919,7 @@ impl<'a> Parser<'a> { description: "field access isn't supported".to_string(), note: None, label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), + span: arg.position_span.start..field.position_span.end, secondary_label: None, suggestion: Suggestion::UsePositional, }, @@ -957,10 +932,7 @@ impl<'a> Parser<'a> { description: "tuple index access isn't supported".to_string(), note: None, label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), + span: arg.position_span.start..field.position_span.end, secondary_label: None, suggestion: Suggestion::UsePositional, }, @@ -971,164 +943,6 @@ impl<'a> Parser<'a> { } } } - - fn suggest_format_parameter(&mut self, c: char) { - let replacement = match c { - '#' => "#?", - 'x' => "x?", - 'X' => "X?", - _ => return, - }; - let Some(pos) = self.consume_pos(c) else { - return; - }; - - let span = self.span(pos - 1, pos + 1); - let pos = self.to_span_index(pos); - - self.errors.insert( - 0, - ParseError { - description: format!("expected `}}`, found `{c}`"), - note: None, - label: "expected `'}'`".into(), - span: pos.to(pos), - secondary_label: None, - suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")), - }, - ) - } -} - -/// Finds the indices of all characters that have been processed and differ between the actual -/// written code (code snippet) and the `InternedString` that gets processed in the `Parser` -/// in order to properly synthesise the intra-string `Span`s for error diagnostics. -fn find_width_map_from_snippet( - input: &str, - snippet: Option, - str_style: Option, -) -> InputStringKind { - let snippet = match snippet { - Some(ref s) if s.starts_with('"') || s.starts_with("r\"") || s.starts_with("r#") => s, - _ => return InputStringKind::NotALiteral, - }; - - if str_style.is_some() { - return InputStringKind::Literal { width_mappings: Vec::new() }; - } - - // Strip quotes. - let snippet = &snippet[1..snippet.len() - 1]; - - // Macros like `println` add a newline at the end. That technically doesn't make them "literals" anymore, but it's fine - // since we will never need to point our spans there, so we lie about it here by ignoring it. - // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines. - // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up. - // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up. - let input_no_nl = input.trim_end_matches('\n'); - let Some(unescaped) = unescape_string(snippet) else { - return InputStringKind::NotALiteral; - }; - - let unescaped_no_nl = unescaped.trim_end_matches('\n'); - - if unescaped_no_nl != input_no_nl { - // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect. - // This can for example happen with proc macros that respan generated literals. - return InputStringKind::NotALiteral; - } - - let mut s = snippet.char_indices(); - let mut width_mappings = vec![]; - while let Some((pos, c)) = s.next() { - match (c, s.clone().next()) { - // skip whitespace and empty lines ending in '\\' - ('\\', Some((_, '\n'))) => { - let _ = s.next(); - let mut width = 2; - - while let Some((_, c)) = s.clone().next() { - if matches!(c, ' ' | '\n' | '\t') { - width += 1; - let _ = s.next(); - } else { - break; - } - } - - width_mappings.push(InnerWidthMapping::new(pos, width, 0)); - } - ('\\', Some((_, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { - width_mappings.push(InnerWidthMapping::new(pos, 2, 1)); - let _ = s.next(); - } - ('\\', Some((_, 'x'))) => { - // consume `\xAB` literal - s.nth(2); - width_mappings.push(InnerWidthMapping::new(pos, 4, 1)); - } - ('\\', Some((_, 'u'))) => { - let mut width = 2; - let _ = s.next(); - - if let Some((_, next_c)) = s.next() { - if next_c == '{' { - // consume up to 6 hexanumeric chars - let digits_len = - s.clone().take(6).take_while(|(_, c)| c.is_ascii_hexdigit()).count(); - - let len_utf8 = s - .as_str() - .get(..digits_len) - .and_then(|digits| u32::from_str_radix(digits, 16).ok()) - .and_then(char::from_u32) - .map_or(1, char::len_utf8); - - // Skip the digits, for chars that encode to more than 1 utf-8 byte - // exclude as many digits as it is greater than 1 byte - // - // So for a 3 byte character, exclude 2 digits - let required_skips = digits_len.saturating_sub(len_utf8.saturating_sub(1)); - - // skip '{' and '}' also - width += required_skips + 2; - - s.nth(digits_len); - } else if next_c.is_ascii_hexdigit() { - width += 1; - - // We suggest adding `{` and `}` when appropriate, accept it here as if - // it were correct - let mut i = 0; // consume up to 6 hexanumeric chars - while let (Some((_, c)), _) = (s.next(), i < 6) { - if c.is_ascii_hexdigit() { - width += 1; - } else { - break; - } - i += 1; - } - } - } - - width_mappings.push(InnerWidthMapping::new(pos, width, 1)); - } - _ => {} - } - } - - InputStringKind::Literal { width_mappings } -} - -fn unescape_string(string: &str) -> Option { - let mut buf = String::new(); - let mut ok = true; - unescape_unicode(string, Mode::Str, &mut |_, unescaped_char| match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => ok = false, - }); - - ok.then_some(buf) } // Assert a reasonable size for `Piece` diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index cc8a0069c4ec..e6a7f24034ad 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -41,7 +41,6 @@ fn simple() { same("}}", &[Lit("}")]); same("\\}}", &[Lit("\\"), Lit("}")]); } - #[test] fn invalid01() { musterr("{") @@ -79,23 +78,48 @@ fn invalid_precision() { } #[test] -fn format_nothing() { +fn format_empty() { same( "{}", &[NextArgument(Box::new(Argument { position: ArgumentImplicitlyIs(0), - position_span: InnerSpan { start: 2, end: 2 }, + position_span: 2..2, format: fmtdflt(), }))], ); } #[test] +fn format_tab_empty() { + let fmt_pre = r###""\t{}""###; + let fmt = "\t{}"; + let parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); + assert_eq!( + parser.collect::>>(), + &[ + Lit("\t"), + NextArgument(Box::new(Argument { + position: ArgumentImplicitlyIs(0), + position_span: 4..4, + format: fmtdflt(), + })) + ], + ); +} +#[test] +fn format_open_brace_tab() { + let fmt_pre = r###""{\t""###; + let fmt = "{\t"; + let mut parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); + let _ = parser.by_ref().collect::>>(); + assert_eq!(parser.errors[0].span, 4..4); +} +#[test] fn format_position() { same( "{3}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: fmtdflt(), }))], ); @@ -106,7 +130,7 @@ fn format_position_nothing_else() { "{3:}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: fmtdflt(), }))], ); @@ -117,18 +141,54 @@ fn format_named() { "{name}", &[NextArgument(Box::new(Argument { position: ArgumentNamed("name"), - position_span: InnerSpan { start: 2, end: 6 }, + position_span: 2..6, format: fmtdflt(), }))], ) } #[test] +fn format_named_space_nothing() { + same( + "{name} {}", + &[ + NextArgument(Box::new(Argument { + position: ArgumentNamed("name"), + position_span: 2..6, + format: fmtdflt(), + })), + Lit(" "), + NextArgument(Box::new(Argument { + position: ArgumentImplicitlyIs(0), + position_span: 9..9, + format: fmtdflt(), + })), + ], + ) +} +#[test] +fn format_raw() { + let snippet = r###"r#"assertion `left {op} right` failed"#"###.into(); + let source = r#"assertion `left {op} right` failed"#; + + let parser = Parser::new(source, Some(1), Some(snippet), true, ParseMode::Format); + let expected = &[ + Lit("assertion `left "), + NextArgument(Box::new(Argument { + position: ArgumentNamed("op"), + position_span: 20..22, + format: fmtdflt(), + })), + Lit(" right` failed"), + ]; + assert_eq!(parser.collect::>>(), expected); +} +#[test] fn format_type() { same( "{3:x}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: None, fill_span: None, @@ -153,7 +213,7 @@ fn format_align_fill() { "{3:>}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: None, fill_span: None, @@ -175,10 +235,10 @@ fn format_align_fill() { "{3:0<}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: Some('0'), - fill_span: Some(InnerSpan::new(4, 5)), + fill_span: Some(4..5), align: AlignLeft, sign: None, alternate: false, @@ -197,10 +257,10 @@ fn format_align_fill() { "{3:*>>(), + &[Lit("\n .intel_syntax noprefix\n nop")] + ); + assert_eq!(parser.line_spans, &[2..2, 11..33, 42..45]); +} +#[test] +fn asm_concat() { + let asm_pre = r###"concat!("invalid", "_", "instruction")"###; + let asm = "invalid_instruction"; + let mut parser = Parser::new(asm, None, Some(asm_pre.into()), false, ParseMode::InlineAsm); + assert!(!parser.is_source_literal); + assert_eq!(parser.by_ref().collect::>>(), &[Lit(asm)]); + assert_eq!(parser.line_spans, &[]); +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index f835406122b8..d8b90844b7d2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -1,11 +1,12 @@ use std::fmt; +use std::ops::Range; use errors::*; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_parse_format::{ - Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, - Piece as RpfPiece, Position, + Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, + Position, }; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; @@ -173,7 +174,7 @@ impl FormatString { pieces.push(Piece::Lit(lit.into())); } RpfPiece::NextArgument(arg) => { - warn_on_format_spec(arg.format, &mut warnings, span); + warn_on_format_spec(arg.format.clone(), &mut warnings, span); let arg = parse_arg(&arg, ctx, &mut warnings, span); pieces.push(Piece::Arg(arg)); } @@ -233,7 +234,7 @@ fn parse_arg<'tcx>( | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; let trait_name = tcx.item_ident(*trait_def_id); let generics = tcx.generics_of(trait_def_id); - let span = slice_span(input_span, arg.position_span); + let span = slice_span(input_span, arg.position_span.clone()); match arg.position { // Something like "hello {name}" @@ -335,14 +336,12 @@ fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec, } } -/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other -fn slice_span(input: Span, inner: InnerSpan) -> Span { - let InnerSpan { start, end } = inner; +fn slice_span(input: Span, range: Range) -> Span { let span = input.data(); Span::new( - span.lo + BytePos::from_usize(start), - span.lo + BytePos::from_usize(end), + span.lo + BytePos::from_usize(range.start), + span.lo + BytePos::from_usize(range.end), span.ctxt, span.parent, ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs index 9ef03065651a..d36e5205c739 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs @@ -224,7 +224,7 @@ impl ExprCollector<'_> { curarg = parser.curarg; - let to_span = |inner_span: rustc_parse_format::InnerSpan| { + let to_span = |inner_span: std::ops::Range| { is_direct_literal.then(|| { TextRange::new( inner_span.start.try_into().unwrap(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 2fd21bb0ed3a..f27a4062a63b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -214,7 +214,7 @@ pub(crate) fn parse( }; } - let to_span = |inner_span: parse::InnerSpan| { + let to_span = |inner_span: std::ops::Range| { is_source_literal.then(|| { TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap()) }) @@ -297,7 +297,7 @@ pub(crate) fn parse( unfinished_literal.clear(); } - let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s)); + let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); placeholder_index += 1; let position_span = to_span(position_span); From 4d5a1acebfe031ca2af75786295a2cd2a0633943 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 12 Apr 2025 17:52:55 +1000 Subject: [PATCH 276/302] coverage: Only merge adjacent coverage spans This also removes some manipulation of the function signature span that only made sense in the context of merging non-adjacent spans. --- .../src/coverage/mappings.rs | 2 +- .../rustc_mir_transform/src/coverage/mod.rs | 30 +- .../rustc_mir_transform/src/coverage/spans.rs | 26 +- tests/coverage/abort.cov-map | 28 +- tests/coverage/assert-ne.cov-map | 19 +- tests/coverage/assert.cov-map | 24 +- tests/coverage/assert_not.cov-map | 17 +- tests/coverage/async.cov-map | 181 +++++---- tests/coverage/async.coverage | 14 +- tests/coverage/async2.cov-map | 79 ++-- tests/coverage/async2.coverage | 4 +- tests/coverage/async_block.cov-map | 19 +- tests/coverage/async_closure.cov-map | 34 +- tests/coverage/async_closure.coverage | 3 +- tests/coverage/attr/impl.cov-map | 21 +- tests/coverage/attr/module.cov-map | 21 +- tests/coverage/attr/nested.cov-map | 20 +- tests/coverage/attr/off-on-sandwich.cov-map | 30 +- .../coverage/attr/trait-impl-inherit.cov-map | 9 +- tests/coverage/await_ready.cov-map | 13 +- tests/coverage/await_ready.coverage | 2 +- tests/coverage/bad_counter_ids.cov-map | 100 +++-- tests/coverage/bench.cov-map | 7 +- tests/coverage/branch/generics.cov-map | 27 +- tests/coverage/branch/guard.cov-map | 15 +- tests/coverage/branch/guard.coverage | 2 +- tests/coverage/branch/if-let.cov-map | 49 ++- tests/coverage/branch/if.cov-map | 39 +- tests/coverage/branch/lazy-boolean.cov-map | 58 ++- tests/coverage/branch/let-else.cov-map | 17 +- tests/coverage/branch/match-arms.cov-map | 85 ++-- tests/coverage/branch/match-trivial.cov-map | 29 +- tests/coverage/branch/match-trivial.coverage | 4 +- tests/coverage/branch/no-mir-spans.cov-map | 16 +- tests/coverage/branch/while.cov-map | 48 ++- tests/coverage/closure.cov-map | 377 +++++++++++------- tests/coverage/closure.coverage | 74 ++-- tests/coverage/closure_bug.cov-map | 45 ++- tests/coverage/closure_bug.coverage | 2 +- tests/coverage/closure_macro.cov-map | 46 ++- tests/coverage/closure_macro.coverage | 2 +- tests/coverage/closure_macro_async.cov-map | 50 ++- tests/coverage/closure_macro_async.coverage | 2 +- tests/coverage/closure_unit_return.cov-map | 39 +- tests/coverage/closure_unit_return.coverage | 4 +- tests/coverage/condition/conditions.cov-map | 64 +-- tests/coverage/conditions.cov-map | 199 +++++---- tests/coverage/continue.cov-map | 95 +++-- tests/coverage/continue.coverage | 4 +- tests/coverage/coroutine.cov-map | 37 +- tests/coverage/coverage_attr_closure.cov-map | 36 +- tests/coverage/dead_code.cov-map | 39 +- tests/coverage/dead_code.coverage | 24 +- tests/coverage/drop_trait.cov-map | 40 +- tests/coverage/drop_trait.coverage | 8 +- tests/coverage/fn_sig_into_try.cov-map | 48 ++- tests/coverage/fn_sig_into_try.coverage | 16 +- tests/coverage/generic-unused-impl.cov-map | 17 +- tests/coverage/generics.cov-map | 107 +++-- tests/coverage/generics.coverage | 8 +- tests/coverage/holes.cov-map | 76 ++-- tests/coverage/holes.coverage | 18 +- tests/coverage/if.cov-map | 13 +- tests/coverage/if.coverage | 20 +- tests/coverage/if_else.cov-map | 13 +- tests/coverage/if_else.coverage | 10 +- tests/coverage/if_not.cov-map | 9 +- tests/coverage/if_not.coverage | 2 +- tests/coverage/ignore_run.cov-map | 7 +- tests/coverage/inline-dead.cov-map | 39 +- tests/coverage/inline-dead.coverage | 2 +- tests/coverage/inline.cov-map | 111 ++++-- tests/coverage/inline.coverage | 2 +- tests/coverage/inner_items.cov-map | 52 ++- tests/coverage/inner_items.coverage | 10 +- tests/coverage/issue-83601.cov-map | 27 +- tests/coverage/issue-84561.cov-map | 120 ++++-- tests/coverage/issue-84561.coverage | 14 +- tests/coverage/issue-85461.cov-map | 9 +- tests/coverage/issue-93054.cov-map | 19 +- tests/coverage/lazy_boolean.cov-map | 18 +- tests/coverage/lazy_boolean.coverage | 8 +- tests/coverage/let_else_loop.cov-map | 27 +- tests/coverage/long_and_wide.cov-map | 32 +- tests/coverage/long_and_wide.coverage | 262 ++++++------ tests/coverage/loop-break.cov-map | 4 +- tests/coverage/loop_break_value.cov-map | 9 +- tests/coverage/loop_break_value.coverage | 4 +- tests/coverage/loops_branches.cov-map | 49 ++- tests/coverage/macro_in_closure.cov-map | 13 +- tests/coverage/macro_name_span.cov-map | 15 +- tests/coverage/match_or_pattern.cov-map | 17 +- tests/coverage/match_or_pattern.coverage | 8 +- tests/coverage/mcdc/condition-limit.cov-map | 17 +- tests/coverage/mcdc/if.cov-map | 95 +++-- tests/coverage/mcdc/if.coverage | 8 +- .../coverage/mcdc/inlined_expressions.cov-map | 9 +- tests/coverage/mcdc/nested_if.cov-map | 36 +- tests/coverage/mcdc/nested_if.coverage | 6 +- tests/coverage/mcdc/non_control_flow.cov-map | 63 +-- tests/coverage/nested_loops.cov-map | 68 ++-- tests/coverage/no-core.cov-map | 7 +- tests/coverage/no_cov_crate.cov-map | 79 ++-- tests/coverage/no_cov_crate.coverage | 4 +- tests/coverage/no_spans.cov-map | 14 +- tests/coverage/no_spans.coverage | 21 +- tests/coverage/no_spans.rs | 13 +- tests/coverage/no_spans_if_not.cov-map | 17 +- tests/coverage/overflow.cov-map | 41 +- tests/coverage/panic_unwind.cov-map | 28 +- tests/coverage/partial_eq.cov-map | 23 +- tests/coverage/partial_eq.coverage | 8 +- tests/coverage/simple_loop.cov-map | 22 +- tests/coverage/simple_loop.coverage | 12 +- tests/coverage/simple_match.cov-map | 17 +- tests/coverage/simple_match.coverage | 8 +- tests/coverage/sort_groups.cov-map | 75 ++-- tests/coverage/test_harness.cov-map | 14 +- tests/coverage/tight_inf_loop.cov-map | 12 +- tests/coverage/trivial.cov-map | 7 +- tests/coverage/try_error_result.cov-map | 254 +++++++----- tests/coverage/try_error_result.coverage | 12 +- tests/coverage/unicode.cov-map | 24 +- tests/coverage/unicode.coverage | 2 +- tests/coverage/unreachable.cov-map | 18 +- tests/coverage/unused.cov-map | 67 ++-- tests/coverage/unused_mod.cov-map | 18 +- tests/coverage/uses_crate.cov-map | 52 ++- tests/coverage/uses_crate.coverage | 10 +- tests/coverage/uses_inline_crate.cov-map | 69 +++- tests/coverage/uses_inline_crate.coverage | 20 +- tests/coverage/while.cov-map | 10 +- tests/coverage/while_early_ret.cov-map | 21 +- tests/coverage/yield.cov-map | 55 ++- ...ch_match_arms.main.InstrumentCoverage.diff | 19 +- ...ument_coverage.bar.InstrumentCoverage.diff | 4 +- ...ment_coverage.main.InstrumentCoverage.diff | 2 +- ...rage_cleanup.main.CleanupPostBorrowck.diff | 3 +- ...erage_cleanup.main.InstrumentCoverage.diff | 3 +- 139 files changed, 2982 insertions(+), 1919 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 73bd2d0705e1..b4b4d0416fb9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -91,7 +91,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( // When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need // to give the same treatment to _all_ functions, because `llvm-cov` // seems to ignore functions that don't have any ordinary code spans. - if let Some(span) = hir_info.fn_sig_span_extended { + if let Some(span) = hir_info.fn_sig_span { code_mappings.push(CodeMapping { span, bcb: START_BCB }); } } else { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index f2e8f9e1bcd6..702c62eddc7f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -268,9 +268,9 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb struct ExtractedHirInfo { function_source_hash: u64, is_async_fn: bool, - /// The span of the function's signature, extended to the start of `body_span`. + /// The span of the function's signature, if available. /// Must have the same context and filename as the body span. - fn_sig_span_extended: Option, + fn_sig_span: Option, body_span: Span, /// "Holes" are regions within the function body (or its expansions) that /// should not be included in coverage spans for this function @@ -308,30 +308,20 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir // The actual signature span is only used if it has the same context and // filename as the body, and precedes the body. - let fn_sig_span_extended = maybe_fn_sig - .map(|fn_sig| fn_sig.span) - .filter(|&fn_sig_span| { - let source_map = tcx.sess.source_map(); - let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); + let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { + let source_map = tcx.sess.source_map(); + let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); - fn_sig_span.eq_ctxt(body_span) - && fn_sig_span.hi() <= body_span.lo() - && file_idx(fn_sig_span) == file_idx(body_span) - }) - // If so, extend it to the start of the body span. - .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo())); + fn_sig_span.eq_ctxt(body_span) + && fn_sig_span.hi() <= body_span.lo() + && file_idx(fn_sig_span) == file_idx(body_span) + }); let function_source_hash = hash_mir_source(tcx, hir_body); let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); - ExtractedHirInfo { - function_source_hash, - is_async_fn, - fn_sig_span_extended, - body_span, - hole_spans, - } + ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f57a158e3e4a..e6e7e2920ec0 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -42,12 +42,12 @@ pub(super) fn extract_refined_covspans<'tcx>( return; } - // Also add the adjusted function signature span, if available. + // Also add the function signature span, if available. // Otherwise, add a fake span at the start of the body, to avoid an ugly // gap between the start of the body and the first real span. // FIXME: Find a more principled way to solve this problem. covspans.push(SpanFromMir::for_fn_sig( - hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()), + hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), )); // First, perform the passes that need macro information. @@ -227,19 +227,21 @@ struct Covspan { } impl Covspan { - /// If `self` and `other` can be merged (i.e. they have the same BCB), - /// mutates `self.span` to also include `other.span` and returns true. + /// If `self` and `other` can be merged, mutates `self.span` to also + /// include `other.span` and returns true. /// - /// Note that compatible covspans can be merged even if their underlying - /// spans are not overlapping/adjacent; any space between them will also be - /// part of the merged covspan. + /// Two covspans can be merged if they have the same BCB, and they are + /// overlapping or adjacent. fn merge_if_eligible(&mut self, other: &Self) -> bool { - if self.bcb != other.bcb { - return false; - } + let eligible_for_merge = + |a: &Self, b: &Self| (a.bcb == b.bcb) && a.span.overlaps_or_adjacent(b.span); - self.span = self.span.to(other.span); - true + if eligible_for_merge(self, other) { + self.span = self.span.to(other.span); + true + } else { + false + } } } diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 4021537392b9..4d8ea874bd79 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,5 +1,5 @@ Function name: abort::main -Raw bytes (83): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 0d, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (98): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 10, 01, 0d, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/abort.rs Number of expressions: 7 @@ -10,9 +10,11 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Expression(6, Add) - expression 6 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 25) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 26) to (start + 2, 10) @@ -30,19 +32,25 @@ Number of file 0 mappings: 13 = (c1 - (c0 + c4)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: abort::might_abort -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 03, 01, 00, 2e, 01, 01, 08, 00, 14, 05, 01, 09, 00, 11, 05, 00, 12, 00, 1f, 05, 01, 09, 00, 0f, 02, 01, 0c, 02, 06, 02, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/abort.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 31) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/assert-ne.cov-map b/tests/coverage/assert-ne.cov-map index 4bee7d7b97c7..fde0d5184d67 100644 --- a/tests/coverage/assert-ne.cov-map +++ b/tests/coverage/assert-ne.cov-map @@ -1,16 +1,23 @@ Function name: assert_ne::main -Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 15, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02] +Raw bytes (55): 0x[01, 01, 03, 01, 05, 01, 09, 01, 09, 09, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 12, 01, 00, 13, 00, 19, 01, 01, 0c, 00, 15, 05, 01, 0d, 00, 13, 02, 02, 0d, 00, 13, 0a, 03, 05, 00, 07, 0a, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/assert-ne.rs -Number of expressions: 2 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 21) -- Code(Counter(1)) at (prev + 4, 13) to (start + 0, 19) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) -- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(2, Sub)) at (prev + 3, 5) to (start + 0, 7) + = (c0 - c2) +- Code(Expression(2, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c0 - c2) Highest counter ID seen: c1 diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index e7ee91979711..07a0d4c8c27e 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -1,5 +1,5 @@ Function name: assert::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 09, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (76): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 0c, 01, 09, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/assert.rs Number of expressions: 6 @@ -9,9 +9,11 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 2, 10) @@ -22,18 +24,22 @@ Number of file 0 mappings: 9 = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: assert::might_fail_assert -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 04, 01, 00, 28, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 01, 01, 05, 00, 0f, 02, 00, 25, 00, 3d, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/assert.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15) -- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 0, 37) to (start + 0, 61) = (c0 - c1) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map index d3ef867a8a82..e0ec3815244e 100644 --- a/tests/coverage/assert_not.cov-map +++ b/tests/coverage/assert_not.cov-map @@ -1,13 +1,18 @@ Function name: assert_not::main -Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 11, 01, 02, 05, 00, 13, 01, 01, 05, 00, 13, 01, 01, 05, 00, 15, 01, 01, 01, 00, 02] +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 06, 01, 00, 0a, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 11, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 13, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 13, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/assert_not.rs Number of expressions: 0 -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 17) -- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 21) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 8d8dd2430571..c528ad525b5f 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -1,115 +1,125 @@ Function name: async::c -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 18] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 24) Highest counter ID seen: c0 Function name: async::c::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0b, 19, 00, 1a, 01, 01, 08, 00, 0e, 05, 01, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 11, 25) to (start + 1, 14) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 11, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: async::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 13] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 19) Highest counter ID seen: c0 Function name: async::d::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 13, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: c0 Function name: async::e (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 13] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 0, 20) +- Code(Zero) at (prev + 21, 1) to (start + 0, 19) Highest counter ID seen: (none) Function name: async::e::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 15, 14, 00, 15, 00, 00, 16, 00, 17, 00, 00, 18, 00, 19] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 21, 20) to (start + 0, 21) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) +- Code(Zero) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: (none) Function name: async::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 13] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 19) Highest counter ID seen: c0 Function name: async::f::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 17, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 23, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: c0 Function name: async::foo (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1e] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1d] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 1) to (start + 0, 30) +- Code(Zero) at (prev + 25, 1) to (start + 0, 29) Highest counter ID seen: (none) Function name: async::foo::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 1e, 00, 2d] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 19, 1e, 00, 1f, 00, 00, 20, 00, 2b, 00, 00, 2c, 00, 2d] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 30) to (start + 0, 45) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 25, 30) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) +- Code(Zero) at (prev + 0, 44) to (start + 0, 45) Highest counter ID seen: (none) Function name: async::g -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 16] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22) Highest counter ID seen: c0 Function name: async::g::{closure#0} (unused) -Raw bytes (59): 0x[01, 01, 00, 0b, 00, 1b, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 11 -- Code(Zero) at (prev + 27, 23) to (start + 1, 12) -- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +Number of file 0 mappings: 12 +- Code(Zero) at (prev + 27, 23) to (start + 0, 24) +- Code(Zero) at (prev + 1, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 23) - Code(Zero) at (prev + 0, 27) to (start + 0, 28) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) @@ -122,22 +132,23 @@ Number of file 0 mappings: 11 Highest counter ID seen: (none) Function name: async::h -Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 16] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 15] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 21) Highest counter ID seen: c0 Function name: async::h::{closure#0} (unused) -Raw bytes (39): 0x[01, 01, 00, 07, 00, 23, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 00, 23, 16, 00, 17, 00, 03, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 7 -- Code(Zero) at (prev + 35, 22) to (start + 3, 12) -- Code(Zero) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 8 +- Code(Zero) at (prev + 35, 22) to (start + 0, 23) +- Code(Zero) at (prev + 3, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 25) - Code(Zero) at (prev + 0, 26) to (start + 0, 27) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) @@ -146,25 +157,27 @@ Number of file 0 mappings: 7 Highest counter ID seen: (none) Function name: async::i -Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 13] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 12] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 18) Highest counter ID seen: c0 Function name: async::i::{closure#0} -Raw bytes (65): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0b, 01, 2c, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Raw bytes (75): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0d, 01, 2c, 13, 00, 14, 01, 04, 0b, 00, 0c, 09, 01, 09, 00, 0a, 01, 00, 0e, 00, 0f, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(4), rhs = Counter(5) - expression 2 operands: lhs = Counter(3), rhs = Counter(4) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 44, 19) to (start + 4, 12) -- Code(Counter(2)) at (prev + 5, 9) to (start + 0, 10) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 44, 19) to (start + 0, 20) +- Code(Counter(0)) at (prev + 4, 11) to (start + 0, 12) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 24) - Code(Counter(1)) at (prev + 0, 28) to (start + 0, 33) - Code(Counter(2)) at (prev + 0, 39) to (start + 0, 48) @@ -180,17 +193,18 @@ Number of file 0 mappings: 11 Highest counter ID seen: c5 Function name: async::j -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 37, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0b, 01, 37, 01, 00, 0c, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 0f, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 13) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 12) - Code(Counter(0)) at (prev + 11, 11) to (start + 0, 12) - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 27) - Code(Counter(1)) at (prev + 0, 31) to (start + 0, 39) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10) @@ -203,60 +217,67 @@ Number of file 0 mappings: 10 Highest counter ID seen: c2 Function name: async::j::c -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 39, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 39, 05, 00, 16, 01, 01, 0c, 00, 12, 05, 01, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 57, 5) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 57, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 14) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: async::j::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 40, 05, 00, 17] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 40, 05, 00, 11, 01, 00, 14, 00, 15, 01, 00, 16, 00, 17] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 64, 5) to (start + 0, 23) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 64, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: c0 Function name: async::j::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 41, 05, 00, 17] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 41, 05, 00, 11, 01, 00, 14, 00, 15, 01, 00, 16, 00, 17] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 23) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: c0 Function name: async::k (unused) -Raw bytes (29): 0x[01, 01, 00, 05, 00, 49, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 00, 49, 01, 00, 0c, 00, 01, 0b, 00, 0c, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 5 -- Code(Zero) at (prev + 73, 1) to (start + 1, 12) -- Code(Zero) at (prev + 2, 14) to (start + 0, 16) +Number of file 0 mappings: 6 +- Code(Zero) at (prev + 73, 1) to (start + 0, 12) +- Code(Zero) at (prev + 1, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: async::l -Raw bytes (33): 0x[01, 01, 02, 01, 07, 05, 09, 05, 01, 51, 01, 01, 0c, 02, 02, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 07, 05, 09, 06, 01, 51, 01, 00, 0c, 01, 01, 0b, 00, 0c, 02, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 81, 1) to (start + 1, 12) -- Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 81, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 12) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 16) = (c0 - (c1 + c2)) - Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16) @@ -264,29 +285,43 @@ Number of file 0 mappings: 5 Highest counter ID seen: c2 Function name: async::m -Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 18] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 24) Highest counter ID seen: c0 Function name: async::m::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 59, 19, 00, 22] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 59, 19, 00, 1a, 00, 00, 1b, 00, 20, 00, 00, 21, 00, 22] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 89, 25) to (start + 0, 34) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 89, 25) to (start + 0, 26) +- Code(Zero) at (prev + 0, 27) to (start + 0, 32) +- Code(Zero) at (prev + 0, 33) to (start + 0, 34) Highest counter ID seen: (none) Function name: async::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 08, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 5b, 01, 00, 0a, 01, 01, 0d, 00, 12, 01, 01, 0d, 00, 11, 01, 01, 09, 00, 13, 01, 00, 16, 00, 1e, 01, 00, 1f, 00, 20, 01, 01, 05, 00, 06, 01, 01, 05, 00, 06, 01, 01, 0d, 00, 11, 01, 01, 05, 00, 17, 01, 00, 18, 00, 1e, 01, 00, 1f, 00, 25, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 91, 1) to (start + 8, 2) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 91, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 30) +- Code(Counter(0)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 30) +- Code(Counter(0)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage index aee76b05fb74..9fca1b6997d0 100644 --- a/tests/coverage/async.coverage +++ b/tests/coverage/async.coverage @@ -25,6 +25,7 @@ LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` LL| | LL| 1|pub async fn g(x: u8) { + ^0 LL| 0| match x { LL| 0| y if e().await == y => (), LL| 0| y if f().await == y => (), @@ -33,8 +34,9 @@ LL| 0|} LL| | LL| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not - LL| 0| // executed (not awaited) so the open brace has a `0` count (at least when - LL| 0| // displayed with `llvm-cov show` in color-mode). + ^0 + LL| | // executed (not awaited) so the open brace has a `0` count (at least when + LL| | // displayed with `llvm-cov show` in color-mode). LL| 0| match x { LL| 0| y if foo().await[y] => (), LL| 0| _ => (), @@ -42,9 +44,9 @@ LL| 0|} LL| | LL| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: - LL| 1| // (a) the function signature, counted when the function is called; and - LL| 1| // (b) the open brace for the function body, counted once when the body is - LL| 1| // executed asynchronously. + LL| | // (a) the function signature, counted when the function is called; and + LL| | // (b) the open brace for the function body, counted once when the body is + LL| | // executed asynchronously. LL| 1| match x { LL| 1| y if c(x).await == y + 1 => { d().await; } ^0 ^0 @@ -91,7 +93,7 @@ LL| 1|} LL| | LL| 1|async fn m(x: u8) -> u8 { x - 1 } - ^0 + ^0^0 ^0 LL| | LL| 1|fn main() { LL| 1| let _ = g(10); diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index 43ec9f397bd9..cc6295170980 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -1,59 +1,80 @@ Function name: async2::async_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 16] Number of files: 1 - file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 22) Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 17, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 0f, 17, 00, 18, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 26, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 11, 01, 01, 08, 00, 09, 01, 00, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async2.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 15, 23) to (start + 3, 9) -- Code(Counter(0)) at (prev + 3, 10) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 15, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async2::async_func_just_println -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 24] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 23] Number of files: 1 - file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 35) Highest counter ID seen: c0 Function name: async2::async_func_just_println::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 24, 02, 02] -Number of files: 1 -- file 0 => $DIR/async2.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 36) to (start + 2, 2) -Highest counter ID seen: c0 - -Function name: async2::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 07, 02] -Number of files: 1 -- file 0 => $DIR/async2.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 2) -Highest counter ID seen: c0 - -Function name: async2::non_async_func -Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 01, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 17, 24, 00, 25, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 33, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 9) -- Code(Counter(0)) at (prev + 3, 10) to (start + 2, 6) +- Code(Counter(0)) at (prev + 23, 36) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + +Function name: async2::main +Raw bytes (49): 0x[01, 01, 00, 09, 01, 1b, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 23, 01, 02, 05, 00, 13, 01, 02, 05, 00, 17, 01, 00, 18, 00, 22, 01, 01, 05, 00, 17, 01, 00, 18, 00, 2f, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/async2.rs +Number of expressions: 0 +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 35) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + +Function name: async2::non_async_func +Raw bytes (49): 0x[01, 01, 00, 09, 01, 07, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 2a, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 11, 01, 01, 08, 00, 09, 01, 00, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/async2.rs +Number of expressions: 0 +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage index fa56072924bb..e9ed8253093d 100644 --- a/tests/coverage/async2.coverage +++ b/tests/coverage/async2.coverage @@ -28,9 +28,9 @@ LL| | LL| 1|fn main() { LL| 1| println!("codecovsample::main"); - LL| 1| + LL| | LL| 1| non_async_func(); - LL| 1| + LL| | LL| 1| executor::block_on(async_func()); LL| 1| executor::block_on(async_func_just_println()); LL| 1|} diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map index 9e76bb981ffe..07d4c0eb3cd6 100644 --- a/tests/coverage/async_block.cov-map +++ b/tests/coverage/async_block.cov-map @@ -1,30 +1,33 @@ Function name: async_block::main -Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 22, 01, 02, 01, 00, 02] +Raw bytes (41): 0x[01, 01, 01, 05, 01, 07, 01, 07, 01, 00, 0a, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 1b, 02, 00, 1c, 00, 22, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 11) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) = (c1 - c0) -- Code(Expression(0, Sub)) at (prev + 7, 9) to (start + 0, 34) +- Code(Expression(0, Sub)) at (prev + 7, 9) to (start + 0, 27) + = (c1 - c0) +- Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 0, 34) = (c1 - c0) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: async_block::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 09, 1c, 00, 1d, 01, 01, 10, 00, 17, 05, 00, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 9, 28) to (start + 1, 23) -- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 9, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 23) +- Code(Counter(1)) at (prev + 0, 24) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index 10b6db0fc713..9f8dc8d6cbba 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -1,32 +1,39 @@ Function name: async_closure::call_once:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2b] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2a] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 43) +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 42) Highest counter ID seen: c0 Function name: async_closure::call_once::::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 06, 2b, 01, 0e, 02, 02, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 2b, 00, 2c, 01, 01, 05, 00, 0e, 02, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 6, 43) to (start + 1, 14) -- Code(Expression(0, Sub)) at (prev + 2, 1) to (start + 0, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 6, 43) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c0 Function name: async_closure::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 01, 16, 01, 02, 05, 02, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 01, 0a, 01, 00, 0e, 01, 01, 09, 00, 16, 01, 01, 05, 00, 17, 01, 00, 18, 00, 27, 01, 01, 05, 00, 17, 01, 00, 18, 00, 21, 01, 00, 22, 00, 2f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 10, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 2, 5) to (start + 2, 2) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 39) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 33) +- Code(Counter(0)) at (prev + 0, 34) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} @@ -50,11 +57,12 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: async_closure::main::{closure#0}::{closure#0}:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 diff --git a/tests/coverage/async_closure.coverage b/tests/coverage/async_closure.coverage index 5aed131de2e5..14f043415eac 100644 --- a/tests/coverage/async_closure.coverage +++ b/tests/coverage/async_closure.coverage @@ -8,7 +8,8 @@ LL| 1|} LL| | LL| 1|pub fn main() { - LL| 2| let async_closure = async || {}; + LL| 3| let async_closure = async || {}; + ^1 ------------------ | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map index ad24dfb63229..0562c291e6c1 100644 --- a/tests/coverage/attr/impl.cov-map +++ b/tests/coverage/attr/impl.cov-map @@ -1,27 +1,30 @@ Function name: ::off_on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 05, 00, 13] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 0f, 05, 00, 10, 00, 00, 12, 00, 13] Number of files: 1 - file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 15, 5) to (start + 0, 19) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 15, 5) to (start + 0, 16) +- Code(Zero) at (prev + 0, 18) to (start + 0, 19) Highest counter ID seen: (none) Function name: ::on_inherit (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 17] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 17, 05, 00, 14, 00, 00, 16, 00, 17] Number of files: 1 - file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 23, 5) to (start + 0, 23) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 23, 5) to (start + 0, 20) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: (none) Function name: ::on_on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 05, 00, 12] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1a, 05, 00, 0f, 00, 00, 11, 00, 12] Number of files: 1 - file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 26, 5) to (start + 0, 18) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 26, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 17) to (start + 0, 18) Highest counter ID seen: (none) diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map index eba24da0dd1e..88f4915bfe8f 100644 --- a/tests/coverage/attr/module.cov-map +++ b/tests/coverage/attr/module.cov-map @@ -1,27 +1,30 @@ Function name: module::off::on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0d, 05, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 0d, 05, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 - file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 13, 5) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 13, 5) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) Function name: module::on::inherit (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 05, 00, 14] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 15, 05, 00, 11, 00, 00, 13, 00, 14] Number of files: 1 - file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 5) to (start + 0, 20) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 21, 5) to (start + 0, 17) +- Code(Zero) at (prev + 0, 19) to (start + 0, 20) Highest counter ID seen: (none) Function name: module::on::on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 05, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 18, 05, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 - file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 24, 5) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 24, 5) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map index a831340bce5e..8ca218f7267f 100644 --- a/tests/coverage/attr/nested.cov-map +++ b/tests/coverage/attr/nested.cov-map @@ -1,20 +1,24 @@ Function name: nested::closure_expr -Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 01, 01, 0f, 01, 0b, 05, 01, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 40, 01, 00, 12, 01, 01, 09, 00, 0f, 01, 0a, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 64, 1) to (start + 1, 15) -- Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 64, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: nested::closure_tail -Raw bytes (14): 0x[01, 01, 00, 02, 01, 4f, 01, 01, 0f, 01, 11, 05, 01, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 4f, 01, 00, 12, 01, 01, 09, 00, 0f, 01, 10, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 79, 1) to (start + 1, 15) -- Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 79, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 16, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index d26f06bb81f5..c0c6eab57108 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -1,30 +1,36 @@ Function name: off_on_sandwich::dense_a::dense_b -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 10, 01, 07, 05, 00, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 05, 00, 11, 01, 01, 09, 00, 10, 01, 01, 09, 00, 10, 01, 05, 05, 00, 06] Number of files: 1 - file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 5) to (start + 2, 16) -- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 16, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c -Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 15, 01, 0b, 09, 00, 0a] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 22, 09, 00, 16, 01, 01, 0d, 00, 15, 01, 01, 0d, 00, 15, 01, 09, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 34, 9) to (start + 2, 21) -- Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 34, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) +- Code(Counter(0)) at (prev + 9, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d -Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 19, 01, 07, 0d, 00, 0e] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 25, 0d, 00, 1a, 01, 01, 11, 00, 19, 01, 01, 11, 00, 19, 01, 05, 0d, 00, 0e] Number of files: 1 - file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 37, 13) to (start + 2, 25) -- Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 37, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(0)) at (prev + 5, 13) to (start + 0, 14) Highest counter ID seen: c0 diff --git a/tests/coverage/attr/trait-impl-inherit.cov-map b/tests/coverage/attr/trait-impl-inherit.cov-map index b3e875785926..bf10083dd290 100644 --- a/tests/coverage/attr/trait-impl-inherit.cov-map +++ b/tests/coverage/attr/trait-impl-inherit.cov-map @@ -1,9 +1,12 @@ Function name: ::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 10, 01, 01, 09, 00, 11, 01, 00, 12, 00, 1a, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/trait-impl-inherit.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/await_ready.cov-map index 7bff6a4a7748..a7eb051ff093 100644 --- a/tests/coverage/await_ready.cov-map +++ b/tests/coverage/await_ready.cov-map @@ -1,21 +1,22 @@ Function name: await_ready::await_ready -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1e] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1d] Number of files: 1 - file 0 => $DIR/await_ready.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 30) +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 29) Highest counter ID seen: c0 Function name: await_ready::await_ready::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 0e, 1e, 03, 0f, 02, 04, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 0e, 1e, 00, 1f, 01, 02, 05, 01, 0f, 02, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/await_ready.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 14, 30) to (start + 3, 15) -- Code(Expression(0, Sub)) at (prev + 4, 1) to (start + 0, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 14, 30) to (start + 0, 31) +- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 15) +- Code(Expression(0, Sub)) at (prev + 2, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c0 diff --git a/tests/coverage/await_ready.coverage b/tests/coverage/await_ready.coverage index 1150d807e763..9a2d8f5a4fdf 100644 --- a/tests/coverage/await_ready.coverage +++ b/tests/coverage/await_ready.coverage @@ -12,7 +12,7 @@ LL| |#[coverage(on)] LL| |#[rustfmt::skip] LL| 1|async fn await_ready() -> u8 { - LL| 1| // await should be covered even if the function never yields + LL| | // await should be covered even if the function never yields LL| 1| ready() LL| 1| .await LL| 1|} diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index 2ef299307261..8b1b177f906e 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,84 +1,108 @@ Function name: bad_counter_ids::eq_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 0f, 00, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 24, 01, 00, 0c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 15) -- Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 29, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 00, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 0f, 01, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 10, 01, 00, 0d, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 15, 01, 00, 15, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 0f, 00, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 2e, 01, 00, 0c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 15) -- Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 46, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 33, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 00, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 51, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 0f, 01, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 1a, 01, 00, 0d, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) -Highest counter ID seen: c0 - -Function name: bad_counter_ids::ne_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] -Number of files: 1 -- file 0 => $DIR/bad_counter_ids.rs -Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + +Function name: bad_counter_ids::ne_good_message +Raw bytes (34): 0x[01, 01, 00, 06, 01, 1f, 01, 00, 15, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 2b, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/bad_counter_ids.rs +Number of expressions: 0 +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/bench.cov-map b/tests/coverage/bench.cov-map index 1707957fddc1..f2b21ddb70bb 100644 --- a/tests/coverage/bench.cov-map +++ b/tests/coverage/bench.cov-map @@ -1,9 +1,10 @@ Function name: bench::my_bench -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 01, 00, 24, 01, 00, 26, 00, 27] Number of files: 1 - file 0 => $DIR/bench.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 0, 38) to (start + 0, 39) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map index 50e6eedb676f..cb03f2a79f76 100644 --- a/tests/coverage/branch/generics.cov-map +++ b/tests/coverage/branch/generics.cov-map @@ -1,12 +1,13 @@ Function name: generics::print_size::<()> -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) @@ -16,14 +17,15 @@ Number of file 0 mappings: 5 Highest counter ID seen: c1 Function name: generics::print_size:: -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) @@ -33,14 +35,15 @@ Number of file 0 mappings: 5 Highest counter ID seen: c1 Function name: generics::print_size:: -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index c1a275b34a3f..9c6a9bf40fd1 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,5 +1,5 @@ Function name: guard::branch_match_guard -Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 0e, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] +Raw bytes (104): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 10, 01, 0c, 01, 00, 26, 01, 01, 05, 00, 0e, 02, 02, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 00, 1e, 0d, 00, 22, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 00, 1e, 11, 00, 22, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => $DIR/guard.rs Number of expressions: 8 @@ -11,9 +11,10 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(0), rhs = Counter(1) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Expression(0, Sub)) at (prev + 3, 11) to (start + 0, 12) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 2, 11) to (start + 0, 12) = (c1 - c3) - Code(Expression(1, Sub)) at (prev + 1, 20) to (start + 2, 10) = (c2 - c1) @@ -22,14 +23,16 @@ Number of file 0 mappings: 13 - Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c3 false = (c1 - c3) -- Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10) +- Code(Counter(3)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 34) to (start + 2, 10) - Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15) - Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 0, 25) = (c1 - c3) - Branch { true: Counter(4), false: Expression(2, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c4 false = (c1 - (c3 + c4)) -- Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10) +- Code(Counter(4)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(4)) at (prev + 0, 34) to (start + 2, 10) - Code(Expression(4, Sub)) at (prev + 3, 14) to (start + 2, 10) = ((c0 + c1) - ((c2 + c3) + c4)) - Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) diff --git a/tests/coverage/branch/guard.coverage b/tests/coverage/branch/guard.coverage index f89b965b5d0f..465aefbf0665 100644 --- a/tests/coverage/branch/guard.coverage +++ b/tests/coverage/branch/guard.coverage @@ -17,7 +17,7 @@ LL| 1| println!("zero"); LL| 1| } LL| 3| Some(x) if x % 2 == 0 => { - ^2 + ^2 ^2 ------------------ | Branch (LL:20): [True: 2, False: 1] ------------------ diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index a79232233013..86bfcadb1255 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -1,12 +1,13 @@ Function name: if_let::if_let -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (58): 0x[01, 01, 01, 01, 05, 0a, 01, 0c, 01, 00, 1f, 01, 01, 05, 00, 0e, 20, 02, 05, 02, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 00, 08, 01, 00, 09, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if-let.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 12) to (start + 0, 19) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 2, 12) to (start + 0, 19) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) @@ -15,41 +16,53 @@ Number of file 0 mappings: 7 - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 12) to (start + 2, 6) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: if_let::if_let_chain -Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (102): 0x[01, 01, 0c, 01, 05, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 05, 09, 0e, 01, 17, 01, 00, 32, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 26, 09, 01, 10, 00, 17, 26, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 26, 01, 05, 03, 06, 26, 01, 09, 00, 0c, 26, 00, 0d, 00, 0e, 2f, 02, 0c, 02, 06, 01, 03, 05, 00, 08, 01, 00, 09, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if-let.rs -Number of expressions: 8 +Number of expressions: 12 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 3 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 4 operands: lhs = Counter(1), rhs = Counter(2) -- expression 5 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 5 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 6 operands: lhs = Counter(1), rhs = Counter(2) -- expression 7 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51) +- expression 7 operands: lhs = Counter(0), rhs = Expression(11, Add) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +- expression 9 operands: lhs = Counter(0), rhs = Expression(11, Add) +- expression 10 operands: lhs = Counter(1), rhs = Counter(2) +- expression 11 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 50) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) -- Branch { true: Expression(5, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) +- Branch { true: Expression(9, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) true = (c0 - (c1 + c2)) false = c2 -- Code(Expression(5, Sub)) at (prev + 0, 21) to (start + 0, 22) +- Code(Expression(9, Sub)) at (prev + 0, 21) to (start + 0, 22) = (c0 - (c1 + c2)) - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27) = (c0 - c1) -- Code(Expression(5, Sub)) at (prev + 1, 5) to (start + 3, 6) +- Code(Expression(9, Sub)) at (prev + 1, 5) to (start + 3, 6) = (c0 - (c1 + c2)) -- Code(Expression(7, Add)) at (prev + 3, 12) to (start + 2, 6) +- Code(Expression(9, Sub)) at (prev + 1, 9) to (start + 0, 12) + = (c0 - (c1 + c2)) +- Code(Expression(9, Sub)) at (prev + 0, 13) to (start + 0, 14) + = (c0 - (c1 + c2)) +- Code(Expression(11, Add)) at (prev + 2, 12) to (start + 2, 6) = (c1 + c2) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 64b13fcfaa1e..09a014ce8a1a 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -1,14 +1,15 @@ Function name: if::branch_and -Raw bytes (54): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 2b, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (59): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 2b, 01, 00, 20, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 43, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -23,7 +24,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (126): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 14, 01, 0c, 01, 00, 17, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 0c, 05, 00, 0d, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 7 @@ -34,13 +35,15 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(4) - expression 6 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 18 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 20 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 8) to (start + 0, 10) @@ -68,7 +71,7 @@ Number of file 0 mappings: 18 Highest counter ID seen: c4 Function name: if::branch_not_as -Raw bytes (90): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0e, 01, 1d, 01, 01, 0e, 01, 03, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (95): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0f, 01, 1d, 01, 00, 1a, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 5 @@ -77,9 +80,10 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Counter(3) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 20) +Number of file 0 mappings: 15 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 0, 8) to (start + 0, 20) true = (c0 - c1) false = c1 @@ -104,7 +108,7 @@ Number of file 0 mappings: 14 Highest counter ID seen: c3 Function name: if::branch_or -Raw bytes (60): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 08, 01, 35, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 09, 01, 35, 01, 00, 1f, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 6 @@ -114,9 +118,10 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Counter(2) - expression 4 operands: lhs = Counter(0), rhs = Expression(5, Add) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 53, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index b01ca5c94dff..9ec7c9a7f42b 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -1,40 +1,46 @@ Function name: lazy_boolean::branch_and -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 13, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 01, 01, 05, 09, 01, 13, 01, 00, 20, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 19, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: lazy_boolean::branch_or -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 1b, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 01, 01, 05, 09, 01, 1b, 01, 00, 1f, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 27, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: lazy_boolean::chain -Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] +Raw bytes (161): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 17, 01, 24, 01, 00, 11, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/lazy-boolean.rs Number of expressions: 15 @@ -53,9 +59,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(0), rhs = Expression(13, Add) - expression 13 operands: lhs = Expression(14, Add), rhs = Counter(6) - expression 14 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 23 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 18) true = c1 @@ -69,7 +76,8 @@ Number of file 0 mappings: 19 true = c3 false = (c2 - c3) - Code(Counter(3)) at (prev + 0, 40) to (start + 0, 45) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 18) @@ -87,11 +95,13 @@ Number of file 0 mappings: 19 false = (c0 - ((c4 + c5) + c6)) - Code(Expression(12, Sub)) at (prev + 0, 40) to (start + 0, 45) = (c0 - ((c4 + c5) + c6)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c6 Function name: lazy_boolean::nested_mixed -Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] +Raw bytes (157): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 17, 01, 31, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/lazy-boolean.rs Number of expressions: 13 @@ -108,9 +118,10 @@ Number of expressions: 13 - expression 10 operands: lhs = Counter(0), rhs = Counter(5) - expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add) - expression 12 operands: lhs = Counter(5), rhs = Counter(6) -Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 23 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 14) to (start + 0, 19) true = c1 @@ -127,7 +138,8 @@ Number of file 0 mappings: 19 false = ((c1 + c2) - c3) - Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 51) = ((c1 + c2) - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(4), false: Expression(8, Sub) } at (prev + 0, 14) to (start + 0, 19) @@ -143,6 +155,8 @@ Number of file 0 mappings: 19 true = c6 false = (c0 - (c5 + c6)) - Code(Counter(6)) at (prev + 0, 44) to (start + 0, 51) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c6 diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 2af5e919f4c9..61bedbfbff0c 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,19 +1,24 @@ Function name: let_else::let_else -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] +Raw bytes (63): 0x[01, 01, 01, 01, 05, 0b, 01, 0c, 01, 00, 21, 01, 01, 05, 00, 0e, 20, 02, 05, 02, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 00, 0c, 05, 00, 0d, 00, 13, 05, 01, 09, 00, 0f, 02, 03, 05, 00, 08, 02, 00, 09, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/let-else.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 9) to (start + 0, 16) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 2, 9) to (start + 0, 16) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 19) to (start + 0, 24) -- Code(Counter(1)) at (prev + 1, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 10) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 8) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 0, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index 3f753f14eb5b..a2ed0d84ed61 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,5 +1,5 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 0e, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] +Raw bytes (158): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 1a, 01, 30, 01, 00, 23, 01, 01, 05, 00, 0e, 21, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 20, 05, 02, 00, 17, 00, 1b, 05, 00, 1a, 00, 1b, 05, 00, 1f, 00, 26, 05, 00, 27, 00, 28, 09, 01, 11, 00, 12, 20, 09, 06, 00, 17, 00, 1b, 09, 00, 1a, 00, 1b, 09, 00, 1f, 00, 26, 09, 00, 27, 00, 28, 0d, 01, 11, 00, 12, 20, 0d, 0a, 00, 17, 00, 1b, 0d, 00, 1a, 00, 1b, 0d, 00, 1f, 00, 26, 0d, 00, 27, 00, 28, 11, 01, 11, 00, 12, 20, 11, 0e, 00, 17, 00, 1b, 11, 00, 1a, 00, 1b, 11, 00, 1f, 00, 26, 11, 00, 27, 00, 28, 12, 01, 0e, 00, 15, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/match-arms.rs Number of expressions: 8 @@ -11,70 +11,103 @@ Number of expressions: 8 - expression 5 operands: lhs = Expression(6, Add), rhs = Counter(4) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3) - expression 7 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 12 -- Code(Counter(0)) at (prev + 48, 1) to (start + 1, 14) -- Code(Counter(8)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 40) +Number of file 0 mappings: 26 +- Code(Counter(0)) at (prev + 48, 1) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(8)) at (prev + 2, 11) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c1 false = (c5 - c1) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(1)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c2 false = (c6 - c2) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(2)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(2)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(2)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c3 false = (c7 - c3) -- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(3)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(3)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(4), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c4 false = (c8 - c4) +- Code(Counter(4)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(4)) at (prev + 0, 39) to (start + 0, 40) - Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 21) = (c0 - (((c1 + c2) + c3) + c4)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c8 Function name: match_arms::match_arms -Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] +Raw bytes (95): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 11, 01, 18, 01, 00, 1b, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 05, 00, 17, 00, 1e, 05, 00, 1f, 00, 20, 09, 01, 11, 00, 12, 09, 00, 17, 00, 1e, 09, 00, 1f, 00, 20, 0d, 01, 11, 00, 12, 0d, 00, 17, 00, 1e, 0d, 00, 1f, 00, 20, 02, 01, 11, 00, 12, 02, 00, 17, 00, 1e, 02, 00, 1f, 00, 20, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/match-arms.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 24, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 32) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 32) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 32) -- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 32) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(1)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(2)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 18) = (c0 - ((c1 + c2) + c3)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 30) + = (c0 - ((c1 + c2) + c3)) +- Code(Expression(0, Sub)) at (prev + 0, 31) to (start + 0, 32) + = (c0 - ((c1 + c2) + c3)) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: match_arms::or_patterns -Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] +Raw bytes (79): 0x[01, 01, 05, 05, 09, 01, 0b, 03, 0d, 01, 03, 01, 03, 0d, 01, 25, 01, 00, 1c, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2b, 03, 00, 2c, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 12, 00, 24, 00, 2b, 12, 00, 2c, 00, 2d, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/match-arms.rs -Number of expressions: 4 +Number of expressions: 5 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 3 operands: lhs = Counter(0), rhs = Expression(0, Add) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) +- expression 4 operands: lhs = Counter(0), rhs = Expression(0, Add) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Code(Counter(2)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 45) +- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 43) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 0, 44) to (start + 0, 45) = (c1 + c2) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) - Code(Expression(1, Sub)) at (prev + 0, 30) to (start + 0, 31) = (c0 - ((c1 + c2) + c3)) -- Code(Expression(3, Sub)) at (prev + 0, 36) to (start + 0, 45) +- Code(Expression(4, Sub)) at (prev + 0, 36) to (start + 0, 43) = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(4, Sub)) at (prev + 0, 44) to (start + 0, 45) + = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/branch/match-trivial.cov-map b/tests/coverage/branch/match-trivial.cov-map index dd05ae4e345f..a88e89523ae2 100644 --- a/tests/coverage/branch/match-trivial.cov-map +++ b/tests/coverage/branch/match-trivial.cov-map @@ -1,19 +1,24 @@ Function name: match_trivial::_uninhabited (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 0e] -Number of files: 1 -- file 0 => $DIR/match-trivial.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 22, 1) to (start + 1, 14) -Highest counter ID seen: (none) - -Function name: match_trivial::trivial -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 0e, 01, 03, 0b, 05, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 16, 01, 00, 20, 00, 01, 05, 00, 0e] Number of files: 1 - file 0 => $DIR/match-trivial.rs Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 5, 2) +- Code(Zero) at (prev + 22, 1) to (start + 0, 32) +- Code(Zero) at (prev + 1, 5) to (start + 0, 14) +Highest counter ID seen: (none) + +Function name: match_trivial::trivial +Raw bytes (34): 0x[01, 01, 00, 06, 01, 1e, 01, 00, 17, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 0c, 01, 01, 1b, 00, 22, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/match-trivial.rs +Number of expressions: 0 +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/match-trivial.coverage b/tests/coverage/branch/match-trivial.coverage index 4ffb172e1b67..6e7bf2d29abc 100644 --- a/tests/coverage/branch/match-trivial.coverage +++ b/tests/coverage/branch/match-trivial.coverage @@ -32,8 +32,8 @@ LL| | LL| 1| match x { LL| 1| Trivial::Value => consume("trivial"), - LL| 1| } - LL| 1| + LL| | } + LL| | LL| 1| consume("done"); LL| 1|} LL| | diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map index d28e6a580085..4f893cba1f81 100644 --- a/tests/coverage/branch/no-mir-spans.cov-map +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -1,31 +1,31 @@ Function name: no_mir_spans::while_cond -Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 11, 20, 02, 01, 04, 0b, 00, 10] +Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 10, 20, 02, 01, 04, 0b, 00, 10] Number of files: 1 - file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 16) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 16) true = (c1 - c0) false = c0 Highest counter ID seen: c0 Function name: no_mir_spans::while_cond_not -Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 15, 20, 02, 01, 04, 0b, 00, 14] +Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 14, 20, 02, 01, 04, 0b, 00, 14] Number of files: 1 - file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 20) true = (c1 - c0) false = c0 Highest counter ID seen: c0 Function name: no_mir_spans::while_op_and -Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 13, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19] +Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19] Number of files: 1 - file 0 => $DIR/no-mir-spans.rs Number of expressions: 4 @@ -34,7 +34,7 @@ Number of expressions: 4 - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16) true = c1 false = (c2 - c1) @@ -44,7 +44,7 @@ Number of file 0 mappings: 3 Highest counter ID seen: c1 Function name: no_mir_spans::while_op_or -Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19] +Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 11, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19] Number of files: 1 - file 0 => $DIR/no-mir-spans.rs Number of expressions: 3 @@ -52,7 +52,7 @@ Number of expressions: 3 - expression 1 operands: lhs = Counter(2), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 17) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16) true = c1 false = (c2 - c1) diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index e5fda26822e2..767a7e46495f 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -1,12 +1,14 @@ Function name: while::while_cond -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 0c, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (48): 0x[01, 01, 01, 05, 01, 08, 01, 0c, 01, 00, 10, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 16) true = (c1 - c0) @@ -17,14 +19,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_cond_not -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 15, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (48): 0x[01, 01, 01, 05, 01, 08, 01, 15, 01, 00, 14, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 20) true = (c1 - c0) @@ -35,7 +39,7 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_op_and -Raw bytes (58): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 08, 01, 1e, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 0c, 01, 1e, 01, 00, 12, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while.rs Number of expressions: 5 @@ -44,10 +48,14 @@ Number of expressions: 5 - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(1) - expression 3 operands: lhs = Counter(0), rhs = Counter(2) - expression 4 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) true = c2 false = (c1 - c2) @@ -61,7 +69,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: while::while_op_or -Raw bytes (56): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 08, 01, 29, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (76): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 0c, 01, 29, 01, 00, 11, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while.rs Number of expressions: 4 @@ -69,10 +77,14 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) true = c2 false = (c1 - c2) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 096be9ea78a0..5f7e4ce58e97 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,18 +1,56 @@ Function name: closure::main -Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0d, 1b, 01, 1a, 05, 02, 0a, 01, 0c, 05, 11, 1b, 01, 1e, 05, 02, 0a, 01, 0c, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] +Raw bytes (336): 0x[01, 01, 01, 01, 05, 42, 01, 09, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 11, 01, 00, 14, 00, 1c, 01, 02, 09, 00, 18, 01, 00, 1b, 00, 43, 01, 01, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 0d, 05, 00, 10, 01, 00, 13, 00, 3b, 01, 02, 09, 00, 0a, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 02, 0d, 00, 0e, 01, 04, 05, 00, 10, 01, 00, 13, 00, 17, 01, 01, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 0d, 05, 00, 10, 01, 00, 13, 00, 17, 01, 02, 09, 00, 0a, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 02, 0d, 00, 0e, 01, 05, 09, 00, 16, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 28, 01, 02, 09, 00, 1a, 01, 01, 0e, 00, 12, 01, 01, 0e, 00, 11, 01, 02, 0d, 00, 1a, 01, 02, 0e, 00, 15, 01, 04, 09, 00, 18, 01, 0c, 09, 00, 16, 01, 00, 19, 00, 1b, 01, 01, 09, 00, 1e, 01, 03, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 05, 01, 09, 00, 30, 02, 03, 05, 00, 06, 01, 01, 05, 00, 28, 01, 01, 05, 00, 46, 01, 01, 05, 00, 43, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 24 -- Code(Counter(0)) at (prev + 9, 1) to (start + 13, 27) -- Code(Counter(0)) at (prev + 26, 5) to (start + 2, 10) -- Code(Counter(0)) at (prev + 12, 5) to (start + 17, 27) -- Code(Counter(0)) at (prev + 30, 5) to (start + 2, 10) -- Code(Counter(0)) at (prev + 12, 5) to (start + 12, 22) -- Code(Counter(0)) at (prev + 22, 5) to (start + 13, 24) -- Code(Counter(0)) at (prev + 25, 9) to (start + 1, 30) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 41) +Number of file 0 mappings: 66 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 28) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 59) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 23) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 40) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 2, 14) to (start + 0, 21) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 12, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 30) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 41) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 45) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 36) - Code(Counter(0)) at (prev + 5, 9) to (start + 0, 36) @@ -27,238 +65,277 @@ Number of file 0 mappings: 24 - Code(Counter(0)) at (prev + 8, 9) to (start + 0, 68) - Code(Counter(0)) at (prev + 10, 8) to (start + 0, 16) - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 48) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 28, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 40, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c1 + +Function name: closure::main::{closure#10} (unused) +Raw bytes (25): 0x[01, 01, 00, 04, 00, 9b, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 155, 7) to (start + 0, 8) +- Code(Zero) at (prev + 0, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 0, 32) to (start + 0, 33) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#11} (unused) +Raw bytes (25): 0x[01, 01, 00, 04, 00, 9f, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 159, 7) to (start + 0, 8) +- Code(Zero) at (prev + 0, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 0, 32) to (start + 0, 33) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#12} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 0a, 00, 16] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 167, 10) to (start + 0, 22) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#13} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 00, ad, 01, 11, 00, 1d] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 173, 17) to (start + 0, 29) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#14} +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b4, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) -Highest counter ID seen: c1 - -Function name: closure::main::{closure#10} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 155, 7) to (start + 0, 33) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#11} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9f, 01, 07, 00, 21] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 159, 7) to (start + 0, 33) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#12} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 01, 00, 17] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 167, 1) to (start + 0, 23) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#13} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, ac, 01, 0d, 02, 0e] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 172, 13) to (start + 2, 14) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#14} -Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27) -- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +- Code(Counter(0)) at (prev + 180, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) Highest counter ID seen: c1 Function name: closure::main::{closure#15} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 Function name: closure::main::{closure#16} -Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c6, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27) -- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 198, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) Highest counter ID seen: c1 Function name: closure::main::{closure#17} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 Function name: closure::main::{closure#18} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 19, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 25, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#19} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 43, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 67, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 52, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 82, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 68, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 11, 00, 17, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 104, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) -Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 01, 06] +Raw bytes (40): 0x[01, 01, 00, 07, 00, 81, 01, 05, 00, 06, 00, 01, 0c, 00, 14, 00, 00, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 00, 23, 00, 00, 24, 00, 2c, 00, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 7 +- Code(Zero) at (prev + 129, 5) to (start + 0, 6) +- Code(Zero) at (prev + 1, 12) to (start + 0, 20) +- Code(Zero) at (prev + 0, 21) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 9) to (start + 0, 35) +- Code(Zero) at (prev + 0, 36) to (start + 0, 44) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#5} +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 46, 00, 4e] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 140, 70) to (start + 0, 78) +Highest counter ID seen: c0 + +Function name: closure::main::{closure#6} +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 4a, 00, 56] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 141, 74) to (start + 0, 86) +Highest counter ID seen: c0 + +Function name: closure::main::{closure#7} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 44, 00, 50] +Number of files: 1 +- file 0 => $DIR/closure.rs +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 142, 68) to (start + 0, 80) +Highest counter ID seen: (none) + +Function name: closure::main::{closure#8} (unused) +Raw bytes (25): 0x[01, 01, 00, 04, 00, 93, 01, 3b, 00, 3c, 00, 00, 3d, 00, 45, 00, 00, 46, 00, 52, 00, 00, 54, 00, 55] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Zero) at (prev + 129, 5) to (start + 1, 20) -- Code(Zero) at (prev + 1, 21) to (start + 2, 10) -- Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Zero) at (prev + 1, 9) to (start + 1, 6) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#4} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 89, 01, 35, 00, 43] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 137, 53) to (start + 0, 67) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#5} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 3d, 00, 4f] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 140, 61) to (start + 0, 79) -Highest counter ID seen: c0 - -Function name: closure::main::{closure#6} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 41, 00, 57] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 141, 65) to (start + 0, 87) -Highest counter ID seen: c0 - -Function name: closure::main::{closure#7} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 3b, 00, 51] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 142, 59) to (start + 0, 81) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#8} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 93, 01, 3b, 00, 55] -Number of files: 1 -- file 0 => $DIR/closure.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 147, 59) to (start + 0, 85) +- Code(Zero) at (prev + 147, 59) to (start + 0, 60) +- Code(Zero) at (prev + 0, 61) to (start + 0, 69) +- Code(Zero) at (prev + 0, 70) to (start + 0, 82) +- Code(Zero) at (prev + 0, 84) to (start + 0, 85) Highest counter ID seen: (none) Function name: closure::main::{closure#9} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 95, 01, 38, 02, 06] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 95, 01, 38, 00, 39, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 149, 56) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 149, 56) to (start + 0, 57) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 2deeb9806c4d..142852692289 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -7,18 +7,18 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let is_false = !is_true; - LL| 1| + LL| | LL| 1| let mut some_string = Some(String::from("the string content")); LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else LL| | ( LL| | || @@ -33,7 +33,7 @@ LL| | ); LL| | LL| 1| some_string = Some(String::from("the string content")); - LL| 1| let + LL| | let LL| 1| a LL| | = LL| | || @@ -46,21 +46,21 @@ LL| 0| }; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else - LL| 1| ( + LL| | ( LL| 1| a - LL| 1| ) - LL| 1| ); - LL| 1| + LL| | ) + LL| | ); + LL| | LL| 1| some_string = None; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else LL| | ( LL| | || @@ -75,7 +75,7 @@ LL| | ); LL| | LL| 1| some_string = None; - LL| 1| let + LL| | let LL| 1| a LL| | = LL| | || @@ -88,16 +88,16 @@ LL| 1| }; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else - LL| 1| ( + LL| | ( LL| 1| a - LL| 1| ) - LL| 1| ); - LL| 1| - LL| 1| let + LL| | ) + LL| | ); + LL| | + LL| | let LL| 1| quote_closure LL| | = LL| | |val| @@ -110,17 +110,17 @@ LL| 5| }; LL| 1| println!( LL| 1| "Repeated, quoted string: {:?}" - LL| 1| , + LL| | , LL| 1| std::iter::repeat("repeat me") LL| 1| .take(5) LL| 1| .map - LL| 1| ( + LL| | ( LL| 1| quote_closure - LL| 1| ) + LL| | ) LL| 1| .collect::>() - LL| 1| ); - LL| 1| - LL| 1| let + LL| | ); + LL| | + LL| | let LL| 1| _unused_closure LL| | = LL| | | @@ -135,22 +135,22 @@ LL| | LL| 1| let mut countdown = 10; LL| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; - ^0 LL| | LL| | LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - ^0 + ^0 LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - ^0 + ^0 LL| | LL| | LL| | LL| | LL| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; - ^0 + ^0^0 ^0 ^0 LL| | LL| 1| let _shortish_unused_closure = | _unused_arg: u8 | { + ^0 LL| 0| println!("not called") LL| 0| }; LL| | @@ -173,14 +173,14 @@ LL| | LL| 1| let _short_unused_closure_line_break_no_block2 = LL| | | _unused_arg: u8 | - LL| 0| println!( + LL| | println!( LL| 0| "not called" - LL| 0| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = LL| | | _unused_arg: u8 | - LL| 0| println!( + LL| | println!( LL| 0| "not called: {}", LL| 0| if is_true { "check" } else { "me" } LL| | ) @@ -198,7 +198,7 @@ LL| | LL| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = LL| | | _unused_arg: u8 | - LL| 1| println!( + LL| | println!( LL| 1| "not called: {}", LL| 1| if is_true { "check" } else { "me" } ^0 diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 8355cbf352b3..a7087c69dcba 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,5 +1,5 @@ Function name: closure_bug::main -Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] +Raw bytes (132): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 18, 01, 07, 01, 00, 0a, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 2d, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 05, 00, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 09, 00, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 0d, 00, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 11, 00, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_bug.rs Number of expressions: 4 @@ -7,38 +7,45 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) - expression 3 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 17 -- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10) -- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14) -- Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23) +Number of file 0 mappings: 24 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 45) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(0, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(1, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(2, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c3) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(4)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(3, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c4) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: closure_bug::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 - file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 14, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -46,13 +53,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 - file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 23, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 23, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -60,13 +67,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 - file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 32, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 32, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -74,13 +81,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#3} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 - file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 41, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 41, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage index cc64470baa77..b85375d1850b 100644 --- a/tests/coverage/closure_bug.coverage +++ b/tests/coverage/closure_bug.coverage @@ -6,7 +6,7 @@ LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let truthy = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let a LL| | = LL| | | diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index c624896a720a..3ab1d7f5fba8 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -1,41 +1,57 @@ Function name: closure_macro::load_configuration_files -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 1d, 01, 00, 38, 01, 01, 05, 00, 1f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_macro.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_macro::main -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (66): 0x[01, 01, 01, 01, 05, 0c, 01, 21, 01, 00, 24, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 02, 01, 09, 00, 0f, 01, 00, 12, 00, 1b, 01, 00, 1c, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 00, 1f, 02, 00, 22, 00, 2e, 02, 01, 0d, 00, 2d, 02, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_macro.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 32) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 27) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 31) = (c0 - c1) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 46) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 45) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 10, 1c, 00, 1d, 01, 02, 11, 00, 18, 01, 00, 1b, 00, 22, 01, 01, 10, 00, 21, 05, 01, 11, 00, 19, 05, 00, 1a, 00, 1e, 05, 01, 11, 00, 27, 02, 02, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/closure_macro.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) -- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 16, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 33) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 30) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 39) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 22) = (c0 - c1) - Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) = (c0 - (c1 + c2)) diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/closure_macro.coverage index 00022bbff89f..b1d7a8327a4e 100644 --- a/tests/coverage/closure_macro.coverage +++ b/tests/coverage/closure_macro.coverage @@ -14,7 +14,7 @@ LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { LL| 0| $value.or_else(|e| { - LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| | // This closure, which is declared in a macro, should be instrumented. LL| 0| let message = format!($error_message, e); LL| 0| if message.len() > 0 { LL| 0| println!("{}", message); diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 77bf31de8bd8..b5f4cee0ec44 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -1,50 +1,66 @@ Function name: closure_macro_async::load_configuration_files -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 21, 01, 00, 38, 01, 01, 05, 00, 1f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_macro_async::test -Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 00, 2b] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 00, 2a] Number of files: 1 - file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 43) +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 42) Highest counter ID seen: c0 Function name: closure_macro_async::test::{closure#0} -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 25, 2b, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (66): 0x[01, 01, 01, 01, 05, 0c, 01, 25, 2b, 00, 2c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 02, 01, 09, 00, 0f, 01, 00, 12, 00, 1b, 01, 00, 1c, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 00, 1f, 02, 00, 22, 00, 2e, 02, 01, 0d, 00, 2d, 02, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_macro_async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 37, 43) to (start + 1, 32) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 37, 43) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 27) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 31) = (c0 - c1) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 46) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 45) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 14, 1c, 00, 1d, 01, 02, 11, 00, 18, 01, 00, 1b, 00, 22, 01, 01, 10, 00, 21, 05, 01, 11, 00, 19, 05, 00, 1a, 00, 1e, 05, 01, 11, 00, 27, 02, 02, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/closure_macro_async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 20, 28) to (start + 3, 33) -- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 20, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 33) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 30) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 39) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 22) = (c0 - c1) - Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) = (c0 - (c1 + c2)) diff --git a/tests/coverage/closure_macro_async.coverage b/tests/coverage/closure_macro_async.coverage index 1e1ffec9f761..7bfea3c9bb3b 100644 --- a/tests/coverage/closure_macro_async.coverage +++ b/tests/coverage/closure_macro_async.coverage @@ -18,7 +18,7 @@ LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { LL| 0| $value.or_else(|e| { - LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| | // This closure, which is declared in a macro, should be instrumented. LL| 0| let message = format!($error_message, e); LL| 0| if message.len() > 0 { LL| 0| println!("{}", message); diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map index c75119019fc8..f665d93e6e1c 100644 --- a/tests/coverage/closure_unit_return.cov-map +++ b/tests/coverage/closure_unit_return.cov-map @@ -1,38 +1,49 @@ Function name: closure_unit_return::explicit_unit -Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 01, 01, 10, 01, 05, 05, 02, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 07, 01, 00, 13, 01, 01, 09, 00, 10, 01, 04, 05, 00, 09, 01, 00, 0a, 00, 11, 01, 01, 05, 00, 07, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 7) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_unit_return::explicit_unit::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 08, 16, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 08, 16, 00, 17, 00, 01, 09, 00, 0b, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 8, 22) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 8, 22) to (start + 0, 23) +- Code(Zero) at (prev + 1, 9) to (start + 0, 11) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: closure_unit_return::implicit_unit -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 10, 01, 05, 05, 02, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 10, 01, 00, 13, 01, 01, 09, 00, 10, 01, 04, 05, 00, 09, 01, 00, 0a, 00, 11, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 0, 17) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_unit_return::implicit_unit::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 11, 16, 00, 17, 00, 01, 09, 00, 0b, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 22) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 17, 22) to (start + 0, 23) +- Code(Zero) at (prev + 1, 9) to (start + 0, 11) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure_unit_return.coverage b/tests/coverage/closure_unit_return.coverage index 5e57e0db1600..02ea63b6dc39 100644 --- a/tests/coverage/closure_unit_return.coverage +++ b/tests/coverage/closure_unit_return.coverage @@ -6,6 +6,7 @@ LL| | LL| 1|fn explicit_unit() { LL| 1| let closure = || { + ^0 LL| 0| (); LL| 0| }; LL| | @@ -15,11 +16,12 @@ LL| | LL| 1|fn implicit_unit() { LL| 1| let closure = || { + ^0 LL| 0| (); LL| 0| }; LL| | LL| 1| drop(closure); - LL| 1| // implicit return of `()` + LL| | // implicit return of `()` LL| 1|} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index 1bcf045b8942..fda5dd1b97d1 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -1,5 +1,5 @@ Function name: conditions::assign_3_and_or -Raw bytes (65): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 1c, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (75): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0b, 01, 1c, 01, 00, 2e, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 5 @@ -8,8 +8,8 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 28, 1) to (start + 0, 47) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 28, 1) to (start + 0, 46) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -24,11 +24,13 @@ Number of file 0 mappings: 9 - Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c0 - (c2 + c3)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: conditions::assign_3_or_and -Raw bytes (63): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 09, 01, 17, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (73): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0b, 01, 17, 01, 00, 2e, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 4 @@ -36,8 +38,8 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 46) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -52,18 +54,20 @@ Number of file 0 mappings: 9 - Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c2 - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: conditions::assign_and -Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 0d, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (57): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 0d, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 32) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -73,19 +77,21 @@ Number of file 0 mappings: 7 - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: conditions::assign_or -Raw bytes (49): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 07, 01, 12, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (59): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 09, 01, 12, 01, 00, 1f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 18, 1) to (start + 0, 32) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 18, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -96,27 +102,32 @@ Number of file 0 mappings: 7 - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: conditions::foo -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: conditions::func_call -Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 1f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) - Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 9) to (start + 0, 10) @@ -130,11 +141,16 @@ Number of file 0 mappings: 7 Highest counter ID seen: c2 Function name: conditions::simple_assign -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 08, 01, 00, 1a, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 86a317948132..29d9604085ed 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,8 +1,8 @@ Function name: conditions::main -Raw bytes (533): 0x[01, 01, 47, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 97, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 97, 01, 15, 0d, 11, 19, 45, 19, 8f, 01, 45, 49, 8f, 01, 4d, 45, 49, 19, 8b, 01, 8f, 01, 4d, 45, 49, 97, 01, db, 01, 0d, 11, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, db, 01, 1d, 15, 19, 21, 39, 21, d3, 01, 39, 3d, d3, 01, 41, 39, 3d, 21, cf, 01, d3, 01, 41, 39, 3d, db, 01, 97, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, 97, 02, 25, 1d, 21, 29, 2d, 29, 8f, 02, 2d, 31, 8f, 02, 35, 2d, 31, 29, 8b, 02, 8f, 02, 35, 2d, 31, 97, 02, 9b, 02, 1d, 21, 25, 29, 44, 01, 03, 01, 02, 0c, 01, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 01, 0a, 06, 02, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 01, 12, 2a, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 03, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 97, 01, 03, 08, 00, 0c, 97, 01, 01, 0d, 01, 10, 97, 01, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 97, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 6a, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 72, 00, 21, 00, 2e, 76, 00, 32, 00, 40, 8b, 01, 00, 41, 02, 0e, 86, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 92, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, db, 01, 02, 09, 01, 0c, db, 01, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 97, 02, 02, 09, 00, 0a, db, 01, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, ae, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, b6, 01, 00, 1d, 00, 2a, ba, 01, 00, 2e, 00, 3c, cf, 01, 00, 3d, 02, 0a, ca, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, d6, 01, 02, 0d, 02, 0f, 9b, 02, 05, 09, 00, 0a, 97, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, ea, 01, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, f2, 01, 00, 1d, 00, 2a, f6, 01, 00, 2e, 00, 3c, 8b, 02, 00, 3d, 02, 0a, 86, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, 92, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (656): 0x[01, 01, 57, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 9f, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 9f, 01, 15, 0d, 11, 19, 45, 19, 97, 01, 45, 49, 97, 01, 4d, 45, 49, 19, 93, 01, 97, 01, 4d, 45, 49, 9f, 01, 9b, 02, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, 9b, 02, 1d, 15, 19, 21, 39, 21, e3, 01, 39, 3d, e3, 01, 41, 39, 3d, 21, df, 01, e3, 01, 41, 39, 3d, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, d7, 02, 25, 1d, 21, 29, 2d, 29, cf, 02, 2d, 31, cf, 02, 35, 2d, 31, 29, cb, 02, cf, 02, 35, 2d, 31, d7, 02, db, 02, 1d, 21, 25, 29, 53, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 2a, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 9f, 01, 03, 08, 00, 0c, 9f, 01, 01, 0d, 00, 1a, 9f, 01, 00, 1d, 00, 1e, 9f, 01, 01, 0c, 00, 10, 9f, 01, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 9f, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 72, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 7a, 00, 21, 00, 2e, 7e, 00, 32, 00, 40, 93, 01, 00, 41, 02, 0e, 8e, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 9a, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 9b, 02, 02, 09, 00, 16, 9b, 02, 00, 19, 00, 1a, 9b, 02, 01, 08, 00, 0c, 9b, 02, 00, 0d, 02, 06, 00, 02, 05, 00, 06, d7, 02, 02, 09, 00, 0a, 9b, 02, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, be, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, c6, 01, 00, 1d, 00, 2a, ca, 01, 00, 2e, 00, 3c, df, 01, 00, 3d, 02, 0a, da, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, 96, 02, 02, 0d, 00, 20, 96, 02, 00, 23, 00, 2c, 96, 02, 01, 09, 00, 11, 96, 02, 00, 12, 00, 1b, 96, 02, 01, 09, 00, 0f, db, 02, 03, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, aa, 02, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, b2, 02, 00, 1d, 00, 2a, b6, 02, 00, 2e, 00, 3c, cb, 02, 00, 3d, 02, 0a, c6, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, d2, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs -Number of expressions: 71 +Number of expressions: 87 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) - expression 2 operands: lhs = Counter(2), rhs = Counter(23) @@ -23,66 +23,86 @@ Number of expressions: 71 - expression 17 operands: lhs = Counter(4), rhs = Expression(18, Add) - expression 18 operands: lhs = Expression(19, Add), rhs = Counter(22) - expression 19 operands: lhs = Counter(20), rhs = Counter(21) -- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(37, Add) +- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(39, Add) - expression 21 operands: lhs = Counter(3), rhs = Counter(4) - expression 22 operands: lhs = Counter(3), rhs = Counter(4) - expression 23 operands: lhs = Counter(3), rhs = Counter(4) - expression 24 operands: lhs = Counter(3), rhs = Counter(4) - expression 25 operands: lhs = Counter(3), rhs = Counter(4) -- expression 26 operands: lhs = Expression(37, Add), rhs = Counter(5) +- expression 26 operands: lhs = Counter(3), rhs = Counter(4) - expression 27 operands: lhs = Counter(3), rhs = Counter(4) -- expression 28 operands: lhs = Counter(6), rhs = Counter(17) -- expression 29 operands: lhs = Counter(6), rhs = Expression(35, Add) -- expression 30 operands: lhs = Counter(17), rhs = Counter(18) -- expression 31 operands: lhs = Expression(35, Add), rhs = Counter(19) +- expression 28 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 29 operands: lhs = Counter(3), rhs = Counter(4) +- expression 30 operands: lhs = Counter(6), rhs = Counter(17) +- expression 31 operands: lhs = Counter(6), rhs = Expression(37, Add) - expression 32 operands: lhs = Counter(17), rhs = Counter(18) -- expression 33 operands: lhs = Counter(6), rhs = Expression(34, Add) -- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(19) -- expression 35 operands: lhs = Counter(17), rhs = Counter(18) -- expression 36 operands: lhs = Expression(37, Add), rhs = Expression(54, Add) -- expression 37 operands: lhs = Counter(3), rhs = Counter(4) -- expression 38 operands: lhs = Counter(5), rhs = Counter(6) -- expression 39 operands: lhs = Counter(5), rhs = Counter(6) +- expression 33 operands: lhs = Expression(37, Add), rhs = Counter(19) +- expression 34 operands: lhs = Counter(17), rhs = Counter(18) +- expression 35 operands: lhs = Counter(6), rhs = Expression(36, Add) +- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(19) +- expression 37 operands: lhs = Counter(17), rhs = Counter(18) +- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(70, Add) +- expression 39 operands: lhs = Counter(3), rhs = Counter(4) - expression 40 operands: lhs = Counter(5), rhs = Counter(6) -- expression 41 operands: lhs = Counter(7), rhs = Counter(8) +- expression 41 operands: lhs = Counter(5), rhs = Counter(6) - expression 42 operands: lhs = Counter(5), rhs = Counter(6) -- expression 43 operands: lhs = Expression(54, Add), rhs = Counter(7) +- expression 43 operands: lhs = Counter(5), rhs = Counter(6) - expression 44 operands: lhs = Counter(5), rhs = Counter(6) -- expression 45 operands: lhs = Counter(8), rhs = Counter(14) -- expression 46 operands: lhs = Counter(8), rhs = Expression(52, Add) -- expression 47 operands: lhs = Counter(14), rhs = Counter(15) -- expression 48 operands: lhs = Expression(52, Add), rhs = Counter(16) -- expression 49 operands: lhs = Counter(14), rhs = Counter(15) -- expression 50 operands: lhs = Counter(8), rhs = Expression(51, Add) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(16) -- expression 52 operands: lhs = Counter(14), rhs = Counter(15) -- expression 53 operands: lhs = Expression(54, Add), rhs = Expression(69, Add) -- expression 54 operands: lhs = Counter(5), rhs = Counter(6) -- expression 55 operands: lhs = Counter(7), rhs = Counter(8) -- expression 56 operands: lhs = Counter(9), rhs = Counter(10) -- expression 57 operands: lhs = Counter(7), rhs = Counter(8) -- expression 58 operands: lhs = Expression(69, Add), rhs = Counter(9) +- expression 45 operands: lhs = Counter(7), rhs = Counter(8) +- expression 46 operands: lhs = Counter(5), rhs = Counter(6) +- expression 47 operands: lhs = Expression(70, Add), rhs = Counter(7) +- expression 48 operands: lhs = Counter(5), rhs = Counter(6) +- expression 49 operands: lhs = Counter(8), rhs = Counter(14) +- expression 50 operands: lhs = Counter(8), rhs = Expression(56, Add) +- expression 51 operands: lhs = Counter(14), rhs = Counter(15) +- expression 52 operands: lhs = Expression(56, Add), rhs = Counter(16) +- expression 53 operands: lhs = Counter(14), rhs = Counter(15) +- expression 54 operands: lhs = Counter(8), rhs = Expression(55, Add) +- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(16) +- expression 56 operands: lhs = Counter(14), rhs = Counter(15) +- expression 57 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 58 operands: lhs = Counter(5), rhs = Counter(6) - expression 59 operands: lhs = Counter(7), rhs = Counter(8) -- expression 60 operands: lhs = Counter(10), rhs = Counter(11) -- expression 61 operands: lhs = Counter(10), rhs = Expression(67, Add) -- expression 62 operands: lhs = Counter(11), rhs = Counter(12) -- expression 63 operands: lhs = Expression(67, Add), rhs = Counter(13) -- expression 64 operands: lhs = Counter(11), rhs = Counter(12) -- expression 65 operands: lhs = Counter(10), rhs = Expression(66, Add) -- expression 66 operands: lhs = Expression(67, Add), rhs = Counter(13) -- expression 67 operands: lhs = Counter(11), rhs = Counter(12) -- expression 68 operands: lhs = Expression(69, Add), rhs = Expression(70, Add) -- expression 69 operands: lhs = Counter(7), rhs = Counter(8) -- expression 70 operands: lhs = Counter(9), rhs = Counter(10) -Number of file 0 mappings: 68 -- Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) -- Code(Counter(0)) at (prev + 2, 13) to (start + 2, 6) +- expression 60 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 61 operands: lhs = Counter(5), rhs = Counter(6) +- expression 62 operands: lhs = Counter(7), rhs = Counter(8) +- expression 63 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 64 operands: lhs = Counter(5), rhs = Counter(6) +- expression 65 operands: lhs = Counter(7), rhs = Counter(8) +- expression 66 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 67 operands: lhs = Counter(5), rhs = Counter(6) +- expression 68 operands: lhs = Counter(7), rhs = Counter(8) +- expression 69 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 70 operands: lhs = Counter(5), rhs = Counter(6) +- expression 71 operands: lhs = Counter(7), rhs = Counter(8) +- expression 72 operands: lhs = Counter(9), rhs = Counter(10) +- expression 73 operands: lhs = Counter(7), rhs = Counter(8) +- expression 74 operands: lhs = Expression(85, Add), rhs = Counter(9) +- expression 75 operands: lhs = Counter(7), rhs = Counter(8) +- expression 76 operands: lhs = Counter(10), rhs = Counter(11) +- expression 77 operands: lhs = Counter(10), rhs = Expression(83, Add) +- expression 78 operands: lhs = Counter(11), rhs = Counter(12) +- expression 79 operands: lhs = Expression(83, Add), rhs = Counter(13) +- expression 80 operands: lhs = Counter(11), rhs = Counter(12) +- expression 81 operands: lhs = Counter(10), rhs = Expression(82, Add) +- expression 82 operands: lhs = Expression(83, Add), rhs = Counter(13) +- expression 83 operands: lhs = Counter(11), rhs = Counter(12) +- expression 84 operands: lhs = Expression(85, Add), rhs = Expression(86, Add) +- expression 85 operands: lhs = Counter(7), rhs = Counter(8) +- expression 86 operands: lhs = Counter(9), rhs = Counter(10) +Number of file 0 mappings: 83 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) = (c1 + c2) - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29) -- Code(Counter(1)) at (prev + 1, 9) to (start + 1, 10) -- Code(Expression(1, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) +- Code(Expression(1, Sub)) at (prev + 1, 15) to (start + 0, 28) = (c0 - c1) - Code(Counter(2)) at (prev + 1, 12) to (start + 0, 25) - Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42) @@ -93,12 +113,17 @@ Number of file 0 mappings: 68 = ((c23 + c24) + c25) - Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c2 - ((c23 + c24) + c25)) -- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 18) -- Code(Expression(10, Sub)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 18) +- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - (c1 + c2)) -- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12) +- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 22) = (c1 + c2) -- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(0, Add)) at (prev + 0, 25) to (start + 0, 26) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 1, 8) to (start + 0, 12) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 0, 13) to (start + 2, 6) = (c1 + c2) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) @@ -118,73 +143,89 @@ Number of file 0 mappings: 68 - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 23) - Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c1 + c2) - (c3 + c4)) -- Code(Expression(37, Add)) at (prev + 3, 8) to (start + 0, 12) +- Code(Expression(39, Add)) at (prev + 3, 8) to (start + 0, 12) = (c3 + c4) -- Code(Expression(37, Add)) at (prev + 1, 13) to (start + 1, 16) +- Code(Expression(39, Add)) at (prev + 1, 13) to (start + 0, 26) = (c3 + c4) -- Code(Expression(37, Add)) at (prev + 1, 17) to (start + 2, 10) +- Code(Expression(39, Add)) at (prev + 0, 29) to (start + 0, 30) + = (c3 + c4) +- Code(Expression(39, Add)) at (prev + 1, 12) to (start + 0, 16) + = (c3 + c4) +- Code(Expression(39, Add)) at (prev + 0, 17) to (start + 2, 10) = (c3 + c4) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(37, Add)) at (prev + 2, 12) to (start + 0, 25) +- Code(Expression(39, Add)) at (prev + 2, 12) to (start + 0, 25) = (c3 + c4) - Code(Counter(5)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(26, Sub)) at (prev + 4, 17) to (start + 0, 30) +- Code(Expression(28, Sub)) at (prev + 4, 17) to (start + 0, 30) = ((c3 + c4) - c5) - Code(Counter(6)) at (prev + 1, 16) to (start + 0, 29) -- Code(Expression(28, Sub)) at (prev + 0, 33) to (start + 0, 46) +- Code(Expression(30, Sub)) at (prev + 0, 33) to (start + 0, 46) = (c6 - c17) -- Code(Expression(29, Sub)) at (prev + 0, 50) to (start + 0, 64) +- Code(Expression(31, Sub)) at (prev + 0, 50) to (start + 0, 64) = (c6 - (c17 + c18)) -- Code(Expression(34, Add)) at (prev + 0, 65) to (start + 2, 14) +- Code(Expression(36, Add)) at (prev + 0, 65) to (start + 2, 14) = ((c17 + c18) + c19) -- Code(Expression(33, Sub)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(35, Sub)) at (prev + 2, 13) to (start + 0, 14) = (c6 - ((c17 + c18) + c19)) - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 27) -- Code(Expression(36, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 19) = ((c3 + c4) - (c5 + c6)) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(54, Add)) at (prev + 2, 9) to (start + 1, 12) +- Code(Expression(70, Add)) at (prev + 2, 9) to (start + 0, 22) = (c5 + c6) -- Code(Expression(54, Add)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(70, Add)) at (prev + 0, 25) to (start + 0, 26) + = (c5 + c6) +- Code(Expression(70, Add)) at (prev + 1, 8) to (start + 0, 12) + = (c5 + c6) +- Code(Expression(70, Add)) at (prev + 0, 13) to (start + 2, 6) = (c5 + c6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(69, Add)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(85, Add)) at (prev + 2, 9) to (start + 0, 10) = (c7 + c8) -- Code(Expression(54, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(70, Add)) at (prev + 0, 16) to (start + 0, 29) = (c5 + c6) - Code(Counter(7)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(43, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(47, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c5 + c6) - c7) - Code(Counter(8)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(45, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(49, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c8 - c14) -- Code(Expression(46, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(50, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c8 - (c14 + c15)) -- Code(Expression(51, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(55, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c14 + c15) + c16) -- Code(Expression(50, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(54, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c8 - ((c14 + c15) + c16)) - Code(Counter(8)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(53, Sub)) at (prev + 2, 13) to (start + 2, 15) +- Code(Expression(69, Sub)) at (prev + 2, 13) to (start + 0, 32) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(70, Add)) at (prev + 5, 9) to (start + 0, 10) +- Code(Expression(69, Sub)) at (prev + 0, 35) to (start + 0, 44) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 17) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 0, 18) to (start + 0, 27) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 15) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(86, Add)) at (prev + 3, 9) to (start + 0, 10) = (c9 + c10) -- Code(Expression(69, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29) = (c7 + c8) - Code(Counter(9)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(58, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(74, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c7 + c8) - c9) - Code(Counter(10)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(60, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(76, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c10 - c11) -- Code(Expression(61, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(77, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c10 - (c11 + c12)) -- Code(Expression(66, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(82, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c11 + c12) + c13) -- Code(Expression(65, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(81, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c10 - ((c11 + c12) + c13)) - Code(Counter(10)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(68, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(84, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c7 + c8) - (c9 + c10)) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c10 diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index a8077a32df7d..1a839f19a0f5 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -1,75 +1,88 @@ Function name: continue::main -Raw bytes (198): 0x[01, 01, 16, 05, 01, 05, 0b, 01, 09, 0d, 01, 0d, 1f, 01, 11, 0d, 1f, 01, 11, 15, 01, 15, 2b, 01, 19, 1d, 01, 1d, 37, 01, 21, 25, 01, 25, 43, 01, 29, 25, 01, 2d, 01, 53, 2d, 01, 31, 2d, 01, 1e, 01, 03, 01, 03, 12, 05, 04, 0e, 00, 13, 02, 01, 0f, 00, 16, 09, 02, 11, 00, 19, 06, 02, 12, 04, 0e, 0d, 06, 0e, 00, 13, 0e, 01, 0f, 00, 16, 1a, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 1a, 03, 09, 00, 0e, 15, 02, 0e, 00, 13, 22, 01, 0f, 00, 16, 19, 01, 15, 02, 0e, 26, 04, 11, 00, 19, 19, 03, 09, 00, 0e, 1d, 02, 0e, 00, 13, 2e, 01, 0c, 00, 13, 21, 01, 0d, 00, 15, 32, 01, 0a, 01, 0e, 25, 03, 0e, 00, 13, 46, 01, 0f, 00, 16, 3e, 01, 16, 02, 0e, 29, 03, 12, 02, 0e, 46, 04, 09, 00, 0e, 2d, 02, 0e, 00, 13, 31, 01, 0f, 00, 16, 56, 01, 16, 02, 0e, 4e, 04, 11, 00, 16, 56, 03, 09, 00, 0e, 01, 02, 0d, 01, 02] +Raw bytes (241): 0x[01, 01, 1a, 05, 01, 05, 13, 01, 09, 05, 13, 01, 09, 0d, 01, 0d, 27, 01, 11, 0d, 27, 01, 11, 15, 01, 15, 33, 01, 19, 1d, 01, 1d, 47, 01, 21, 1d, 47, 01, 21, 25, 01, 25, 53, 01, 29, 25, 01, 2d, 01, 63, 2d, 01, 31, 2d, 01, 25, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0e, 00, 13, 02, 01, 0f, 00, 16, 09, 02, 11, 00, 19, 0e, 02, 12, 02, 0e, 0e, 04, 09, 00, 0e, 0d, 02, 0e, 00, 13, 16, 01, 0f, 00, 16, 22, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 22, 03, 09, 00, 0e, 15, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 19, 01, 15, 02, 0e, 2e, 04, 11, 00, 19, 19, 03, 09, 00, 0e, 1d, 02, 0e, 00, 13, 36, 01, 0c, 00, 13, 21, 01, 0d, 00, 15, 42, 01, 09, 00, 0a, 42, 01, 09, 00, 0e, 25, 02, 0e, 00, 13, 56, 01, 0f, 00, 16, 4e, 01, 16, 02, 0e, 29, 03, 12, 02, 0e, 56, 04, 09, 00, 0e, 2d, 02, 0e, 00, 13, 31, 01, 0f, 00, 16, 66, 01, 16, 02, 0e, 5e, 04, 11, 00, 16, 66, 03, 09, 00, 0e, 01, 02, 0d, 00, 0e, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/continue.rs -Number of expressions: 22 +Number of expressions: 26 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) +- expression 1 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -- expression 3 operands: lhs = Counter(3), rhs = Counter(0) -- expression 4 operands: lhs = Counter(3), rhs = Expression(7, Add) -- expression 5 operands: lhs = Counter(0), rhs = Counter(4) -- expression 6 operands: lhs = Counter(3), rhs = Expression(7, Add) +- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(0), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(0) +- expression 6 operands: lhs = Counter(3), rhs = Expression(9, Add) - expression 7 operands: lhs = Counter(0), rhs = Counter(4) -- expression 8 operands: lhs = Counter(5), rhs = Counter(0) -- expression 9 operands: lhs = Counter(5), rhs = Expression(10, Add) -- expression 10 operands: lhs = Counter(0), rhs = Counter(6) -- expression 11 operands: lhs = Counter(7), rhs = Counter(0) -- expression 12 operands: lhs = Counter(7), rhs = Expression(13, Add) -- expression 13 operands: lhs = Counter(0), rhs = Counter(8) -- expression 14 operands: lhs = Counter(9), rhs = Counter(0) -- expression 15 operands: lhs = Counter(9), rhs = Expression(16, Add) -- expression 16 operands: lhs = Counter(0), rhs = Counter(10) -- expression 17 operands: lhs = Counter(9), rhs = Counter(0) -- expression 18 operands: lhs = Counter(11), rhs = Counter(0) -- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(11) -- expression 20 operands: lhs = Counter(0), rhs = Counter(12) -- expression 21 operands: lhs = Counter(11), rhs = Counter(0) -Number of file 0 mappings: 30 -- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18) -- Code(Counter(1)) at (prev + 4, 14) to (start + 0, 19) +- expression 8 operands: lhs = Counter(3), rhs = Expression(9, Add) +- expression 9 operands: lhs = Counter(0), rhs = Counter(4) +- expression 10 operands: lhs = Counter(5), rhs = Counter(0) +- expression 11 operands: lhs = Counter(5), rhs = Expression(12, Add) +- expression 12 operands: lhs = Counter(0), rhs = Counter(6) +- expression 13 operands: lhs = Counter(7), rhs = Counter(0) +- expression 14 operands: lhs = Counter(7), rhs = Expression(17, Add) +- expression 15 operands: lhs = Counter(0), rhs = Counter(8) +- expression 16 operands: lhs = Counter(7), rhs = Expression(17, Add) +- expression 17 operands: lhs = Counter(0), rhs = Counter(8) +- expression 18 operands: lhs = Counter(9), rhs = Counter(0) +- expression 19 operands: lhs = Counter(9), rhs = Expression(20, Add) +- expression 20 operands: lhs = Counter(0), rhs = Counter(10) +- expression 21 operands: lhs = Counter(9), rhs = Counter(0) +- expression 22 operands: lhs = Counter(11), rhs = Counter(0) +- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(11) +- expression 24 operands: lhs = Counter(0), rhs = Counter(12) +- expression 25 operands: lhs = Counter(11), rhs = Counter(0) +Number of file 0 mappings: 37 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c1 - c0) - Code(Counter(2)) at (prev + 2, 17) to (start + 0, 25) -- Code(Expression(1, Sub)) at (prev + 2, 18) to (start + 4, 14) +- Code(Expression(3, Sub)) at (prev + 2, 18) to (start + 2, 14) = (c1 - (c0 + c2)) -- Code(Counter(3)) at (prev + 6, 14) to (start + 0, 19) -- Code(Expression(3, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(3, Sub)) at (prev + 4, 9) to (start + 0, 14) + = (c1 - (c0 + c2)) +- Code(Counter(3)) at (prev + 2, 14) to (start + 0, 19) +- Code(Expression(5, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c3 - c0) -- Code(Expression(6, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(8, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c3 - (c0 + c4)) - Code(Counter(4)) at (prev + 4, 17) to (start + 0, 25) -- Code(Expression(6, Sub)) at (prev + 3, 9) to (start + 0, 14) +- Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 14) = (c3 - (c0 + c4)) - Code(Counter(5)) at (prev + 2, 14) to (start + 0, 19) -- Code(Expression(8, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(10, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c5 - c0) - Code(Counter(6)) at (prev + 1, 21) to (start + 2, 14) -- Code(Expression(9, Sub)) at (prev + 4, 17) to (start + 0, 25) +- Code(Expression(11, Sub)) at (prev + 4, 17) to (start + 0, 25) = (c5 - (c0 + c6)) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 14) - Code(Counter(7)) at (prev + 2, 14) to (start + 0, 19) -- Code(Expression(11, Sub)) at (prev + 1, 12) to (start + 0, 19) +- Code(Expression(13, Sub)) at (prev + 1, 12) to (start + 0, 19) = (c7 - c0) - Code(Counter(8)) at (prev + 1, 13) to (start + 0, 21) -- Code(Expression(12, Sub)) at (prev + 1, 10) to (start + 1, 14) +- Code(Expression(16, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c7 - (c0 + c8)) -- Code(Counter(9)) at (prev + 3, 14) to (start + 0, 19) -- Code(Expression(17, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(16, Sub)) at (prev + 1, 9) to (start + 0, 14) + = (c7 - (c0 + c8)) +- Code(Counter(9)) at (prev + 2, 14) to (start + 0, 19) +- Code(Expression(21, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c9 - c0) -- Code(Expression(15, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(19, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c9 - (c0 + c10)) - Code(Counter(10)) at (prev + 3, 18) to (start + 2, 14) -- Code(Expression(17, Sub)) at (prev + 4, 9) to (start + 0, 14) +- Code(Expression(21, Sub)) at (prev + 4, 9) to (start + 0, 14) = (c9 - c0) - Code(Counter(11)) at (prev + 2, 14) to (start + 0, 19) - Code(Counter(12)) at (prev + 1, 15) to (start + 0, 22) -- Code(Expression(21, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(25, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c11 - c0) -- Code(Expression(19, Sub)) at (prev + 4, 17) to (start + 0, 22) +- Code(Expression(23, Sub)) at (prev + 4, 17) to (start + 0, 22) = ((c0 + c12) - c11) -- Code(Expression(21, Sub)) at (prev + 3, 9) to (start + 0, 14) +- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 14) = (c11 - c0) -- Code(Counter(0)) at (prev + 2, 13) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c12 diff --git a/tests/coverage/continue.coverage b/tests/coverage/continue.coverage index 4916cac0038e..17fe4874d151 100644 --- a/tests/coverage/continue.coverage +++ b/tests/coverage/continue.coverage @@ -2,7 +2,7 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut x = 0; LL| 11| for _ in 0..10 { LL| 10| match is_true { @@ -12,7 +12,7 @@ LL| 0| _ => { LL| 0| x = 1; LL| 0| } - LL| 0| } + LL| | } LL| 0| x = 3; LL| | } LL| 11| for _ in 0..10 { diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 0ce915538638..daa42915a4af 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -1,31 +1,40 @@ Function name: coroutine::get_u32 -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0b, 01, 00, 2d, 01, 01, 08, 00, 0b, 05, 01, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/coroutine.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 11) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 14) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: coroutine::main -Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] +Raw bytes (93): 0x[01, 01, 02, 01, 05, 05, 09, 11, 01, 13, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 06, 0b, 00, 13, 01, 00, 14, 00, 22, 01, 00, 24, 00, 2a, 01, 00, 2b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 13, 05, 00, 0b, 00, 2e, 05, 00, 14, 00, 22, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/coroutine.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) -- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 45) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 36) to (start + 0, 42) +- Code(Counter(0)) at (prev + 0, 43) to (start + 0, 45) - Code(Counter(1)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(1)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) - Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) @@ -34,12 +43,14 @@ Number of file 0 mappings: 9 Highest counter ID seen: c3 Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 08, 00, 09, 01, 01, 09, 00, 1f, 05, 01, 10, 00, 15, 05, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/coroutine.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) -- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 31) +- Code(Counter(1)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map index e029a3b4643e..deba65f22cca 100644 --- a/tests/coverage/coverage_attr_closure.cov-map +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -1,38 +1,48 @@ Function name: coverage_attr_closure::GLOBAL_CLOSURE_ON::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 0f, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 06, 0f, 00, 10, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 6, 15) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 6, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_off::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 13, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1d, 13, 00, 14, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 29, 19) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 29, 19) to (start + 0, 20) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: coverage_attr_closure::contains_closures_on -Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 01, 1a, 01, 05, 09, 00, 1b, 01, 04, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 01, 00, 1a, 01, 01, 09, 00, 1a, 01, 04, 09, 00, 1b, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 15, 1) to (start + 1, 26) -- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 27) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 27) - Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 11, 13, 00, 14, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 19) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 17, 19) to (start + 0, 20) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index 4cb311428a18..ae4146dc2467 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -1,37 +1,52 @@ Function name: dead_code::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 1b, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/dead_code.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 00, 0f, 01, 00, 0f, 00, 04, 09, 00, 10, 00, 00, 13, 00, 2e, 00, 02, 09, 00, 16, 00, 00, 19, 00, 1a, 00, 01, 08, 00, 0f, 00, 00, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/dead_code.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 15, 1) to (start + 7, 15) -- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Zero) at (prev + 15, 1) to (start + 0, 15) +- Code(Zero) at (prev + 4, 9) to (start + 0, 16) +- Code(Zero) at (prev + 0, 19) to (start + 0, 46) +- Code(Zero) at (prev + 2, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 25) to (start + 0, 26) +- Code(Zero) at (prev + 1, 8) to (start + 0, 15) +- Code(Zero) at (prev + 0, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 00, 03, 01, 00, 26, 00, 04, 09, 00, 10, 00, 00, 13, 00, 2e, 00, 02, 09, 00, 16, 00, 00, 19, 00, 1a, 00, 01, 08, 00, 0f, 00, 00, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/dead_code.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 3, 1) to (start + 7, 15) -- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Zero) at (prev + 3, 1) to (start + 0, 38) +- Code(Zero) at (prev + 4, 9) to (start + 0, 16) +- Code(Zero) at (prev + 0, 19) to (start + 0, 46) +- Code(Zero) at (prev + 2, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 25) to (start + 0, 26) +- Code(Zero) at (prev + 1, 8) to (start + 0, 15) +- Code(Zero) at (prev + 0, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.coverage b/tests/coverage/dead_code.coverage index 55d196f81604..fbb4a001d959 100644 --- a/tests/coverage/dead_code.coverage +++ b/tests/coverage/dead_code.coverage @@ -1,11 +1,11 @@ LL| |#![allow(dead_code, unused_assignments, unused_variables)] LL| | LL| 0|pub fn unused_pub_fn_not_in_library() { - LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 0| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 0| let is_true = std::env::args().len() == 1; - LL| 0| + LL| | LL| 0| let mut countdown = 0; LL| 0| if is_true { LL| 0| countdown = 10; @@ -13,11 +13,11 @@ LL| 0|} LL| | LL| 0|fn unused_fn() { - LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 0| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 0| let is_true = std::env::args().len() == 1; - LL| 0| + LL| | LL| 0| let mut countdown = 0; LL| 0| if is_true { LL| 0| countdown = 10; @@ -25,11 +25,11 @@ LL| 0|} LL| | LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; LL| 1| if is_true { LL| 1| countdown = 10; diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map index a52ebd87aa82..dcf9dbd8c647 100644 --- a/tests/coverage/drop_trait.cov-map +++ b/tests/coverage/drop_trait.cov-map @@ -1,21 +1,33 @@ Function name: ::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 05, 02, 06] -Number of files: 1 -- file 0 => $DIR/drop_trait.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6) -Highest counter ID seen: c0 - -Function name: drop_trait::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 01, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/drop_trait.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12) -- Code(Counter(0)) at (prev + 6, 9) to (start + 1, 22) -- Code(Zero) at (prev + 2, 6) to (start + 4, 11) -- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c0 + +Function name: drop_trait::main +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 0e, 01, 00, 1c, 01, 01, 09, 00, 15, 01, 00, 18, 00, 30, 01, 02, 09, 00, 0d, 01, 00, 10, 00, 2a, 01, 02, 08, 00, 0c, 01, 01, 09, 00, 11, 01, 00, 12, 00, 29, 01, 01, 10, 00, 16, 00, 01, 05, 00, 06, 00, 02, 0d, 00, 28, 00, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/drop_trait.rs +Number of expressions: 0 +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 48) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 42) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 22) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +- Code(Zero) at (prev + 2, 13) to (start + 0, 40) +- Code(Zero) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/drop_trait.coverage b/tests/coverage/drop_trait.coverage index 85d557573cf3..10ed8c0f154f 100644 --- a/tests/coverage/drop_trait.coverage +++ b/tests/coverage/drop_trait.coverage @@ -13,16 +13,16 @@ LL| | LL| 1|fn main() -> Result<(), u8> { LL| 1| let _firecracker = Firework { strength: 1 }; - LL| 1| + LL| | LL| 1| let _tnt = Firework { strength: 100 }; - LL| 1| + LL| | LL| 1| if true { LL| 1| println!("Exiting with error..."); LL| 1| return Err(1); LL| 0| } - LL| 0| + LL| | LL| 0| let _ = Firework { strength: 1000 }; - LL| 0| + LL| | LL| 0| Ok(()) LL| 1|} LL| | diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map index 465baa7f7f9b..fc57a4892be4 100644 --- a/tests/coverage/fn_sig_into_try.cov-map +++ b/tests/coverage/fn_sig_into_try.cov-map @@ -1,44 +1,52 @@ Function name: fn_sig_into_try::a -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 05, 02] -Number of files: 1 -- file 0 => $DIR/fn_sig_into_try.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2) -Highest counter ID seen: c0 - -Function name: fn_sig_into_try::b -Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0a, 01, 00, 16, 01, 03, 05, 00, 0f, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15) -- Code(Zero) at (prev + 3, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + +Function name: fn_sig_into_try::b +Raw bytes (29): 0x[01, 01, 00, 05, 01, 11, 01, 00, 16, 01, 03, 05, 00, 0f, 00, 00, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/fn_sig_into_try.rs +Number of expressions: 0 +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: fn_sig_into_try::c -Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 18, 01, 00, 16, 01, 03, 0d, 00, 17, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23) -- Code(Zero) at (prev + 3, 23) to (start + 0, 24) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 13) to (start + 0, 23) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: fn_sig_into_try::d -Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 1f, 01, 00, 16, 01, 03, 0c, 00, 0e, 01, 00, 11, 00, 13, 01, 01, 05, 00, 0f, 00, 00, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15) -- Code(Zero) at (prev + 4, 15) to (start + 0, 16) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 12) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/fn_sig_into_try.coverage b/tests/coverage/fn_sig_into_try.coverage index cabe747ce5ac..bc744db4b69c 100644 --- a/tests/coverage/fn_sig_into_try.coverage +++ b/tests/coverage/fn_sig_into_try.coverage @@ -8,31 +8,31 @@ LL| |// signature should be handled in the same way. LL| | LL| 1|fn a() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| Some(7i32); LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn b() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn c() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| let _ = Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn d() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| let _: () = (); LL| 1| Some(7i32)?; ^0 diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map index 119c426965d1..da9e5495a72b 100644 --- a/tests/coverage/generic-unused-impl.cov-map +++ b/tests/coverage/generic-unused-impl.cov-map @@ -1,18 +1,23 @@ Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 0b, 05, 00, 29, 00, 01, 0e, 00, 12, 00, 00, 16, 00, 1a, 00, 01, 09, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 11, 5) to (start + 3, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 11, 5) to (start + 0, 41) +- Code(Zero) at (prev + 1, 14) to (start + 0, 18) +- Code(Zero) at (prev + 0, 22) to (start + 0, 26) +- Code(Zero) at (prev + 1, 9) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: generic_unused_impl::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 - file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map index 92c6ad01e300..7f9b7ee0f471 100644 --- a/tests/coverage/generics.cov-map +++ b/tests/coverage/generics.cov-map @@ -1,48 +1,73 @@ Function name: as core::ops::drop::Drop>::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] -Number of files: 1 -- file 0 => $DIR/generics.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) -Highest counter ID seen: c0 - -Function name: >::set_strength -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] -Number of files: 1 -- file 0 => $DIR/generics.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) -Highest counter ID seen: c0 - -Function name: as core::ops::drop::Drop>::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] -Number of files: 1 -- file 0 => $DIR/generics.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) -Highest counter ID seen: c0 - -Function name: >::set_strength -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] -Number of files: 1 -- file 0 => $DIR/generics.rs -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) -Highest counter ID seen: c0 - -Function name: generics::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 01, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/generics.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12) -- Code(Counter(0)) at (prev + 9, 9) to (start + 1, 22) -- Code(Zero) at (prev + 2, 6) to (start + 4, 11) -- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c0 + +Function name: >::set_strength +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 05, 00, 30, 01, 01, 09, 00, 25, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/generics.rs +Number of expressions: 0 +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 48) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c0 + +Function name: as core::ops::drop::Drop>::drop +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/generics.rs +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c0 + +Function name: >::set_strength +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 05, 00, 30, 01, 01, 09, 00, 25, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/generics.rs +Number of expressions: 0 +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 48) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c0 + +Function name: generics::main +Raw bytes (99): 0x[01, 01, 00, 13, 01, 16, 01, 00, 1c, 01, 01, 09, 00, 18, 01, 00, 1b, 00, 33, 01, 01, 05, 00, 10, 01, 00, 11, 00, 1d, 01, 02, 09, 00, 10, 01, 00, 13, 00, 2f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 15, 01, 01, 05, 00, 08, 01, 00, 09, 00, 15, 01, 02, 08, 00, 0c, 01, 01, 09, 00, 11, 01, 00, 12, 00, 29, 01, 01, 10, 00, 16, 00, 01, 05, 00, 06, 00, 02, 0d, 00, 28, 00, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/generics.rs +Number of expressions: 0 +Number of file 0 mappings: 19 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 22) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +- Code(Zero) at (prev + 2, 13) to (start + 0, 40) +- Code(Zero) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/generics.coverage b/tests/coverage/generics.coverage index a2cd1465d26f..43697cacb9a5 100644 --- a/tests/coverage/generics.coverage +++ b/tests/coverage/generics.coverage @@ -44,18 +44,18 @@ LL| 1|fn main() -> Result<(), u8> { LL| 1| let mut firecracker = Firework { strength: 1 }; LL| 1| firecracker.set_strength(2); - LL| 1| + LL| | LL| 1| let mut tnt = Firework { strength: 100.1 }; LL| 1| tnt.set_strength(200.1); LL| 1| tnt.set_strength(300.3); - LL| 1| + LL| | LL| 1| if true { LL| 1| println!("Exiting with error..."); LL| 1| return Err(1); LL| 0| } - LL| 0| + LL| | LL| 0| let _ = Firework { strength: 1000 }; - LL| 0| + LL| | LL| 0| Ok(()) LL| 1|} LL| | diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 5298c2d92d5d..c2158c441506 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -1,57 +1,81 @@ Function name: ::_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 2b, 09, 00, 1d] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 2b, 09, 00, 1a, 00, 00, 1c, 00, 1d] Number of files: 1 - file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 43, 9) to (start + 0, 29) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 43, 9) to (start + 0, 26) +- Code(Zero) at (prev + 0, 28) to (start + 0, 29) Highest counter ID seen: (none) Function name: holes::main -Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 06, 27, 01, 13, 05, 01, 02] +Raw bytes (154): 0x[01, 01, 00, 1e, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 03, 09, 00, 0f, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 03, 09, 00, 0f, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 09, 00, 27, 01, 0d, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 17) -- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 17) +Number of file 0 mappings: 30 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) - Code(Counter(0)) at (prev + 7, 9) to (start + 0, 17) -- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 6, 39) -- Code(Counter(0)) at (prev + 19, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 9) to (start + 0, 39) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 05, 00, 17] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1f, 05, 00, 14, 00, 00, 16, 00, 17] Number of files: 1 - file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 31, 5) to (start + 0, 23) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 31, 5) to (start + 0, 20) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 09, 02, 0a] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 18, 09, 00, 0a, 00, 01, 0d, 00, 16, 00, 00, 17, 00, 19, 00, 01, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 24, 9) to (start + 2, 10) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 24, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 13) to (start + 0, 22) +- Code(Zero) at (prev + 0, 23) to (start + 0, 25) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 4b, 09, 02, 0a] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 4b, 09, 00, 0a, 00, 01, 0d, 00, 12, 00, 01, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 75, 9) to (start + 2, 10) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 75, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 13) to (start + 0, 18) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: (none) diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage index a6a02f1b9d08..1ea60491800d 100644 --- a/tests/coverage/holes.coverage +++ b/tests/coverage/holes.coverage @@ -58,8 +58,8 @@ LL| | } LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| #[rustfmt::skip] + LL| | + LL| | #[rustfmt::skip] LL| 1| let _const = LL| | const LL| | { @@ -68,8 +68,8 @@ LL| | ; LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| #[rustfmt::skip] + LL| | + LL| | #[rustfmt::skip] LL| 1| let _async = LL| | async LL| 0| { @@ -78,11 +78,11 @@ LL| | ; LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| // This tests the edge case of a const block nested inside an "anon const", - LL| 1| // such as the length of an array literal. Handling this case requires - LL| 1| // `nested_filter::OnlyBodies` or equivalent. - LL| 1| #[rustfmt::skip] + LL| | + LL| | // This tests the edge case of a const block nested inside an "anon const", + LL| | // such as the length of an array literal. Handling this case requires + LL| | // `nested_filter::OnlyBodies` or equivalent. + LL| | #[rustfmt::skip] LL| 1| let _const_block_inside_anon_const = LL| | [ LL| | 0 diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index 611dd2ef08d5..044c0f2ba089 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,12 +1,17 @@ Function name: if::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 04, 01, 00, 0a, 01, 05, 05, 00, 0c, 01, 02, 09, 02, 0a, 01, 05, 09, 01, 0e, 01, 03, 09, 00, 0a, 01, 03, 09, 00, 10, 05, 01, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16) -- Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 2, 9) to (start + 2, 10) +- Code(Counter(0)) at (prev + 5, 9) to (start + 1, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage index 0762418347c2..c3c8a1bf38a4 100644 --- a/tests/coverage/if.coverage +++ b/tests/coverage/if.coverage @@ -2,23 +2,23 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. - LL| 1| let + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. + LL| | let LL| 1| is_true - LL| 1| = + LL| | = LL| 1| std::env::args().len() LL| 1| == LL| 1| 1 - LL| 1| ; - LL| 1| let + LL| | ; + LL| | let LL| 1| mut LL| 1| countdown - LL| 1| = + LL| | = LL| 1| 0 - LL| 1| ; - LL| 1| if + LL| | ; + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map index 35096d859502..1d8ca1809532 100644 --- a/tests/coverage/if_else.cov-map +++ b/tests/coverage/if_else.cov-map @@ -1,13 +1,18 @@ Function name: if_else::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02] +Raw bytes (68): 0x[01, 01, 02, 01, 05, 01, 09, 0c, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 02, 09, 00, 10, 05, 01, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if_else.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 4, 1) to (start + 8, 16) -- Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16) = (c0 - c1) - Code(Counter(0)) at (prev + 6, 9) to (start + 0, 16) diff --git a/tests/coverage/if_else.coverage b/tests/coverage/if_else.coverage index 2bf93487cec2..148e2b195173 100644 --- a/tests/coverage/if_else.coverage +++ b/tests/coverage/if_else.coverage @@ -2,13 +2,13 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; - LL| 1| if + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index 0fd35c55e3e5..1b1a1b30e934 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,14 +1,15 @@ Function name: if_not::if_not -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0b, 01, 05, 01, 00, 16, 01, 02, 09, 01, 0d, 02, 02, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if_not.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 2, 9) to (start + 1, 13) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) diff --git a/tests/coverage/if_not.coverage b/tests/coverage/if_not.coverage index 678ccf9f2f85..8478e861a3aa 100644 --- a/tests/coverage/if_not.coverage +++ b/tests/coverage/if_not.coverage @@ -3,7 +3,7 @@ LL| | LL| |#[rustfmt::skip] LL| 12|fn if_not(cond: bool) { - LL| 12| if + LL| | if LL| 12| ! LL| 12| cond LL| 4| { diff --git a/tests/coverage/ignore_run.cov-map b/tests/coverage/ignore_run.cov-map index a93fff71530b..0d8245c54dc4 100644 --- a/tests/coverage/ignore_run.cov-map +++ b/tests/coverage/ignore_run.cov-map @@ -1,9 +1,10 @@ Function name: ignore_run::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 03, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 - file 0 => $DIR/ignore_run.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 450fb75b7c8e..95a5f6bf68b7 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -1,44 +1,53 @@ Function name: inline_dead::dead (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 17, 01, 00, 11, 00, 01, 05, 00, 07, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 23, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 23, 1) to (start + 0, 17) +- Code(Zero) at (prev + 1, 5) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: inline_dead::live:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 01, 01, 09, 05, 02, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0e, 01, 00, 20, 01, 01, 08, 00, 09, 05, 01, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline-dead.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 13) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 13) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: inline_dead::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 04, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 12, 01, 00, 14, 00, 21, 01, 02, 09, 00, 0a, 01, 03, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 33) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline_dead::main::{closure#0} -Raw bytes (19): 0x[01, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 01, 01, 05, 00, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 17, 00, 18, 01, 01, 09, 00, 16, 00, 00, 17, 00, 18, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 7, 23) to (start + 1, 22) -- Code(Zero) at (prev + 1, 23) to (start + 0, 24) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index c12668ce89a2..d75aaf300623 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -3,7 +3,7 @@ LL| | LL| 1|fn main() { LL| 1| println!("{}", live::()); - LL| 1| + LL| | LL| 1| let f = |x: bool| { LL| 1| debug_assert!(x); ^0 diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index 5aa57e15bd5c..4c67dd96ac2f 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -1,86 +1,137 @@ Function name: inline::display:: -Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 29, 01, 00, 22, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 10, 02, 00, 11, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 29, 01, 00, 21, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 10, 02, 00, 11, 02, 06, 01, 03, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 2, 6) = (c1 - c0) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: inline::error -Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 0b] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 31, 01, 00, 0b, 01, 01, 05, 00, 0b] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 11) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) Highest counter ID seen: c0 Function name: inline::length:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1e, 01, 00, 20, 01, 01, 05, 00, 07, 01, 00, 08, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 7) +- Code(Counter(0)) at (prev + 0, 8) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 05, 01, 00, 0a, 01, 01, 05, 00, 11, 01, 00, 12, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::permutate:: -Raw bytes (54): 0x[01, 01, 05, 01, 05, 0d, 09, 0d, 09, 01, 13, 05, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 0a, 01, 0d, 00, 0e, 09, 00, 12, 00, 16, 0a, 00, 17, 04, 0a, 0e, 05, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (142): 0x[01, 01, 0e, 01, 05, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 01, 37, 05, 09, 16, 01, 0f, 01, 00, 38, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 13, 01, 00, 14, 00, 16, 01, 01, 08, 00, 0e, 05, 00, 0f, 02, 06, 02, 02, 0f, 00, 14, 2e, 01, 0d, 00, 0e, 09, 00, 12, 00, 13, 09, 00, 15, 00, 16, 2e, 00, 17, 04, 0a, 2e, 01, 0d, 00, 11, 2e, 00, 12, 00, 14, 2e, 00, 16, 00, 17, 2e, 00, 19, 00, 1a, 2e, 01, 0d, 00, 16, 2e, 00, 17, 00, 19, 2e, 00, 1b, 00, 20, 2e, 01, 0d, 00, 11, 2e, 00, 12, 00, 14, 32, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs -Number of expressions: 5 +Number of expressions: 14 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(3), rhs = Counter(2) - expression 2 operands: lhs = Counter(3), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) -- expression 4 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14) -- Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6) +- expression 3 operands: lhs = Counter(3), rhs = Counter(2) +- expression 4 operands: lhs = Counter(3), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(2) +- expression 6 operands: lhs = Counter(3), rhs = Counter(2) +- expression 7 operands: lhs = Counter(3), rhs = Counter(2) +- expression 8 operands: lhs = Counter(3), rhs = Counter(2) +- expression 9 operands: lhs = Counter(3), rhs = Counter(2) +- expression 10 operands: lhs = Counter(3), rhs = Counter(2) +- expression 11 operands: lhs = Counter(3), rhs = Counter(2) +- expression 12 operands: lhs = Counter(0), rhs = Expression(13, Add) +- expression 13 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 22 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 0, 15) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20) = (c0 - c1) -- Code(Expression(2, Sub)) at (prev + 1, 13) to (start + 0, 14) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 14) = (c3 - c2) -- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 22) -- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 4, 10) +- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 22) +- Code(Expression(11, Sub)) at (prev + 0, 23) to (start + 4, 10) = (c3 - c2) -- Code(Expression(3, Sub)) at (prev + 5, 12) to (start + 2, 6) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 17) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 18) to (start + 0, 20) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 22) to (start + 0, 23) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 25) to (start + 0, 26) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 22) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 23) to (start + 0, 25) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 27) to (start + 0, 32) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 17) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 18) to (start + 0, 20) + = (c3 - c2) +- Code(Expression(12, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: inline::permutations:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 0a, 01, 00, 2d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 14, 01, 00, 15, 00, 1d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::swap:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 23, 01, 00, 33, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 12, 01, 01, 05, 00, 12, 01, 01, 05, 00, 0e, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/inline.coverage b/tests/coverage/inline.coverage index 3d322126a38b..5fe069d5389d 100644 --- a/tests/coverage/inline.coverage +++ b/tests/coverage/inline.coverage @@ -18,7 +18,7 @@ LL| 6| display(xs); LL| 10| } else if k < n { LL| 15| for i in k..n { - ^10 + ^10^10 LL| 15| swap(xs, i, k); LL| 15| permutate(xs, k + 1); LL| 15| swap(xs, i, k); diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index a9e19fe53a53..ca6ddfda2ddf 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -1,46 +1,70 @@ Function name: ::default_trait_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 09, 03, 0a] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 21, 09, 00, 29, 01, 01, 0d, 00, 14, 01, 01, 0d, 00, 11, 01, 00, 12, 00, 1c, 01, 01, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 33, 9) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: ::trait_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 28, 09, 00, 2c, 01, 01, 0d, 00, 29, 01, 01, 0d, 00, 14, 01, 00, 15, 00, 29, 01, 01, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 40, 9) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: inner_items::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 05, 02] +Raw bytes (88): 0x[01, 01, 02, 01, 05, 01, 09, 10, 01, 03, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 00, 10, 01, 00, 13, 02, 06, 01, 04, 05, 00, 08, 01, 00, 09, 00, 1b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inner_items.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15) - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c2) -- Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 2, 6) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: inner_items::main::in_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06] +Raw bytes (44): 0x[01, 01, 00, 08, 01, 12, 05, 00, 17, 01, 01, 0d, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 0d, 00, 0e, 01, 00, 11, 00, 16, 01, 01, 09, 00, 11, 01, 00, 12, 00, 1a, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 8244d347b59c..8503cc12f233 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -1,11 +1,11 @@ LL| |#![allow(unused_assignments, unused_variables, dead_code)] LL| | LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; LL| 1| if is_true { LL| 1| countdown = 10; @@ -54,7 +54,7 @@ LL| 1| let mut val = InStruct { LL| 1| in_struct_field: 101, // LL| 1| }; - LL| 1| + LL| | LL| 1| val.default_trait_func(); LL| 1|} diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index 4e45db836d67..d1d751ff24b8 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,13 +1,30 @@ Function name: issue_83601::main -Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 0f, 05, 03, 09, 01, 0f, 02, 02, 05, 03, 02] +Raw bytes (76): 0x[01, 01, 01, 05, 09, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-83601.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 15) -- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c1 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 1ed5edbb8191..2b643ea599ed 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -1,65 +1,79 @@ Function name: ::fmt -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 24, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, 8a, 01, 05, 00, 43, 01, 01, 09, 00, 0f, 01, 00, 10, 00, 11, 01, 00, 13, 00, 24, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 138, 5) to (start + 1, 36) -- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 138, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 36) +- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: issue_84561::main -Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02] +Raw bytes (30): 0x[01, 01, 00, 05, 01, b4, 01, 01, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 180, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: issue_84561::test1 -Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 00, 0c, 01, 9a, 01, 01, 00, 0b, 01, 01, 05, 00, 0b, 05, 00, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 05, 00, 0b, 0d, 00, 0c, 00, 1e, 01, 01, 05, 02, 06, 01, 03, 05, 00, 0b, 11, 00, 0c, 00, 1e, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 154, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(1)) at (prev + 0, 12) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) - Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 11) -- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11) -- Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(3)) at (prev + 0, 12) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 6) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 11) +- Code(Counter(4)) at (prev + 0, 12) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: issue_84561::test2 -Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02] +Raw bytes (25): 0x[01, 01, 00, 04, 01, b0, 01, 01, 00, 0b, 01, 01, 05, 00, 10, 05, 00, 11, 00, 23, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 176, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(1)) at (prev + 0, 17) to (start + 0, 35) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: issue_84561::test2::call_print -Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] +Raw bytes (25): 0x[01, 01, 00, 04, 01, a7, 01, 09, 00, 1f, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 18, 01, 01, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 167, 9) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 02, 13, 21, 03, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (409): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 02, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 00, 0c, 09, 00, 0f, 00, 15, 09, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 00, 10, 0d, 00, 13, 00, 2e, 0d, 02, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 00, 0c, 0d, 00, 0f, 00, 15, 0d, 01, 05, 00, 0f, 0d, 04, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 00, 0f, 1d, 02, 0c, 00, 13, 21, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 10 @@ -73,29 +87,54 @@ Number of expressions: 10 - expression 7 operands: lhs = Counter(9), rhs = Counter(10) - expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12) - expression 9 operands: lhs = Counter(10), rhs = Counter(11) -Number of file 0 mappings: 51 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15) -- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15) -- Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15) -- Code(Counter(2)) at (prev + 5, 5) to (start + 0, 15) +Number of file 0 mappings: 77 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 15) - Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) - Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 48) -- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 15) -- Code(Zero) at (prev + 3, 32) to (start + 0, 48) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 36) +- Code(Zero) at (prev + 0, 41) to (start + 0, 48) - Code(Zero) at (prev + 0, 51) to (start + 0, 65) - Code(Zero) at (prev + 0, 75) to (start + 0, 90) - Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Zero) at (prev + 5, 9) to (start + 3, 16) -- Code(Zero) at (prev + 5, 13) to (start + 0, 27) +- Code(Zero) at (prev + 5, 9) to (start + 0, 13) +- Code(Zero) at (prev + 3, 9) to (start + 0, 16) +- Code(Zero) at (prev + 2, 13) to (start + 0, 27) - Code(Zero) at (prev + 2, 13) to (start + 0, 28) -- Code(Counter(3)) at (prev + 4, 9) to (start + 2, 15) -- Code(Counter(3)) at (prev + 6, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(3)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) - Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 9) to (start + 1, 15) -- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 12) +- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 8) to (start + 0, 15) - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19) = (c3 - c4) @@ -110,8 +149,9 @@ Number of file 0 mappings: 51 - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c3 - c6) -- Code(Counter(7)) at (prev + 4, 5) to (start + 2, 19) -- Code(Counter(8)) at (prev + 3, 13) to (start + 0, 19) +- Code(Counter(7)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 19) +- Code(Counter(8)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c7 - c8) - Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15) diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/issue-84561.coverage index a55f42a696e6..781f1e97f5ab 100644 --- a/tests/coverage/issue-84561.coverage +++ b/tests/coverage/issue-84561.coverage @@ -14,7 +14,7 @@ LL| 1| println!("{:?}", Foo(1)); LL| 1| println!("{:?}", bar); LL| 1| println!("{:?}", baz); - LL| 1| + LL| | LL| 1| assert_eq!(Foo(1), Foo(1)); LL| 1| assert_ne!(Foo(0), Foo(1)); LL| 1| assert_eq!(Foo(2), Foo(2)); @@ -25,17 +25,17 @@ ^0 LL| 1| println!("{:?}", bar); LL| 1| println!("{:?}", Foo(1)); - LL| 1| + LL| | LL| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); - ^0 ^0 ^0 + ^0 ^0 ^0 ^0 LL| 1| assert_ne!( LL| | Foo(0) LL| | , LL| | Foo(5) LL| | , LL| 0| "{}" - LL| 0| , - LL| 0| if + LL| | , + LL| | if LL| 0| is_true LL| | { LL| 0| "true message" @@ -45,7 +45,7 @@ LL| | ); LL| | LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| assert_eq!( LL| | Foo(1), LL| | Foo(1) @@ -96,7 +96,7 @@ LL| | Foo(5) LL| | ); LL| 1| assert_ne!( - LL| 1| Foo(5), + LL| | Foo(5), LL| 1| if is_true { LL| 1| Foo(0) LL| | } else { diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/issue-85461.cov-map index 566206a7539d..b08d70336930 100644 --- a/tests/coverage/issue-85461.cov-map +++ b/tests/coverage/issue-85461.cov-map @@ -1,9 +1,12 @@ Function name: issue_85461::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 11, 01, 01, 05, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-85461.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index 3cb54d80e7f0..17f3dafce1d7 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -1,27 +1,30 @@ Function name: issue_93054::foo2 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1c] Number of files: 1 - file 0 => $DIR/issue-93054.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 0, 29) +- Code(Zero) at (prev + 21, 1) to (start + 0, 28) Highest counter ID seen: (none) Function name: issue_93054::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 1d, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 - file 0 => $DIR/issue-93054.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 Function name: issue_93054::make (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 19, 01, 00, 1b, 00, 01, 05, 00, 09, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-93054.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 25, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 9) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index 9722b4c2a325..cbbe6a89fb0f 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,5 +1,5 @@ Function name: lazy_boolean::main -Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 25, 01, 21, 01, 11, 01, 15, 01, 19, 01, 1d, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 09, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 0d, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 11, 03, 05, 00, 06, 01, 03, 09, 00, 10, 15, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 19, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 1d, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (198): 0x[01, 01, 07, 01, 05, 01, 25, 01, 21, 01, 11, 01, 15, 01, 19, 01, 1d, 24, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 0a, 00, 0f, 01, 00, 11, 00, 16, 01, 00, 18, 00, 1d, 01, 00, 21, 00, 2a, 01, 01, 08, 00, 0f, 05, 00, 10, 04, 06, 05, 01, 09, 00, 0e, 02, 03, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 09, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 0d, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 11, 03, 05, 00, 06, 01, 03, 09, 00, 10, 15, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 19, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 1d, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/lazy_boolean.rs Number of expressions: 7 @@ -10,10 +10,18 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(5) - expression 5 operands: lhs = Counter(0), rhs = Counter(6) - expression 6 operands: lhs = Counter(0), rhs = Counter(7) -Number of file 0 mappings: 28 -- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) +Number of file 0 mappings: 36 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 10) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 29) +- Code(Counter(0)) at (prev + 0, 33) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 4, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17) - Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage index 828ba2a58116..0a30038e02fa 100644 --- a/tests/coverage/lazy_boolean.coverage +++ b/tests/coverage/lazy_boolean.coverage @@ -2,11 +2,11 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let (mut a, mut b, mut c) = (0, 0, 0); LL| 1| if is_true { LL| 1| a = 1; diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index f55e5a930b47..169d4a5c0961 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -1,33 +1,36 @@ Function name: let_else_loop::_if (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 16, 01, 00, 13, 00, 01, 08, 00, 0c, 00, 00, 0f, 00, 16, 00, 00, 20, 00, 27] Number of files: 1 - file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Zero) at (prev + 22, 1) to (start + 1, 12) -- Code(Zero) at (prev + 1, 15) to (start + 0, 22) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 22, 1) to (start + 0, 19) +- Code(Zero) at (prev + 1, 8) to (start + 0, 12) +- Code(Zero) at (prev + 0, 15) to (start + 0, 22) - Code(Zero) at (prev + 0, 32) to (start + 0, 39) Highest counter ID seen: (none) Function name: let_else_loop::_loop_either_way (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 00, 20, 00, 01, 10, 00, 14, 00, 00, 1c, 00, 23, 00, 01, 05, 00, 0c] Number of files: 1 - file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Zero) at (prev + 15, 1) to (start + 1, 20) -- Code(Zero) at (prev + 1, 28) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 15, 1) to (start + 0, 32) +- Code(Zero) at (prev + 1, 16) to (start + 0, 20) +- Code(Zero) at (prev + 0, 28) to (start + 0, 35) - Code(Zero) at (prev + 1, 5) to (start + 0, 12) Highest counter ID seen: (none) Function name: let_else_loop::loopy -Raw bytes (19): 0x[01, 01, 00, 03, 01, 09, 01, 01, 14, 09, 01, 1c, 00, 23, 05, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 01, 00, 15, 01, 01, 10, 00, 14, 09, 00, 1c, 00, 23, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 20) -- Code(Counter(2)) at (prev + 1, 28) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 20) +- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 35) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/long_and_wide.cov-map b/tests/coverage/long_and_wide.cov-map index c8194ccc79b3..93466a98eaf3 100644 --- a/tests/coverage/long_and_wide.cov-map +++ b/tests/coverage/long_and_wide.cov-map @@ -1,36 +1,44 @@ Function name: long_and_wide::far_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 96, 01, 01, 00, 15] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 96, 01, 01, 00, 12, 01, 00, 14, 00, 15] Number of files: 1 - file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) Highest counter ID seen: c0 Function name: long_and_wide::long_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 10, 01, 00, 13, 01, 84, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 132, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: long_and_wide::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 07, 01, 00, 0a, 01, 01, 05, 00, 12, 01, 01, 05, 00, 12, 01, 01, 05, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: long_and_wide::wide_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01] +Raw bytes (23): 0x[01, 01, 00, 03, 01, 0e, 01, 00, 13, 01, 00, 86, 01, 00, 88, 01, 01, 00, 8a, 01, 00, 8b, 01] Number of files: 1 - file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 134) to (start + 0, 136) +- Code(Counter(0)) at (prev + 0, 138) to (start + 0, 139) Highest counter ID seen: c0 diff --git a/tests/coverage/long_and_wide.coverage b/tests/coverage/long_and_wide.coverage index f0898d9f4662..d9bacdf9eed3 100644 --- a/tests/coverage/long_and_wide.coverage +++ b/tests/coverage/long_and_wide.coverage @@ -14,137 +14,137 @@ LL| 1|fn wide_function() { /* */ (); } LL| | LL| 1|fn long_function() { - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // LL| 1|} LL| | LL| 1|fn far_function() {} diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index 8edb6d06dd6d..3981623550dd 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,11 +1,11 @@ Function name: loop_break::main -Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0b, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0a, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/loop-break.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) - Code(Counter(1)) at (prev + 2, 12) to (start + 0, 33) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map index d16335a0a291..cf355eceb2c1 100644 --- a/tests/coverage/loop_break_value.cov-map +++ b/tests/coverage/loop_break_value.cov-map @@ -1,9 +1,12 @@ Function name: loop_break_value::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 0a, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 04, 01, 00, 0a, 01, 01, 09, 00, 0f, 01, 02, 0d, 05, 0a, 01, 07, 01, 00, 02] Number of files: 1 - file 0 => $DIR/loop_break_value.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 1) to (start + 10, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 2, 13) to (start + 5, 10) +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/loop_break_value.coverage b/tests/coverage/loop_break_value.coverage index 7d4533987594..5e80168b958b 100644 --- a/tests/coverage/loop_break_value.coverage +++ b/tests/coverage/loop_break_value.coverage @@ -3,13 +3,13 @@ LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let result - LL| 1| = + LL| | = LL| 1| loop LL| 1| { LL| 1| break LL| 1| 10 LL| 1| ; LL| 1| } - LL| 1| ; + LL| | ; LL| 1|} diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index d414710ee9d6..78fdaa53f46f 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,5 +1,5 @@ Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 14, 01, 09, 05, 01, 10, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (137): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 19, 01, 09, 05, 00, 43, 01, 01, 0c, 00, 10, 01, 01, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 15, 01, 00, 17, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 17, 0d, 00, 18, 00, 19, 0d, 00, 1b, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/loops_branches.rs Number of expressions: 4 @@ -7,13 +7,16 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) -- Code(Counter(0)) at (prev + 2, 16) to (start + 0, 21) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 29) - Code(Counter(1)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) - Code(Counter(3)) at (prev + 3, 13) to (start + 0, 14) @@ -23,7 +26,9 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(3)) at (prev + 0, 24) to (start + 0, 25) +- Code(Counter(3)) at (prev + 0, 27) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c3) - (c1 + c2)) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) @@ -33,7 +38,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c3 Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (137): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 19, 01, 22, 05, 00, 43, 01, 01, 0c, 00, 11, 00, 00, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 15, 01, 00, 17, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 17, 09, 00, 18, 00, 19, 09, 00, 1b, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/loops_branches.rs Number of expressions: 4 @@ -41,14 +46,17 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(3) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) -- Code(Zero) at (prev + 1, 18) to (start + 1, 10) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 34, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 1, 10) - Code(Counter(0)) at (prev + 2, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 29) - Code(Counter(3)) at (prev + 0, 30) to (start + 0, 31) - Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 23) @@ -58,7 +66,9 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(2)) at (prev + 0, 24) to (start + 0, 25) +- Code(Counter(2)) at (prev + 0, 27) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c2) - (c1 + c3)) - Code(Expression(3, Sub)) at (prev + 3, 9) to (start + 0, 15) @@ -67,11 +77,20 @@ Number of file 0 mappings: 20 Highest counter ID seen: c3 Function name: loops_branches::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 37, 01, 00, 0a, 01, 01, 09, 00, 13, 01, 00, 16, 00, 1f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 09, 00, 15, 01, 00, 18, 00, 23, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 12, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/loops_branches.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 3e71ed877bf9..4544aa50143e 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -1,18 +1,21 @@ Function name: macro_in_closure::NO_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 1c, 00, 2d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 25, 00, 2c] Number of files: 1 - file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 28) to (start + 0, 45) +- Code(Counter(0)) at (prev + 7, 37) to (start + 0, 44) Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 1e, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 1e, 00, 1f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 9, 30) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 30) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index 18b4e28b7b43..c96cb75846b2 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -1,18 +1,21 @@ Function name: macro_name_span::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 3e] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 1c, 00, 1d, 01, 01, 09, 00, 3e] Number of files: 1 - file 0 => $DIR/macro_name_span.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 62) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 22, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 62) Highest counter ID seen: c0 Function name: macro_name_span::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0b, 01, 00, 0a, 01, 01, 05, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/macro_name_span.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index a29c712998f7..0bb126bc09b1 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,5 +1,5 @@ Function name: match_or_pattern::main -Raw bytes (145): 0x[01, 01, 08, 01, 05, 01, 09, 01, 0d, 01, 11, 01, 15, 01, 19, 01, 1d, 01, 21, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 06, 03, 1b, 00, 1d, 09, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 0d, 00, 10, 03, 06, 0a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 0e, 01, 1b, 00, 1d, 11, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 16, 01, 1b, 00, 1d, 19, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 1d, 00, 10, 03, 06, 1a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 1e, 01, 1b, 00, 1d, 21, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (190): 0x[01, 01, 08, 01, 05, 01, 09, 01, 0d, 01, 11, 01, 15, 01, 19, 01, 1d, 01, 21, 22, 01, 01, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 0e, 01, 00, 10, 00, 12, 01, 00, 15, 00, 16, 01, 01, 09, 00, 0e, 01, 00, 10, 00, 12, 01, 00, 15, 00, 16, 01, 01, 08, 00, 0f, 05, 00, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 06, 03, 1b, 00, 1d, 09, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 0d, 00, 10, 03, 06, 0a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 0e, 01, 1b, 00, 1d, 11, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 16, 01, 1b, 00, 1d, 19, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 1d, 00, 10, 03, 06, 1a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 1e, 01, 1b, 00, 1d, 21, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/match_or_pattern.rs Number of expressions: 8 @@ -11,9 +11,18 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(0), rhs = Counter(6) - expression 6 operands: lhs = Counter(0), rhs = Counter(7) - expression 7 operands: lhs = Counter(0), rhs = Counter(8) -Number of file 0 mappings: 25 -- Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15) -- Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6) +Number of file 0 mappings: 34 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 3, 6) - Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17) diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/match_or_pattern.coverage index a65c226e5672..50540bc5614a 100644 --- a/tests/coverage/match_or_pattern.coverage +++ b/tests/coverage/match_or_pattern.coverage @@ -1,9 +1,9 @@ LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut a: u8 = 0; LL| 1| let mut b: u8 = 0; LL| 1| if is_true { diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index f966d754f540..ffee97cfbc50 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,5 +1,5 @@ Function name: condition_limit::accept_7_conditions -Raw bytes (147): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 12, 01, 06, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (192): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 1b, 01, 06, 01, 00, 2c, 01, 01, 0a, 00, 0b, 01, 00, 0d, 00, 0e, 01, 00, 10, 00, 11, 01, 00, 13, 00, 14, 01, 00, 16, 00, 17, 01, 00, 19, 00, 1a, 01, 00, 1c, 00, 1d, 01, 00, 21, 00, 29, 01, 01, 08, 00, 09, 28, 08, 07, 00, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/condition-limit.rs Number of expressions: 8 @@ -11,9 +11,18 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(5), rhs = Counter(6) - expression 6 operands: lhs = Counter(6), rhs = Counter(7) - expression 7 operands: lhs = Counter(0), rhs = Counter(7) -Number of file 0 mappings: 18 -- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 9) -- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39) +Number of file 0 mappings: 27 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 10) to (start + 0, 11) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 0, 33) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 0, 8) to (start + 0, 39) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 7, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index de4ea7790f75..dac1eb4c94bd 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,14 +1,15 @@ Function name: if::mcdc_check_a -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 0e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 0e, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -23,16 +24,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_b -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 16, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 16, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 22, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -47,16 +49,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_both -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 1e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 1e, 01, 00, 25, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -71,16 +74,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_neither -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 06, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 06, 01, 00, 28, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -95,7 +99,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_not_tree_decision -Raw bytes (85): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0a, 01, 30, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (90): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0b, 01, 30, 01, 00, 3b, 28, 05, 03, 03, 08, 00, 15, 01, 00, 09, 00, 0a, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 7 @@ -106,9 +110,10 @@ Number of expressions: 7 - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) - expression 6 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 48, 1) to (start + 3, 10) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 48, 1) to (start + 0, 59) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 3 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -129,7 +134,7 @@ Number of file 0 mappings: 10 Highest counter ID seen: c3 Function name: if::mcdc_check_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0a, 01, 26, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (92): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0b, 01, 26, 01, 00, 37, 01, 03, 08, 00, 09, 28, 04, 03, 00, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs Number of expressions: 8 @@ -141,9 +146,10 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(2), rhs = Counter(3) - expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 38, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 38, 1) to (start + 0, 55) +- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -164,46 +170,53 @@ Number of file 0 mappings: 10 Highest counter ID seen: c3 Function name: if::mcdc_nested_if -Raw bytes (120): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 2b, 0d, 05, 09, 0d, 11, 2b, 11, 05, 09, 01, 2b, 05, 09, 0e, 01, 3a, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 2b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 0d, 12, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 1a, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 1e, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (139): 0x[01, 01, 0d, 01, 05, 01, 33, 05, 09, 05, 09, 05, 09, 05, 09, 33, 0d, 05, 09, 0d, 11, 33, 11, 05, 09, 01, 33, 05, 09, 11, 01, 3a, 01, 00, 2d, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 2e, 02, 00, 00, 00, 0d, 00, 0e, 33, 01, 09, 00, 0c, 33, 00, 0d, 00, 15, 33, 01, 0c, 00, 0d, 28, 06, 02, 00, 0c, 00, 12, 30, 0d, 1a, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 22, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 26, 02, 09, 00, 0a, 2e, 01, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/if.rs -Number of expressions: 11 +Number of expressions: 13 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(12, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Expression(10, Add), rhs = Counter(3) +- expression 4 operands: lhs = Counter(1), rhs = Counter(2) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) -- expression 6 operands: lhs = Counter(3), rhs = Counter(4) -- expression 7 operands: lhs = Expression(10, Add), rhs = Counter(4) -- expression 8 operands: lhs = Counter(1), rhs = Counter(2) -- expression 9 operands: lhs = Counter(0), rhs = Expression(10, Add) +- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +- expression 8 operands: lhs = Counter(3), rhs = Counter(4) +- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(4) - expression 10 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 58, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add) +- expression 12 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 58, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) - Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14) = (c0 - c1) -- MCDCBranch { true: Counter(2), false: Expression(9, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(11, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 false = (c0 - (c1 + c2)) -- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 13) +- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 0, 12) = (c1 + c2) -- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) -- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) +- Code(Expression(12, Add)) at (prev + 0, 13) to (start + 0, 21) + = (c1 + c2) +- Code(Expression(12, Add)) at (prev + 1, 12) to (start + 0, 13) + = (c1 + c2) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 12) to (start + 0, 18) +- MCDCBranch { true: Counter(3), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) true = c3 false = ((c1 + c2) - c3) - Code(Counter(3)) at (prev + 0, 17) to (start + 0, 18) -- MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) +- MCDCBranch { true: Counter(4), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) true = c4 false = (c3 - c4) - Code(Counter(4)) at (prev + 0, 19) to (start + 2, 10) -- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(9, Sub)) at (prev + 2, 9) to (start + 0, 10) = ((c1 + c2) - c4) -- Code(Expression(9, Sub)) at (prev + 1, 12) to (start + 2, 6) +- Code(Expression(11, Sub)) at (prev + 1, 12) to (start + 2, 6) = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/mcdc/if.coverage b/tests/coverage/mcdc/if.coverage index 51917d060454..fda5525c472c 100644 --- a/tests/coverage/mcdc/if.coverage +++ b/tests/coverage/mcdc/if.coverage @@ -123,8 +123,8 @@ LL| 3|} LL| | LL| 4|fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) { - LL| 4| // This expression is intentionally written in a way - LL| 4| // where 100% branch coverage indicates 100% mcdc coverage. + LL| | // This expression is intentionally written in a way + LL| | // where 100% branch coverage indicates 100% mcdc coverage. LL| 4| if a && (b || c) { ^3 ^2 ------------------ @@ -160,8 +160,8 @@ LL| 4|} LL| | LL| 4|fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { - LL| 4| // Contradict to `mcdc_check_tree_decision`, - LL| 4| // 100% branch coverage of this expression does not indicate 100% mcdc coverage. + LL| | // Contradict to `mcdc_check_tree_decision`, + LL| | // 100% branch coverage of this expression does not indicate 100% mcdc coverage. LL| 4| if (a || b) && c { ^1 ------------------ diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 714d168cf498..d05ef368ba4a 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,13 +1,14 @@ Function name: inlined_expressions::inlined_instance -Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 07, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (55): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 07, 01, 00, 2e, 01, 01, 05, 00, 06, 28, 03, 02, 00, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/inlined_expressions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 6) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 5) to (start + 0, 11) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index 7232e4f89cdd..853cdf2c5760 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,5 +1,5 @@ Function name: nested_if::doubly_nested_if_in_condition -Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 14, 01, 0e, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 15, 01, 0e, 01, 00, 45, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested_if.rs Number of expressions: 15 @@ -18,9 +18,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add) - expression 13 operands: lhs = Counter(2), rhs = Counter(3) - expression 14 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) +Number of file 0 mappings: 21 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 69) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 78) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -59,7 +60,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c6 Function name: nested_if::nested_if_in_condition -Raw bytes (118): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0e, 01, 06, 01, 01, 09, 28, 06, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (123): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0f, 01, 06, 01, 00, 35, 01, 01, 08, 00, 09, 28, 06, 02, 00, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested_if.rs Number of expressions: 10 @@ -73,9 +74,10 @@ Number of expressions: 10 - expression 7 operands: lhs = Counter(1), rhs = Expression(8, Add) - expression 8 operands: lhs = Counter(2), rhs = Counter(3) - expression 9 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) +Number of file 0 mappings: 15 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 53) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 46) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -103,7 +105,7 @@ Number of file 0 mappings: 14 Highest counter ID seen: c4 Function name: nested_if::nested_in_then_block_in_condition -Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 14, 01, 21, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 15, 01, 21, 01, 00, 52, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested_if.rs Number of expressions: 15 @@ -122,9 +124,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add) - expression 13 operands: lhs = Counter(2), rhs = Counter(3) - expression 14 operands: lhs = Counter(0), rhs = Counter(6) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) +Number of file 0 mappings: 21 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 82) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 75) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -163,7 +166,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c6 Function name: nested_if::nested_single_condition_decision -Raw bytes (83): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0b, 01, 16, 01, 04, 09, 28, 03, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (88): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0c, 01, 16, 01, 00, 36, 01, 04, 08, 00, 09, 28, 03, 02, 00, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested_if.rs Number of expressions: 5 @@ -172,9 +175,10 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 22, 1) to (start + 4, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 54) +- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 41) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage index c3ac30d22bf8..8b5179b34fee 100644 --- a/tests/coverage/mcdc/nested_if.coverage +++ b/tests/coverage/mcdc/nested_if.coverage @@ -122,9 +122,9 @@ LL| 4|} LL| | LL| 3|fn nested_single_condition_decision(a: bool, b: bool) { - LL| 3| // Decision with only 1 decision should not be instrumented by MCDC because - LL| 3| // branch-coverage is equivalent to MCDC coverage in this case, and we don't - LL| 3| // want to waste bitmap space for this. + LL| | // Decision with only 1 decision should not be instrumented by MCDC because + LL| | // branch-coverage is equivalent to MCDC coverage in this case, and we don't + LL| | // want to waste bitmap space for this. LL| 3| if a && if b { false } else { true } { ^2 ^1 ^1 ------------------ diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index 02251e691522..f06bc2ed8168 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,5 +1,5 @@ Function name: non_control_flow::assign_3 -Raw bytes (79): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0a, 01, 15, 01, 00, 28, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0c, 01, 15, 01, 00, 27, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 4 @@ -7,8 +7,8 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 40) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 39) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) @@ -24,11 +24,13 @@ Number of file 0 mappings: 10 - MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c2 - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: non_control_flow::assign_3_bis -Raw bytes (81): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0a, 01, 1a, 01, 00, 2c, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (91): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0c, 01, 1a, 01, 00, 2b, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 5 @@ -37,8 +39,8 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 44) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) @@ -54,18 +56,20 @@ Number of file 0 mappings: 10 - MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c0 - (c2 + c3)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: non_control_flow::assign_and -Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 0b, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (70): 0x[01, 01, 02, 01, 05, 05, 09, 0a, 01, 0b, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 33) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 32) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) @@ -76,19 +80,21 @@ Number of file 0 mappings: 8 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: non_control_flow::assign_or -Raw bytes (62): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 08, 01, 10, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (72): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 10, 01, 00, 1f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 32) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) @@ -100,27 +106,32 @@ Number of file 0 mappings: 8 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: non_control_flow::foo -Raw bytes (9): 0x[01, 01, 00, 01, 01, 24, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 24, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: non_control_flow::func_call -Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 1f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) - Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 9) to (start + 0, 15) @@ -135,7 +146,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: non_control_flow::right_comb_tree -Raw bytes (111): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 0e, 01, 1f, 01, 00, 41, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 01, 02] +Raw bytes (121): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 10, 01, 1f, 01, 00, 40, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/non_control_flow.rs Number of expressions: 5 @@ -144,8 +155,8 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(2), rhs = Counter(3) - expression 3 operands: lhs = Counter(3), rhs = Counter(4) - expression 4 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 65) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 64) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) @@ -168,6 +179,8 @@ Number of file 0 mappings: 14 - MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39) true = c5 false = (c4 - c5) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c5 diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index 4a35da13a847..649c65d8590b 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -1,40 +1,60 @@ Function name: nested_loops::main -Raw bytes (97): 0x[01, 01, 0e, 07, 2f, 05, 11, 01, 0d, 2f, 05, 01, 0d, 27, 05, 01, 09, 33, 27, 05, 15, 01, 09, 2f, 33, 01, 0d, 05, 15, 05, 01, 0d, 01, 01, 01, 02, 1b, 05, 04, 13, 00, 20, 09, 01, 0d, 01, 18, 0d, 02, 12, 00, 17, 11, 01, 10, 00, 16, 02, 01, 11, 00, 16, 0e, 01, 0e, 03, 16, 15, 04, 11, 01, 1b, 16, 02, 15, 00, 21, 1e, 01, 18, 02, 12, 2a, 03, 0d, 00, 0e, 36, 02, 09, 00, 17, 01, 02, 01, 00, 02] +Raw bytes (164): 0x[01, 01, 14, 07, 47, 05, 11, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 3f, 05, 01, 09, 4b, 3f, 05, 15, 01, 09, 47, 4b, 01, 0d, 05, 15, 05, 01, 18, 01, 01, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 02, 13, 00, 20, 09, 01, 0d, 00, 12, 09, 00, 15, 00, 18, 09, 01, 0d, 00, 12, 09, 00, 15, 00, 18, 0d, 01, 12, 00, 17, 11, 01, 10, 00, 16, 02, 01, 11, 00, 16, 26, 01, 0d, 00, 0e, 26, 01, 0d, 00, 13, 26, 01, 0d, 00, 13, 26, 01, 10, 00, 16, 15, 01, 11, 00, 18, 15, 01, 14, 00, 1b, 2e, 01, 15, 00, 21, 36, 01, 18, 02, 12, 42, 03, 0d, 00, 0e, 4e, 02, 09, 00, 17, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/nested_loops.rs -Number of expressions: 14 -- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(11, Add) +Number of expressions: 20 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(17, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(1) +- expression 3 operands: lhs = Expression(17, Add), rhs = Counter(1) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(1) -- expression 6 operands: lhs = Counter(0), rhs = Counter(2) -- expression 7 operands: lhs = Expression(12, Add), rhs = Expression(9, Add) -- expression 8 operands: lhs = Counter(1), rhs = Counter(5) -- expression 9 operands: lhs = Counter(0), rhs = Counter(2) -- expression 10 operands: lhs = Expression(11, Add), rhs = Expression(12, Add) -- expression 11 operands: lhs = Counter(0), rhs = Counter(3) -- expression 12 operands: lhs = Counter(1), rhs = Counter(5) -- expression 13 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 1, 1) to (start + 2, 27) -- Code(Counter(1)) at (prev + 4, 19) to (start + 0, 32) -- Code(Counter(2)) at (prev + 1, 13) to (start + 1, 24) -- Code(Counter(3)) at (prev + 2, 18) to (start + 0, 23) +- expression 5 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 6 operands: lhs = Counter(0), rhs = Counter(3) +- expression 7 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 8 operands: lhs = Counter(0), rhs = Counter(3) +- expression 9 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 10 operands: lhs = Counter(0), rhs = Counter(3) +- expression 11 operands: lhs = Expression(15, Add), rhs = Counter(1) +- expression 12 operands: lhs = Counter(0), rhs = Counter(2) +- expression 13 operands: lhs = Expression(18, Add), rhs = Expression(15, Add) +- expression 14 operands: lhs = Counter(1), rhs = Counter(5) +- expression 15 operands: lhs = Counter(0), rhs = Counter(2) +- expression 16 operands: lhs = Expression(17, Add), rhs = Expression(18, Add) +- expression 17 operands: lhs = Counter(0), rhs = Counter(3) +- expression 18 operands: lhs = Counter(1), rhs = Counter(5) +- expression 19 operands: lhs = Counter(1), rhs = Counter(0) +Number of file 0 mappings: 24 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 2, 19) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(2)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(3)) at (prev + 1, 18) to (start + 0, 23) - Code(Counter(4)) at (prev + 1, 16) to (start + 0, 22) - Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 22) = ((c1 + c4) - (c0 + c3)) -- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 3, 22) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 14) = ((c0 + c3) - c1) -- Code(Counter(5)) at (prev + 4, 17) to (start + 1, 27) -- Code(Expression(5, Sub)) at (prev + 2, 21) to (start + 0, 33) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 19) + = ((c0 + c3) - c1) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 19) + = ((c0 + c3) - c1) +- Code(Expression(9, Sub)) at (prev + 1, 16) to (start + 0, 22) + = ((c0 + c3) - c1) +- Code(Counter(5)) at (prev + 1, 17) to (start + 0, 24) +- Code(Counter(5)) at (prev + 1, 20) to (start + 0, 27) +- Code(Expression(11, Sub)) at (prev + 1, 21) to (start + 0, 33) = ((c0 + c2) - c1) -- Code(Expression(7, Sub)) at (prev + 1, 24) to (start + 2, 18) +- Code(Expression(13, Sub)) at (prev + 1, 24) to (start + 2, 18) = ((c1 + c5) - (c0 + c2)) -- Code(Expression(10, Sub)) at (prev + 3, 13) to (start + 0, 14) +- Code(Expression(16, Sub)) at (prev + 3, 13) to (start + 0, 14) = ((c0 + c3) - (c1 + c5)) -- Code(Expression(13, Sub)) at (prev + 2, 9) to (start + 0, 23) +- Code(Expression(19, Sub)) at (prev + 2, 9) to (start + 0, 23) = (c1 - c0) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c5 diff --git a/tests/coverage/no-core.cov-map b/tests/coverage/no-core.cov-map index 89012b0ab917..f2867008127b 100644 --- a/tests/coverage/no-core.cov-map +++ b/tests/coverage/no-core.cov-map @@ -1,9 +1,10 @@ Function name: no_core::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0c, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 - file 0 => $DIR/no-core.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index caef09355d22..ca3c95fe84c4 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -1,68 +1,99 @@ Function name: no_cov_crate::add_coverage_1 -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_2 -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1a, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_not_called (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 00, 1d, 00, 01, 05, 00, 0d, 00, 00, 0e, 00, 26, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 31, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 31, 1) to (start + 0, 29) +- Code(Zero) at (prev + 1, 5) to (start + 0, 13) +- Code(Zero) at (prev + 0, 14) to (start + 0, 38) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: no_cov_crate::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 4f, 01, 0b, 02] +Raw bytes (74): 0x[01, 01, 00, 0e, 01, 4f, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 05, 00, 1a, 01, 01, 05, 00, 1a, 01, 01, 05, 00, 13, 01, 01, 05, 00, 13, 01, 02, 05, 00, 22, 01, 00, 23, 00, 2a, 01, 01, 05, 00, 16, 01, 00, 17, 00, 1e, 01, 01, 05, 00, 23, 01, 00, 24, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 79, 1) to (start + 11, 2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 79, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 36) to (start + 0, 43) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer -Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 05, 02, 22, 01, 0c, 05, 00, 06] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 33, 05, 00, 20, 01, 01, 09, 00, 11, 01, 00, 12, 00, 26, 01, 01, 09, 00, 1a, 01, 00, 1b, 00, 22, 01, 0a, 05, 00, 06] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 51, 5) to (start + 2, 34) -- Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 51, 5) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered -Raw bytes (14): 0x[01, 01, 00, 02, 01, 41, 05, 02, 16, 01, 0b, 05, 00, 06] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 41, 05, 00, 2d, 01, 01, 09, 00, 11, 01, 00, 12, 00, 26, 01, 01, 09, 00, 0e, 01, 00, 0f, 00, 16, 01, 09, 05, 00, 06] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 65, 5) to (start + 2, 22) -- Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 22) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered::inner -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 45, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 45, 09, 00, 20, 01, 01, 10, 00, 17, 05, 00, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 - file 0 => $DIR/no_cov_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 69, 9) to (start + 1, 23) -- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 69, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 23) +- Code(Counter(1)) at (prev + 0, 24) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage index 2a8961e6c93a..c6453e60a1a4 100644 --- a/tests/coverage/no_cov_crate.coverage +++ b/tests/coverage/no_cov_crate.coverage @@ -78,12 +78,12 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| do_not_add_coverage_1(); LL| 1| do_not_add_coverage_2(); LL| 1| add_coverage_1(); LL| 1| add_coverage_2(); - LL| 1| + LL| | LL| 1| nested_fns::outer_not_covered(is_true); LL| 1| nested_fns::outer(is_true); LL| 1| nested_fns::outer_both_covered(is_true); diff --git a/tests/coverage/no_spans.cov-map b/tests/coverage/no_spans.cov-map index 992247fd520b..821976b0fab0 100644 --- a/tests/coverage/no_spans.cov-map +++ b/tests/coverage/no_spans.cov-map @@ -1,18 +1,20 @@ Function name: no_spans::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 1c, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 1c, 00, 1d] Number of files: 1 - file 0 => $DIR/no_spans.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 26, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 21, 28) to (start + 0, 29) Highest counter ID seen: c0 -Function name: no_spans::affected_function::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e] +Function name: no_spans::main +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_spans.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 12) to (start + 0, 14) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/no_spans.coverage b/tests/coverage/no_spans.coverage index 19e8c2fe5b6b..cf0e47677e9a 100644 --- a/tests/coverage/no_spans.coverage +++ b/tests/coverage/no_spans.coverage @@ -1,20 +1,15 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 LL| | - LL| |// If the span extractor can't find any relevant spans for a function, the - LL| |// refinement loop will terminate with nothing in its `prev` slot. If the - LL| |// subsequent code tries to unwrap `prev`, it will panic. + LL| |// Test that coverage instrumentation can gracefully handle functions that end + LL| |// up having no relevant spans, without crashing the compiler or causing + LL| |// `llvm-cov` to fail. LL| |// - LL| |// This scenario became more likely after #118525 started discarding spans that - LL| |// can't be un-expanded back to within the function body. - LL| |// - LL| |// Regression test for "invalid attempt to unwrap a None some_prev", as seen - LL| |// in issues such as #118643 and #118662. + LL| |// This was originally a regression test for issues such as #118643 and #118662. LL| | - LL| |#[coverage(off)] - LL| |fn main() { - LL| | affected_function()(); - LL| |} + LL| 1|fn main() { + LL| 1| affected_function()(); + LL| 1|} LL| | LL| |macro_rules! macro_that_defines_a_function { LL| | (fn $name:ident () $body:tt) => { @@ -24,7 +19,7 @@ LL| | LL| |macro_that_defines_a_function! { LL| 1| fn affected_function() { - LL| 1| || () + LL| | || () LL| | } LL| |} diff --git a/tests/coverage/no_spans.rs b/tests/coverage/no_spans.rs index e5312406f8a1..979b40719277 100644 --- a/tests/coverage/no_spans.rs +++ b/tests/coverage/no_spans.rs @@ -1,17 +1,12 @@ #![feature(coverage_attribute)] //@ edition: 2021 -// If the span extractor can't find any relevant spans for a function, the -// refinement loop will terminate with nothing in its `prev` slot. If the -// subsequent code tries to unwrap `prev`, it will panic. +// Test that coverage instrumentation can gracefully handle functions that end +// up having no relevant spans, without crashing the compiler or causing +// `llvm-cov` to fail. // -// This scenario became more likely after #118525 started discarding spans that -// can't be un-expanded back to within the function body. -// -// Regression test for "invalid attempt to unwrap a None some_prev", as seen -// in issues such as #118643 and #118662. +// This was originally a regression test for issues such as #118643 and #118662. -#[coverage(off)] fn main() { affected_function()(); } diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map index 9d4fc074111f..c8aa5c7527d2 100644 --- a/tests/coverage/no_spans_if_not.cov-map +++ b/tests/coverage/no_spans_if_not.cov-map @@ -1,20 +1,23 @@ Function name: no_spans_if_not::affected_function -Raw bytes (19): 0x[01, 01, 00, 03, 01, 16, 1c, 01, 12, 01, 02, 0d, 00, 0f, 00, 02, 0d, 00, 0f] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 00, 1d, 01, 01, 0c, 00, 12, 01, 01, 0d, 00, 0f, 00, 02, 0d, 00, 0f] Number of files: 1 - file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 18) -- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 15) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 15) - Code(Zero) at (prev + 2, 13) to (start + 0, 15) Highest counter ID seen: c0 Function name: no_spans_if_not::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0b, 01, 00, 0a, 01, 01, 05, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index 9bb68ee107dd..18b0503b9e7c 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -1,5 +1,5 @@ Function name: overflow::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 10, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 03, 0a, 06, 03, 13, 00, 20, 0d, 00, 21, 03, 0a, 0e, 03, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (96): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 10, 01, 10, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 03, 0a, 09, 01, 11, 00, 17, 09, 00, 1a, 00, 28, 06, 02, 13, 00, 20, 0d, 00, 21, 03, 0a, 0d, 01, 11, 00, 17, 0d, 00, 1a, 00, 28, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/overflow.rs Number of expressions: 6 @@ -9,33 +9,50 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 3, 10) -- Code(Expression(1, Sub)) at (prev + 3, 19) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(2)) at (prev + 0, 26) to (start + 0, 40) +- Code(Expression(1, Sub)) at (prev + 2, 19) to (start + 0, 32) = (c1 - (c0 + c2)) - Code(Counter(3)) at (prev + 0, 33) to (start + 3, 10) -- Code(Expression(3, Sub)) at (prev + 3, 9) to (start + 0, 10) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(3)) at (prev + 0, 26) to (start + 0, 40) +- Code(Expression(3, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: overflow::might_overflow -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 05, 02] +Raw bytes (76): 0x[01, 01, 01, 01, 05, 0e, 01, 05, 01, 00, 26, 01, 01, 08, 00, 12, 05, 00, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1e, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 26, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 21, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 2f, 01, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/overflow.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 18) +- Code(Counter(1)) at (prev + 0, 19) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index f6d1fe5b9b48..ff656d3d8d58 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -1,5 +1,5 @@ Function name: panic_unwind::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (76): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 0c, 01, 0d, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/panic_unwind.rs Number of expressions: 6 @@ -9,9 +9,11 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 2, 10) @@ -22,19 +24,25 @@ Number of file 0 mappings: 9 = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: panic_unwind::might_panic -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 04, 01, 00, 23, 01, 01, 08, 00, 14, 05, 01, 09, 00, 11, 05, 00, 12, 00, 20, 05, 01, 09, 00, 0f, 02, 01, 0c, 02, 06, 02, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/panic_unwind.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 32) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 02054aa444a5..0a81be749128 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,18 +1,29 @@ Function name: ::new -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0c, 05, 00, 41, 01, 01, 09, 00, 25, 01, 00, 10, 00, 15, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/partial_eq.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 12, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: partial_eq::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 11, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 25, 01, 01, 09, 00, 16, 01, 00, 19, 00, 25, 01, 02, 05, 00, 0d, 01, 01, 09, 00, 1b, 01, 03, 09, 00, 26, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/partial_eq.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 37) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 27) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 38) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index dc5b82b3c5f1..0662ce2c3000 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -17,13 +17,13 @@ LL| 1|fn main() { LL| 1| let version_3_2_1 = Version::new(3, 2, 1); LL| 1| let version_3_3_0 = Version::new(3, 3, 0); - LL| 1| + LL| | LL| 1| println!( LL| 1| "{:?} < {:?} = {}", - LL| 1| version_3_2_1, - LL| 1| version_3_3_0, + LL| | version_3_2_1, + LL| | version_3_3_0, LL| 1| version_3_2_1 < version_3_3_0, // - LL| 1| ); + LL| | ); LL| 1|} LL| | LL| |/* diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index 542c93cbfa05..5447ffdb6e7c 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,19 +1,27 @@ Function name: simple_loop::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 09, 01, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 05, 00, 06, 09, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 06, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] +Raw bytes (75): 0x[01, 01, 03, 01, 05, 09, 01, 09, 01, 0d, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 03, 09, 00, 10, 05, 01, 05, 05, 06, 02, 05, 05, 00, 06, 09, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 0a, 02, 09, 00, 0a, 0a, 01, 09, 02, 0a, 01, 05, 01, 00, 02] Number of files: 1 - file 0 => $DIR/simple_loop.rs -Number of expressions: 2 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16) -- Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) +- expression 2 operands: lhs = Counter(2), rhs = Counter(0) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(2)) at (prev + 5, 13) to (start + 2, 14) - Code(Counter(0)) at (prev + 4, 13) to (start + 0, 18) -- Code(Expression(1, Sub)) at (prev + 2, 10) to (start + 3, 10) +- Code(Expression(2, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c2 - c0) -- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2) +- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 2, 10) + = (c2 - c0) +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage index 237e509f42e1..a75263f633e5 100644 --- a/tests/coverage/simple_loop.coverage +++ b/tests/coverage/simple_loop.coverage @@ -2,14 +2,14 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; - LL| 1| - LL| 1| if + LL| | + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index a96ddc2bb9ae..cbd6c7ca52fd 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,5 +1,5 @@ Function name: simple_match::main -Raw bytes (64): 0x[01, 01, 05, 01, 05, 09, 01, 09, 01, 09, 13, 01, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 09, 05, 09, 00, 0d, 0a, 05, 0d, 00, 16, 0d, 02, 0d, 00, 0e, 0a, 02, 11, 02, 12, 0d, 04, 0d, 07, 0e, 0e, 0a, 0d, 00, 0f, 01, 03, 01, 00, 02] +Raw bytes (99): 0x[01, 01, 05, 01, 05, 09, 01, 09, 01, 09, 13, 01, 0d, 11, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 09, 05, 09, 00, 0d, 0a, 05, 0d, 00, 16, 0d, 02, 0d, 00, 0e, 0a, 02, 11, 02, 12, 0d, 04, 0d, 07, 0e, 0d, 01, 11, 00, 1e, 0d, 02, 15, 00, 16, 0e, 07, 0d, 00, 0f, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/simple_match.rs Number of expressions: 5 @@ -8,9 +8,14 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(2), rhs = Counter(0) - expression 3 operands: lhs = Counter(2), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(2)) at (prev + 5, 9) to (start + 0, 13) @@ -20,7 +25,9 @@ Number of file 0 mappings: 10 - Code(Expression(2, Sub)) at (prev + 2, 17) to (start + 2, 18) = (c2 - c0) - Code(Counter(3)) at (prev + 4, 13) to (start + 7, 14) -- Code(Expression(3, Sub)) at (prev + 10, 13) to (start + 0, 15) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 30) +- Code(Counter(3)) at (prev + 2, 21) to (start + 0, 22) +- Code(Expression(3, Sub)) at (prev + 7, 13) to (start + 0, 15) = (c2 - (c0 + c3)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage index e1d5e48a2bf1..0ed7e8dc7887 100644 --- a/tests/coverage/simple_match.coverage +++ b/tests/coverage/simple_match.coverage @@ -2,11 +2,11 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 1; LL| 1| if is_true { LL| 1| countdown = 0; diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index b0d260efeb9a..70cf7cff4b67 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -1,79 +1,98 @@ Function name: sort_groups::generic_fn::<&str> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 1c, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] +Raw bytes (76): 0x[01, 01, 01, 01, 05, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0d, 01, 00, 10, 00, 2a, 01, 01, 05, 00, 15, 01, 00, 16, 00, 1a, 01, 01, 05, 00, 1f, 01, 00, 20, 00, 25, 01, 01, 08, 00, 1c, 05, 00, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 00, 16, 01, 00, 17, 00, 1b, 01, 01, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 28) -- Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 36) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::other_fn -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 17, 01, 00, 0e, 01, 00, 10, 00, 11] Number of files: 1 - file 0 => $DIR/sort_groups.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) Highest counter ID seen: c0 diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map index 50654fb22137..691332a1c420 100644 --- a/tests/coverage/test_harness.cov-map +++ b/tests/coverage/test_harness.cov-map @@ -1,18 +1,20 @@ Function name: test_harness::my_test -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 10] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 00, 0d, 01, 00, 0f, 00, 10] Number of files: 1 - file 0 => $DIR/test_harness.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) Highest counter ID seen: c0 Function name: test_harness::unused (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 07, 01, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 - file 0 => $DIR/test_harness.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 7, 1) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 7, 1) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) diff --git a/tests/coverage/tight_inf_loop.cov-map b/tests/coverage/tight_inf_loop.cov-map index 31581f0872f9..c6bee3bd7ad9 100644 --- a/tests/coverage/tight_inf_loop.cov-map +++ b/tests/coverage/tight_inf_loop.cov-map @@ -1,11 +1,13 @@ Function name: tight_inf_loop::main -Raw bytes (19): 0x[01, 01, 00, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 01, 01, 06, 01, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 01, 01, 00, 0a, 01, 01, 08, 00, 0d, 00, 01, 09, 00, 10, 01, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/tight_inf_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 13) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) -- Code(Counter(0)) at (prev + 1, 6) to (start + 1, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 13) +- Code(Zero) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/trivial.cov-map b/tests/coverage/trivial.cov-map index 0064b20480f3..fff10df9aee5 100644 --- a/tests/coverage/trivial.cov-map +++ b/tests/coverage/trivial.cov-map @@ -1,9 +1,10 @@ Function name: trivial::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 03, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 - file 0 => $DIR/trivial.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index a6ecc68ab0e8..e08f42961532 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -1,61 +1,68 @@ Function name: ::get_thing_2 -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 29, 05, 00, 44, 01, 01, 0c, 00, 18, 05, 01, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06] Number of files: 1 - file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 41, 5) to (start + 1, 24) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 41, 5) to (start + 0, 68) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: ::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 34, 05, 00, 3a, 01, 01, 0c, 00, 18, 05, 01, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] Number of files: 1 - file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 52, 5) to (start + 1, 24) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 52, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: try_error_result::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 05, 01, 00, 2e, 01, 01, 08, 00, 14, 05, 01, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: try_error_result::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0a, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (46): 0x[01, 01, 01, 01, 05, 08, 01, 71, 01, 00, 1c, 01, 01, 05, 00, 0a, 01, 00, 0d, 00, 17, 01, 00, 18, 00, 2b, 01, 01, 05, 00, 0a, 05, 01, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 10) -- Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 113, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 43) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: try_error_result::test1 -Raw bytes (67): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0b, 01, 0d, 01, 02, 17, 05, 07, 09, 00, 0e, 09, 02, 09, 04, 1a, 02, 06, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (82): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0e, 01, 0d, 01, 00, 1d, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 02, 02, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/try_error_result.rs Number of expressions: 4 @@ -63,11 +70,14 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(0) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23) -- Code(Counter(1)) at (prev + 7, 9) to (start + 0, 14) -- Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Expression(0, Sub)) at (prev + 6, 13) to (start + 0, 17) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 18) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 23) +- Code(Counter(1)) at (prev + 5, 9) to (start + 0, 14) +- Code(Counter(2)) at (prev + 2, 9) to (start + 1, 17) +- Code(Counter(2)) at (prev + 4, 13) to (start + 0, 26) +- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 17) = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 0, 41) to (start + 0, 42) = ((c0 + c2) - c1) @@ -82,125 +92,157 @@ Number of file 0 mappings: 11 Highest counter ID seen: c2 Function name: try_error_result::test2 -Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 17, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 17, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 17, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 17, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 17, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] +Raw bytes (443): 0x[01, 01, 3d, 0d, 11, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 53, 57, 19, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 41, 6b, 21, 25, 41, 21, 41, 6b, 21, 25, 09, 8f, 01, 93, 01, 2d, 0d, 29, 09, 0d, 09, 0d, 09, 93, 01, 0d, 29, 09, 8f, 01, 93, 01, 2d, 0d, 29, 45, a7, 01, 31, 35, 45, 31, 45, a7, 01, 31, 35, 49, bb, 01, 39, 3d, 49, 39, 49, bb, 01, 39, 3d, 05, 09, c7, 01, 09, cb, 01, 3d, cf, 01, 39, d3, 01, 35, d7, 01, 31, db, 01, 2d, df, 01, 29, e3, 01, 25, e7, 01, 21, eb, 01, 1d, ef, 01, 19, f3, 01, 15, 05, 11, 39, 01, 3d, 01, 00, 1d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1a, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 0d, 02, 0d, 00, 13, 0d, 00, 14, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 00, 35, 02, 00, 45, 00, 4f, 02, 00, 50, 00, 62, 02, 01, 0d, 00, 13, 02, 02, 11, 00, 1c, 15, 01, 11, 00, 12, 36, 02, 11, 00, 15, 36, 02, 11, 00, 1b, 36, 01, 15, 00, 27, 4a, 02, 11, 00, 14, 36, 00, 17, 00, 1d, 36, 00, 1e, 00, 29, 19, 00, 41, 00, 42, 3e, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 4a, 01, 0d, 00, 17, 66, 01, 11, 00, 14, 41, 00, 17, 00, 1d, 41, 00, 1e, 00, 29, 21, 00, 41, 00, 42, 62, 00, 43, 00, 47, 25, 00, 60, 00, 61, 66, 01, 0d, 00, 17, 8a, 01, 04, 11, 00, 14, 7e, 00, 17, 00, 1d, 7e, 00, 1e, 00, 29, 29, 00, 42, 00, 43, 82, 01, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 8a, 01, 01, 0d, 00, 17, a2, 01, 01, 11, 00, 14, 45, 00, 17, 00, 1d, 45, 01, 12, 00, 1d, 31, 00, 36, 00, 37, 9e, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 17, b6, 01, 01, 11, 00, 14, 49, 00, 17, 00, 1d, 49, 01, 12, 00, 1d, 39, 01, 11, 00, 12, b2, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 17, be, 01, 03, 05, 00, 0b, c2, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/try_error_result.rs -Number of expressions: 54 +Number of expressions: 61 - expression 0 operands: lhs = Counter(3), rhs = Counter(4) -- expression 1 operands: lhs = Counter(3), rhs = Expression(15, Add) +- expression 1 operands: lhs = Counter(3), rhs = Expression(21, Add) - expression 2 operands: lhs = Counter(4), rhs = Counter(5) -- expression 3 operands: lhs = Counter(3), rhs = Expression(13, Add) -- expression 4 operands: lhs = Expression(14, Add), rhs = Counter(7) -- expression 5 operands: lhs = Expression(15, Add), rhs = Counter(6) +- expression 3 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 5 operands: lhs = Counter(3), rhs = Expression(21, Add) - expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Counter(3), rhs = Expression(15, Add) -- expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Counter(3), rhs = Expression(14, Add) -- expression 10 operands: lhs = Expression(15, Add), rhs = Counter(6) -- expression 11 operands: lhs = Counter(4), rhs = Counter(5) -- expression 12 operands: lhs = Counter(3), rhs = Expression(13, Add) -- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(7) -- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(6) -- expression 15 operands: lhs = Counter(4), rhs = Counter(5) -- expression 16 operands: lhs = Counter(16), rhs = Expression(20, Add) -- expression 17 operands: lhs = Counter(8), rhs = Counter(9) -- expression 18 operands: lhs = Counter(16), rhs = Counter(8) -- expression 19 operands: lhs = Counter(16), rhs = Expression(20, Add) -- expression 20 operands: lhs = Counter(8), rhs = Counter(9) -- expression 21 operands: lhs = Counter(2), rhs = Expression(28, Add) -- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(11) -- expression 23 operands: lhs = Counter(3), rhs = Counter(10) -- expression 24 operands: lhs = Counter(2), rhs = Counter(3) -- expression 25 operands: lhs = Counter(2), rhs = Expression(29, Add) -- expression 26 operands: lhs = Counter(3), rhs = Counter(10) -- expression 27 operands: lhs = Counter(2), rhs = Expression(28, Add) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(11) +- expression 7 operands: lhs = Counter(3), rhs = Expression(19, Add) +- expression 8 operands: lhs = Expression(20, Add), rhs = Counter(7) +- expression 9 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 10 operands: lhs = Counter(4), rhs = Counter(5) +- expression 11 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 12 operands: lhs = Counter(4), rhs = Counter(5) +- expression 13 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 14 operands: lhs = Counter(4), rhs = Counter(5) +- expression 15 operands: lhs = Counter(3), rhs = Expression(20, Add) +- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 17 operands: lhs = Counter(4), rhs = Counter(5) +- expression 18 operands: lhs = Counter(3), rhs = Expression(19, Add) +- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(7) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 21 operands: lhs = Counter(4), rhs = Counter(5) +- expression 22 operands: lhs = Counter(16), rhs = Expression(26, Add) +- expression 23 operands: lhs = Counter(8), rhs = Counter(9) +- expression 24 operands: lhs = Counter(16), rhs = Counter(8) +- expression 25 operands: lhs = Counter(16), rhs = Expression(26, Add) +- expression 26 operands: lhs = Counter(8), rhs = Counter(9) +- expression 27 operands: lhs = Counter(2), rhs = Expression(35, Add) +- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(11) - expression 29 operands: lhs = Counter(3), rhs = Counter(10) -- expression 30 operands: lhs = Counter(17), rhs = Expression(34, Add) -- expression 31 operands: lhs = Counter(12), rhs = Counter(13) -- expression 32 operands: lhs = Counter(17), rhs = Counter(12) -- expression 33 operands: lhs = Counter(17), rhs = Expression(34, Add) -- expression 34 operands: lhs = Counter(12), rhs = Counter(13) -- expression 35 operands: lhs = Counter(18), rhs = Expression(39, Add) -- expression 36 operands: lhs = Counter(14), rhs = Counter(15) -- expression 37 operands: lhs = Counter(18), rhs = Counter(14) -- expression 38 operands: lhs = Counter(18), rhs = Expression(39, Add) -- expression 39 operands: lhs = Counter(14), rhs = Counter(15) -- expression 40 operands: lhs = Counter(1), rhs = Counter(2) -- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(2) -- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(15) -- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(14) -- expression 44 operands: lhs = Expression(45, Add), rhs = Counter(13) -- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(12) -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(11) -- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(10) -- expression 48 operands: lhs = Expression(49, Add), rhs = Counter(9) -- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(8) -- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(7) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 52 operands: lhs = Expression(53, Add), rhs = Counter(5) -- expression 53 operands: lhs = Counter(1), rhs = Counter(4) -Number of file 0 mappings: 40 -- Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) -- Code(Counter(1)) at (prev + 8, 9) to (start + 0, 14) -- Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Counter(3)) at (prev + 6, 13) to (start + 0, 31) +- expression 30 operands: lhs = Counter(2), rhs = Counter(3) +- expression 31 operands: lhs = Counter(2), rhs = Counter(3) +- expression 32 operands: lhs = Counter(2), rhs = Expression(36, Add) +- expression 33 operands: lhs = Counter(3), rhs = Counter(10) +- expression 34 operands: lhs = Counter(2), rhs = Expression(35, Add) +- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(11) +- expression 36 operands: lhs = Counter(3), rhs = Counter(10) +- expression 37 operands: lhs = Counter(17), rhs = Expression(41, Add) +- expression 38 operands: lhs = Counter(12), rhs = Counter(13) +- expression 39 operands: lhs = Counter(17), rhs = Counter(12) +- expression 40 operands: lhs = Counter(17), rhs = Expression(41, Add) +- expression 41 operands: lhs = Counter(12), rhs = Counter(13) +- expression 42 operands: lhs = Counter(18), rhs = Expression(46, Add) +- expression 43 operands: lhs = Counter(14), rhs = Counter(15) +- expression 44 operands: lhs = Counter(18), rhs = Counter(14) +- expression 45 operands: lhs = Counter(18), rhs = Expression(46, Add) +- expression 46 operands: lhs = Counter(14), rhs = Counter(15) +- expression 47 operands: lhs = Counter(1), rhs = Counter(2) +- expression 48 operands: lhs = Expression(49, Add), rhs = Counter(2) +- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(15) +- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(14) +- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(13) +- expression 52 operands: lhs = Expression(53, Add), rhs = Counter(12) +- expression 53 operands: lhs = Expression(54, Add), rhs = Counter(11) +- expression 54 operands: lhs = Expression(55, Add), rhs = Counter(10) +- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(9) +- expression 56 operands: lhs = Expression(57, Add), rhs = Counter(8) +- expression 57 operands: lhs = Expression(58, Add), rhs = Counter(7) +- expression 58 operands: lhs = Expression(59, Add), rhs = Counter(6) +- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(5) +- expression 60 operands: lhs = Counter(1), rhs = Counter(4) +Number of file 0 mappings: 57 +- Code(Counter(0)) at (prev + 61, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 18) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 23) +- Code(Counter(1)) at (prev + 5, 9) to (start + 0, 14) +- Code(Counter(2)) at (prev + 2, 9) to (start + 1, 17) +- Code(Counter(2)) at (prev + 4, 13) to (start + 0, 26) +- Code(Counter(3)) at (prev + 2, 13) to (start + 0, 19) +- Code(Counter(3)) at (prev + 0, 20) to (start + 0, 31) - Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 3, 28) +- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 0, 53) = (c3 - c4) -- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) -- Code(Expression(7, Sub)) at (prev + 2, 17) to (start + 3, 39) +- Code(Expression(0, Sub)) at (prev + 0, 69) to (start + 0, 79) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 0, 80) to (start + 0, 98) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 28) + = (c3 - c4) +- Code(Counter(5)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 21) = (c3 - (c4 + c5)) -- Code(Expression(12, Sub)) at (prev + 5, 17) to (start + 0, 20) +- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 27) + = (c3 - (c4 + c5)) +- Code(Expression(13, Sub)) at (prev + 1, 21) to (start + 0, 39) + = (c3 - (c4 + c5)) +- Code(Expression(18, Sub)) at (prev + 2, 17) to (start + 0, 20) = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 41) +- Code(Expression(13, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c3 - (c4 + c5)) +- Code(Expression(13, Sub)) at (prev + 0, 30) to (start + 0, 41) = (c3 - (c4 + c5)) - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(9, Sub)) at (prev + 0, 67) to (start + 0, 71) +- Code(Expression(15, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c3 - ((c4 + c5) + c6)) - Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) -- Code(Expression(12, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(18, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(25, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c16 - (c8 + c9)) -- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 41) +- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(16)) at (prev + 0, 30) to (start + 0, 41) - Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 71) +- Code(Expression(24, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c16 - c8) - Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) -- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(25, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c16 - (c8 + c9)) -- Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 20) +- Code(Expression(34, Sub)) at (prev + 4, 17) to (start + 0, 20) = (c2 - ((c3 + c10) + c11)) -- Code(Expression(24, Sub)) at (prev + 0, 23) to (start + 0, 41) +- Code(Expression(31, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c2 - c3) +- Code(Expression(31, Sub)) at (prev + 0, 30) to (start + 0, 41) = (c2 - c3) - Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(25, Sub)) at (prev + 0, 68) to (start + 0, 72) +- Code(Expression(32, Sub)) at (prev + 0, 68) to (start + 0, 72) = (c2 - (c3 + c10)) - Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(27, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(34, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c2 - ((c3 + c10) + c11)) -- Code(Expression(33, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c17 - (c12 + c13)) -- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 29) -- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) -- Code(Expression(32, Sub)) at (prev + 1, 18) to (start + 0, 22) +- Code(Counter(17)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(17)) at (prev + 1, 18) to (start + 0, 29) +- Code(Counter(12)) at (prev + 0, 54) to (start + 0, 55) +- Code(Expression(39, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c17 - c12) - Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c17 - (c12 + c13)) -- Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c18 - (c14 + c15)) -- Code(Counter(18)) at (prev + 0, 23) to (start + 1, 29) -- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) -- Code(Expression(37, Sub)) at (prev + 1, 18) to (start + 0, 22) +- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(18)) at (prev + 1, 18) to (start + 0, 29) +- Code(Counter(14)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c18 - c14) - Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 23) +- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 23) = (c18 - (c14 + c15)) -- Code(Expression(40, Sub)) at (prev + 3, 5) to (start + 0, 11) +- Code(Expression(47, Sub)) at (prev + 3, 5) to (start + 0, 11) = (c1 - c2) -- Code(Expression(41, Sub)) at (prev + 1, 1) to (start + 0, 2) +- Code(Expression(48, Sub)) at (prev + 1, 1) to (start + 0, 2) = (((((((((((((c1 + c4) + c5) + c6) + c7) + c8) + c9) + c10) + c11) + c12) + c13) + c14) + c15) - c2) Highest counter ID seen: c18 diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 7a89c0452ac4..f2ec82f20fa2 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -21,8 +21,8 @@ LL| | { LL| 6| countdown LL| 6| -= 1 - LL| 6| ; - LL| 6| if + LL| | ; + LL| | if LL| 6| countdown < 5 LL| | { LL| 1| call(/*return_error=*/ true)?; @@ -71,19 +71,19 @@ LL| | { LL| 6| countdown LL| 6| -= 1 - LL| 6| ; - LL| 6| if + LL| | ; + LL| | if LL| 6| countdown < 5 LL| | { LL| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); ^0 LL| 1| thing1 - LL| 1| . + LL| | . LL| 1| get_thing_2(/*return_error=*/ false) LL| 0| ? LL| | . LL| 1| call(/*return_error=*/ true) - LL| 1| . + LL| | . LL| 1| expect_err( LL| 1| "call should fail" LL| | ); diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 7ad4395491f0..bbfa8b940c6d 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,12 +1,12 @@ Function name: unicode::main -Raw bytes (53): 0x[01, 01, 02, 05, 01, 01, 0d, 09, 01, 0e, 01, 00, 0b, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] +Raw bytes (58): 0x[01, 01, 02, 05, 01, 01, 0d, 0a, 01, 0e, 01, 00, 0a, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unicode.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 12) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 27) @@ -17,24 +17,28 @@ Number of file 0 mappings: 9 - Code(Counter(3)) at (prev + 0, 71) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c3) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: unicode::他 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1e, 19, 00, 22, 00, 00, 24, 00, 25] Number of files: 1 - file 0 => $DIR/unicode.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 30, 25) to (start + 0, 37) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 30, 25) to (start + 0, 34) +- Code(Zero) at (prev + 0, 36) to (start + 0, 37) Highest counter ID seen: (none) Function name: unicode::申し訳ございません -Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 18, 01, 00, 29, 01, 01, 05, 00, 19, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unicode.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index 443499545500..4646cc92e8e4 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -29,7 +29,7 @@ LL| | LL| |macro_rules! macro_that_defines_a_function { LL| | (fn $名:ident () $体:tt) => { - LL| 0| fn $名 () $体 fn 他 () {} + LL| 0| fn $名 () $体 fn 他 () {} LL| | } LL| |} LL| | diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index fd9a1abc8cb0..c38786ee664c 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -1,27 +1,29 @@ Function name: unreachable::UNREACHABLE_CLOSURE::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 27, 00, 45] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 30, 00, 45] Number of files: 1 - file 0 => $DIR/unreachable.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 14, 39) to (start + 0, 69) +- Code(Zero) at (prev + 14, 48) to (start + 0, 69) Highest counter ID seen: (none) Function name: unreachable::unreachable_function (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 10, 01, 01, 23] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 10, 01, 00, 1a, 00, 01, 0e, 00, 23] Number of files: 1 - file 0 => $DIR/unreachable.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 16, 1) to (start + 1, 35) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 16, 1) to (start + 0, 26) +- Code(Zero) at (prev + 1, 14) to (start + 0, 35) Highest counter ID seen: (none) Function name: unreachable::unreachable_intrinsic (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 01, 2a] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 15, 01, 00, 1b, 00, 01, 0e, 00, 2a] Number of files: 1 - file 0 => $DIR/unreachable.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 1, 42) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 21, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 14) to (start + 0, 42) Highest counter ID seen: (none) diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index 8946b43a8bbc..3380997b921e 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -1,14 +1,16 @@ Function name: unused::foo:: -Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 08, 01, 03, 01, 00, 10, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 17) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c1 - c0) - Code(Expression(1, Sub)) at (prev + 0, 19) to (start + 0, 25) @@ -19,16 +21,18 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: unused::foo:: -Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 08, 01, 03, 01, 00, 10, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 17) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c1 - c0) - Code(Expression(1, Sub)) at (prev + 0, 19) to (start + 0, 25) @@ -39,58 +43,67 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: unused::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 25, 01, 00, 1c, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: unused::unused_func (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 13, 01, 00, 1b, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 19, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 19, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 19, 01, 00, 1c, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 25, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 25, 1) to (start + 0, 28) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 1f, 01, 00, 1c, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 31, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 31, 1) to (start + 0, 28) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_template_func::<_> (unused) -Raw bytes (34): 0x[01, 01, 00, 06, 00, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 00, 0b, 01, 00, 21, 00, 01, 09, 00, 0e, 00, 00, 11, 00, 12, 00, 01, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 6 -- Code(Zero) at (prev + 11, 1) to (start + 1, 18) -- Code(Zero) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Zero) at (prev + 11, 1) to (start + 0, 33) +- Code(Zero) at (prev + 1, 9) to (start + 0, 14) +- Code(Zero) at (prev + 0, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 11) to (start + 0, 17) - Code(Zero) at (prev + 1, 9) to (start + 0, 15) - Code(Zero) at (prev + 0, 19) to (start + 0, 25) - Code(Zero) at (prev + 1, 9) to (start + 0, 15) diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map index 790cd701dc3a..ea419edbdafe 100644 --- a/tests/coverage/unused_mod.cov-map +++ b/tests/coverage/unused_mod.cov-map @@ -1,18 +1,24 @@ Function name: unused_mod::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 04, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 1c, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/unused_mod.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: unused_mod::unused_module::never_called_function (unused) -Raw bytes (9): 0x[01, 02, 00, 01, 00, 02, 01, 02, 02] +Raw bytes (24): 0x[01, 02, 00, 04, 00, 02, 01, 00, 1f, 00, 01, 05, 00, 0d, 00, 00, 0e, 00, 21, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/unused_mod_helper.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 2, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 2, 1) to (start + 0, 31) +- Code(Zero) at (prev + 1, 5) to (start + 0, 13) +- Code(Zero) at (prev + 0, 14) to (start + 0, 33) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/uses_crate.cov-map index 238226f3d683..8f3c63aba5ce 100644 --- a/tests/coverage/uses_crate.cov-map +++ b/tests/coverage/uses_crate.cov-map @@ -1,45 +1,67 @@ Function name: used_crate::used_from_bin_crate_and_lib_crate_generic_function::> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1b, 01, 00, 4c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 4f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 79) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 13, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 13, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 00, 5b, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 5e, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 91) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 94) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: uses_crate::main -Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 07, 02] +Raw bytes (59): 0x[01, 02, 00, 0b, 01, 0c, 01, 00, 0a, 01, 01, 05, 00, 1e, 01, 01, 09, 00, 11, 01, 00, 14, 00, 18, 01, 01, 05, 00, 3a, 01, 00, 3b, 00, 44, 01, 01, 05, 00, 3a, 01, 01, 05, 00, 43, 01, 00, 44, 00, 4c, 01, 01, 05, 00, 52, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/uses_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 7, 2) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 0, 59) to (start + 0, 68) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 0, 68) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 82) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index d1b0dadda768..145c0649ac7b 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -6,9 +6,9 @@ $DIR/auxiliary/used_crate.rs: LL| |use std::fmt::Debug; LL| | LL| 1|pub fn used_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -104,8 +104,8 @@ $DIR/auxiliary/used_crate.rs: LL| 1|fn use_this_lib_crate() { LL| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); LL| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 1| "used from library used_crate.rs", - LL| 1| ); + LL| | "used from library used_crate.rs", + LL| | ); LL| 1| let some_vec = vec![5, 6, 7, 8]; LL| 1| used_only_from_this_lib_crate_generic_function(some_vec); LL| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index fd14ea341202..52f3f94ce642 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -1,59 +1,88 @@ Function name: used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 2c, 01, 00, 4c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 4f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 79) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 01, 02] +Raw bytes (56): 0x[01, 01, 01, 01, 05, 0a, 01, 14, 01, 00, 1e, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15) -- Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 20, 1) to (start + 0, 30) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 31, 01, 00, 5b, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 5e, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 91) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 94) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: uses_inline_crate::main -Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 0a, 02] +Raw bytes (64): 0x[01, 02, 00, 0c, 01, 0c, 01, 00, 0a, 01, 01, 05, 00, 25, 01, 01, 05, 00, 2c, 01, 01, 09, 00, 11, 01, 00, 14, 00, 18, 01, 01, 05, 00, 41, 01, 00, 42, 00, 4b, 01, 01, 05, 00, 41, 01, 01, 05, 00, 4a, 01, 00, 4b, 00, 53, 01, 01, 05, 00, 59, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/uses_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 10, 2) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 0, 66) to (start + 0, 75) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 74) +- Code(Counter(0)) at (prev + 0, 75) to (start + 0, 83) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 89) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 4671c95aefa4..15084bcf7ea9 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -6,9 +6,9 @@ $DIR/auxiliary/used_inline_crate.rs: LL| |use std::fmt::Debug; LL| | LL| 1|pub fn used_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -20,9 +20,9 @@ $DIR/auxiliary/used_inline_crate.rs: LL| | LL| |#[inline(always)] LL| 1|pub fn used_inline_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -126,8 +126,8 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 2|fn use_this_lib_crate() { LL| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); LL| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 2| "used from library used_crate.rs", - LL| 2| ); + LL| | "used from library used_crate.rs", + LL| | ); LL| 2| let some_vec = vec![5, 6, 7, 8]; LL| 2| used_only_from_this_lib_crate_generic_function(some_vec); LL| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); @@ -153,7 +153,7 @@ $DIR/uses_inline_crate.rs: LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); LL| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); LL| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 1| "interesting?", - LL| 1| ); + LL| | "interesting?", + LL| | ); LL| 1|} diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map index 8ad739206297..c4183e18e021 100644 --- a/tests/coverage/while.cov-map +++ b/tests/coverage/while.cov-map @@ -1,11 +1,13 @@ Function name: while::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 01, 01, 01, 10, 01, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 01, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 10, 01, 01, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 20) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 20) - Code(Zero) at (prev + 0, 21) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index 6e3db66f97c7..b29b5d40c4df 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -1,27 +1,32 @@ Function name: while_early_ret::main -Raw bytes (63): 0x[01, 01, 07, 0f, 05, 01, 09, 0f, 13, 01, 09, 05, 0d, 05, 01, 05, 09, 09, 01, 05, 01, 01, 1b, 05, 03, 09, 02, 0a, 09, 05, 0d, 02, 0e, 02, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0a, 04, 15, 00, 1b, 16, 03, 0a, 03, 0a, 1a, 06, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (80): 0x[01, 01, 08, 0f, 05, 01, 09, 0f, 13, 01, 09, 05, 0d, 05, 01, 05, 01, 05, 09, 0c, 01, 05, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 02, 09, 02, 0a, 09, 05, 0d, 02, 0e, 02, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0a, 04, 15, 00, 1b, 1a, 03, 09, 00, 0a, 1a, 01, 09, 02, 0a, 1e, 05, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/while_early_ret.rs -Number of expressions: 7 +Number of expressions: 8 - expression 0 operands: lhs = Expression(3, Add), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Expression(3, Add), rhs = Expression(4, Add) - expression 3 operands: lhs = Counter(0), rhs = Counter(2) - expression 4 operands: lhs = Counter(1), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Counter(0) -- expression 6 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 3, 9) to (start + 2, 10) +- expression 6 operands: lhs = Counter(1), rhs = Counter(0) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 2, 9) to (start + 2, 10) - Code(Counter(2)) at (prev + 5, 13) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 6, 21) to (start + 2, 22) = ((c0 + c2) - c1) - Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27) - Code(Expression(2, Sub)) at (prev + 4, 21) to (start + 0, 27) = ((c0 + c2) - (c1 + c3)) -- Code(Expression(5, Sub)) at (prev + 3, 10) to (start + 3, 10) +- Code(Expression(6, Sub)) at (prev + 3, 9) to (start + 0, 10) = (c1 - c0) -- Code(Expression(6, Sub)) at (prev + 6, 5) to (start + 0, 11) +- Code(Expression(6, Sub)) at (prev + 1, 9) to (start + 2, 10) + = (c1 - c0) +- Code(Expression(7, Sub)) at (prev + 5, 5) to (start + 0, 11) = (c1 - c2) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index db82c9d673d1..87d0a0472615 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,5 +1,5 @@ Function name: yield::main -Raw bytes (94): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 2e, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 2e, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] +Raw bytes (139): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 19, 01, 07, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 06, 0b, 00, 13, 01, 00, 0b, 00, 2e, 01, 00, 14, 00, 22, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 13, 05, 00, 0b, 00, 2e, 05, 00, 14, 00, 22, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 13, 09, 00, 0b, 00, 2e, 09, 00, 14, 00, 22, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 13, 11, 00, 0b, 00, 2e, 11, 00, 14, 00, 22, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/yield.rs Number of expressions: 5 @@ -8,23 +8,32 @@ Number of expressions: 5 - expression 2 operands: lhs = Counter(2), rhs = Counter(4) - expression 3 operands: lhs = Counter(4), rhs = Counter(5) - expression 4 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 16 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(1)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(1)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) - Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c1 - c2) - Code(Counter(2)) at (prev + 3, 9) to (start + 0, 22) -- Code(Counter(2)) at (prev + 8, 11) to (start + 0, 46) +- Code(Counter(2)) at (prev + 8, 11) to (start + 0, 19) +- Code(Counter(2)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(2)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(4)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c2 - c4) -- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(4)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(4)) at (prev + 0, 20) to (start + 0, 34) - Code(Expression(4, Sub)) at (prev + 1, 39) to (start + 0, 41) = (c4 - c5) - Code(Counter(5)) at (prev + 1, 14) to (start + 0, 20) @@ -33,24 +42,28 @@ Number of file 0 mappings: 16 Highest counter ID seen: c5 Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] -Number of files: 1 -- file 0 => $DIR/yield.rs -Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) -- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) -Highest counter ID seen: c1 - -Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 08, 00, 09, 01, 01, 09, 00, 10, 05, 01, 10, 00, 15, 05, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/yield.rs Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 9, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c1 + +Function name: yield::main::{closure#1} +Raw bytes (34): 0x[01, 01, 00, 06, 01, 18, 08, 00, 09, 01, 01, 09, 00, 10, 05, 01, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 00, 15, 0d, 01, 05, 00, 06] +Number of files: 1 +- file 0 => $DIR/yield.rs +Number of expressions: 0 +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 24, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) -- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) +- Code(Counter(3)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c3 diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index 542b70bcee96..d465b8bded22 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -26,11 +26,20 @@ debug a => _9; } -+ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:14:1: 15:21 (#0); -+ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:32 (#0); -+ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:32 (#0); -+ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:32 (#0); -+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:32 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:14:1: 14:10 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:15:11: 15:21 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:18 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:23: 16:30 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:31: 16:32 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:18 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:23: 17:30 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:31: 17:32 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:18 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:23: 18:30 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:31: 18:32 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0); + coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0); + bb0: { diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff index 06e5f011c761..cf6d85abd80e 100644 --- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff @@ -4,7 +4,9 @@ fn bar() -> bool { let mut _0: bool; -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 29:2 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0); + bb0: { + Coverage::VirtualCounter(bcb0); diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index 30de92f3b868..980c5e202ffd 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -7,7 +7,7 @@ let mut _2: bool; let mut _3: !; -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:11 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index 1a22adeba6fc..b707cd41788a 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -7,7 +7,8 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) - coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index b77969a3e169..239b845c2311 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -7,7 +7,8 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); From 77a7ae4e9fcbf3be3988c98015d7f52137bb237c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 17 Apr 2025 17:03:08 +1000 Subject: [PATCH 277/302] coverage: Handle hole spans without dividing spans into buckets Because we no longer merge non-adjacent spans, there is no need to use buckets to prevent merging across hole spans. --- .../rustc_mir_transform/src/coverage/spans.rs | 90 +++++++------------ 1 file changed, 32 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index e6e7e2920ec0..ec76076020eb 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,11 +1,8 @@ -use std::collections::VecDeque; -use std::iter; - use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::ty::TyCtxt; use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; -use tracing::{debug, debug_span, instrument}; +use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; @@ -83,24 +80,17 @@ pub(super) fn extract_refined_covspans<'tcx>( holes.sort_by(|a, b| compare_spans(a.span, b.span)); holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); - // Split the covspans into separate buckets that don't overlap any holes. - let buckets = divide_spans_into_buckets(covspans, &holes); + // Discard any span that overlaps with a hole. + discard_spans_overlapping_holes(&mut covspans, &holes); - for covspans in buckets { - let _span = debug_span!("processing bucket", ?covspans).entered(); + // Perform more refinement steps after holes have been dealt with. + let mut covspans = remove_unwanted_overlapping_spans(covspans); + covspans.dedup_by(|b, a| a.merge_if_eligible(b)); - let mut covspans = remove_unwanted_overlapping_spans(covspans); - debug!(?covspans, "after removing overlaps"); - - // Do one last merge pass, to simplify the output. - covspans.dedup_by(|b, a| a.merge_if_eligible(b)); - debug!(?covspans, "after merge"); - - code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { - // Each span produced by the refiner represents an ordinary code region. - mappings::CodeMapping { span, bcb } - })); - } + code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { + // Each span produced by the refiner represents an ordinary code region. + mappings::CodeMapping { span, bcb } + })); } /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate @@ -142,52 +132,36 @@ fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec) } } -/// Uses the holes to divide the given covspans into buckets, such that: -/// - No span in any hole overlaps a bucket (discarding spans if necessary). -/// - The spans in each bucket are strictly after all spans in previous buckets, -/// and strictly before all spans in subsequent buckets. +/// Discard all covspans that overlap a hole. /// -/// The lists of covspans and holes must be sorted. -/// The resulting buckets are sorted relative to each other, and each bucket's -/// contents are sorted. -#[instrument(level = "debug")] -fn divide_spans_into_buckets(input_covspans: Vec, holes: &[Hole]) -> Vec> { - debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); +/// The lists of covspans and holes must be sorted, and any holes that overlap +/// with each other must have already been merged. +fn discard_spans_overlapping_holes(covspans: &mut Vec, holes: &[Hole]) { + debug_assert!(covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + debug_assert!(holes.array_windows().all(|[a, b]| !a.span.overlaps_or_adjacent(b.span))); - // Now we're ready to start grouping spans into buckets separated by holes. + let mut curr_hole = 0usize; + let mut overlaps_hole = |covspan: &Covspan| -> bool { + while let Some(hole) = holes.get(curr_hole) { + // Both lists are sorted, so we can permanently skip any holes that + // end before the start of the current span. + if hole.span.hi() <= covspan.span.lo() { + curr_hole += 1; + continue; + } - let mut input_covspans = VecDeque::from(input_covspans); + return hole.span.overlaps(covspan.span); + } - // For each hole: - // - Identify the spans that are entirely or partly before the hole. - // - Discard any that overlap with the hole. - // - Add the remaining identified spans to the corresponding bucket. - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); - for (hole, bucket) in holes.iter().zip(&mut buckets) { - bucket.extend( - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()) - .filter(|c| !c.span.overlaps(hole.span)), - ); - } + // No holes left, so this covspan doesn't overlap with any holes. + false + }; - // Any remaining spans form their own final bucket, after the final hole. - // (If there were no holes, this will just be all of the initial spans.) - buckets.push(Vec::from(input_covspans)); - - buckets + covspans.retain(|covspan| !overlaps_hole(covspan)); } -/// Similar to `.drain(..)`, but stops just before it would remove an item not -/// satisfying the predicate. -fn drain_front_while<'a, T>( - queue: &'a mut VecDeque, - mut pred_fn: impl FnMut(&T) -> bool, -) -> impl Iterator { - iter::from_fn(move || queue.pop_front_if(|x| pred_fn(x))) -} - -/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" +/// Takes a list of sorted spans extracted from MIR, and "refines" /// those spans by removing spans that overlap in unwanted ways. #[instrument(level = "debug")] fn remove_unwanted_overlapping_spans(sorted_spans: Vec) -> Vec { From 18a3599fe35a7df3ac5be1778d91f59c6b17d309 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 28 Jan 2025 13:38:30 +0100 Subject: [PATCH 278/302] Update iterator.rs to use arrays by value Update examples to no longer avoid iterating arrays for #84513 --- library/core/src/iter/traits/iterator.rs | 455 +++++++++++------------ 1 file changed, 225 insertions(+), 230 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 91c3a4b29b53..24d1d060f9ad 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -56,12 +56,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// // A call to next() returns the next value... - /// assert_eq!(Some(&1), iter.next()); - /// assert_eq!(Some(&2), iter.next()); - /// assert_eq!(Some(&3), iter.next()); + /// assert_eq!(Some(1), iter.next()); + /// assert_eq!(Some(2), iter.next()); + /// assert_eq!(Some(3), iter.next()); /// /// // ... and then None once it's over. /// assert_eq!(None, iter.next()); @@ -239,10 +239,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().last(), Some(&3)); + /// assert_eq!(a.into_iter().last(), Some(3)); /// /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().last(), Some(&5)); + /// assert_eq!(a.into_iter().last(), Some(5)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -284,12 +284,12 @@ pub trait Iterator { /// use std::num::NonZero; /// /// let a = [1, 2, 3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// assert_eq!(iter.advance_by(2), Ok(())); - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// assert_eq!(iter.advance_by(0), Ok(())); - /// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `&4` was skipped + /// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `4` was skipped /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] @@ -322,7 +322,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().nth(1), Some(&2)); + /// assert_eq!(a.into_iter().nth(1), Some(2)); /// ``` /// /// Calling `nth()` multiple times doesn't rewind the iterator: @@ -330,9 +330,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.nth(1), Some(&2)); + /// assert_eq!(iter.nth(1), Some(2)); /// assert_eq!(iter.nth(1), None); /// ``` /// @@ -340,7 +340,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().nth(10), None); + /// assert_eq!(a.into_iter().nth(10), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -385,11 +385,11 @@ pub trait Iterator { /// /// ``` /// let a = [0, 1, 2, 3, 4, 5]; - /// let mut iter = a.iter().step_by(2); + /// let mut iter = a.into_iter().step_by(2); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&4)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(4)); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -417,37 +417,37 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// let a1 = [1, 2, 3]; - /// let a2 = [4, 5, 6]; + /// let s1 = "abc".chars(); + /// let s2 = "def".chars(); /// - /// let mut iter = a1.iter().chain(a2.iter()); + /// let mut iter = s1.chain(s2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&4)); - /// assert_eq!(iter.next(), Some(&5)); - /// assert_eq!(iter.next(), Some(&6)); + /// assert_eq!(iter.next(), Some('a')); + /// assert_eq!(iter.next(), Some('b')); + /// assert_eq!(iter.next(), Some('c')); + /// assert_eq!(iter.next(), Some('d')); + /// assert_eq!(iter.next(), Some('e')); + /// assert_eq!(iter.next(), Some('f')); /// assert_eq!(iter.next(), None); /// ``` /// /// Since the argument to `chain()` uses [`IntoIterator`], we can pass /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example, slices (`&[T]`) implement + /// [`Iterator`] itself. For example, arrays (`[T]`) implement /// [`IntoIterator`], and so can be passed to `chain()` directly: /// /// ``` - /// let s1 = &[1, 2, 3]; - /// let s2 = &[4, 5, 6]; + /// let a1 = [1, 2, 3]; + /// let a2 = [4, 5, 6]; /// - /// let mut iter = s1.iter().chain(s2); + /// let mut iter = a1.into_iter().chain(a2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&4)); - /// assert_eq!(iter.next(), Some(&5)); - /// assert_eq!(iter.next(), Some(&6)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), Some(4)); + /// assert_eq!(iter.next(), Some(5)); + /// assert_eq!(iter.next(), Some(6)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -496,31 +496,31 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// let a1 = [1, 2, 3]; - /// let a2 = [4, 5, 6]; + /// let s1 = "abc".chars(); + /// let s2 = "def".chars(); /// - /// let mut iter = a1.iter().zip(a2.iter()); + /// let mut iter = s1.zip(s2); /// - /// assert_eq!(iter.next(), Some((&1, &4))); - /// assert_eq!(iter.next(), Some((&2, &5))); - /// assert_eq!(iter.next(), Some((&3, &6))); + /// assert_eq!(iter.next(), Some(('a', 'd'))); + /// assert_eq!(iter.next(), Some(('b', 'e'))); + /// assert_eq!(iter.next(), Some(('c', 'f'))); /// assert_eq!(iter.next(), None); /// ``` /// /// Since the argument to `zip()` uses [`IntoIterator`], we can pass /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example, slices (`&[T]`) implement + /// [`Iterator`] itself. For example, arrays (`[T]`) implement /// [`IntoIterator`], and so can be passed to `zip()` directly: /// /// ``` - /// let s1 = &[1, 2, 3]; - /// let s2 = &[4, 5, 6]; + /// let a1 = [1, 2, 3]; + /// let a2 = [4, 5, 6]; /// - /// let mut iter = s1.iter().zip(s2); + /// let mut iter = a1.into_iter().zip(a2); /// - /// assert_eq!(iter.next(), Some((&1, &4))); - /// assert_eq!(iter.next(), Some((&2, &5))); - /// assert_eq!(iter.next(), Some((&3, &6))); + /// assert_eq!(iter.next(), Some((1, 4))); + /// assert_eq!(iter.next(), Some((2, 5))); + /// assert_eq!(iter.next(), Some((3, 6))); /// assert_eq!(iter.next(), None); /// ``` /// @@ -604,12 +604,12 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let mut a = [0, 1, 2].iter().intersperse(&100); - /// assert_eq!(a.next(), Some(&0)); // The first element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&1)); // The next element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&2)); // The last element from `a`. + /// let mut a = [0, 1, 2].into_iter().intersperse(100); + /// assert_eq!(a.next(), Some(0)); // The first element from `a`. + /// assert_eq!(a.next(), Some(100)); // The separator. + /// assert_eq!(a.next(), Some(1)); // The next element from `a`. + /// assert_eq!(a.next(), Some(100)); // The separator. + /// assert_eq!(a.next(), Some(2)); // The last element from `a`. /// assert_eq!(a.next(), None); // The iterator is finished. /// ``` /// @@ -617,7 +617,8 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::(); + /// let words = ["Hello", "World", "!"]; + /// let hello: String = words.into_iter().intersperse(" ").collect(); /// assert_eq!(hello, "Hello World !"); /// ``` /// @@ -673,7 +674,7 @@ pub trait Iterator { /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); /// /// // The closure mutably borrows its context to generate an item. - /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied(); + /// let mut happy_emojis = [" ❤️ ", " 😀 "].into_iter(); /// let separator = || happy_emojis.next().unwrap_or(" 🦀 "); /// /// let result = src.intersperse_with(separator).collect::(); @@ -734,7 +735,7 @@ pub trait Iterator { /// /// // it won't even execute, as it is lazy. Rust will warn you about this. /// - /// // Instead, use for: + /// // Instead, use a for-loop: /// for x in 0..5 { /// println!("{x}"); /// } @@ -814,10 +815,10 @@ pub trait Iterator { /// ``` /// let a = [0i32, 1, 2]; /// - /// let mut iter = a.iter().filter(|x| x.is_positive()); + /// let mut iter = a.into_iter().filter(|x| x.is_positive()); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -826,21 +827,20 @@ pub trait Iterator { /// situation, where the type of the closure is a double reference: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s! + /// let mut iter = s.iter().filter(|x| **x > 1); // needs two *s! /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); /// ``` /// - /// It's common to instead use destructuring on the argument to strip away - /// one: + /// It's common to instead use destructuring on the argument to strip away one: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and * + /// let mut iter = s.iter().filter(|&x| *x > 1); // both & and * /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -849,9 +849,9 @@ pub trait Iterator { /// or both: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s + /// let mut iter = s.iter().filter(|&&x| x > 1); // two &s /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -945,11 +945,11 @@ pub trait Iterator { /// ``` /// let a = ['a', 'b', 'c']; /// - /// let mut iter = a.iter().enumerate(); + /// let mut iter = a.into_iter().enumerate(); /// - /// assert_eq!(iter.next(), Some((0, &'a'))); - /// assert_eq!(iter.next(), Some((1, &'b'))); - /// assert_eq!(iter.next(), Some((2, &'c'))); + /// assert_eq!(iter.next(), Some((0, 'a'))); + /// assert_eq!(iter.next(), Some((1, 'b'))); + /// assert_eq!(iter.next(), Some((2, 'c'))); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -980,19 +980,19 @@ pub trait Iterator { /// ``` /// let xs = [1, 2, 3]; /// - /// let mut iter = xs.iter().peekable(); + /// let mut iter = xs.into_iter().peekable(); /// /// // peek() lets us see into the future - /// assert_eq!(iter.peek(), Some(&&1)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.peek(), Some(&1)); + /// assert_eq!(iter.next(), Some(1)); /// - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(2)); /// /// // we can peek() multiple times, the iterator won't advance - /// assert_eq!(iter.peek(), Some(&&3)); - /// assert_eq!(iter.peek(), Some(&&3)); + /// assert_eq!(iter.peek(), Some(&3)); + /// assert_eq!(iter.peek(), Some(&3)); /// - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// /// // after the iterator is finished, so is peek() /// assert_eq!(iter.peek(), None); @@ -1005,21 +1005,21 @@ pub trait Iterator { /// ``` /// let xs = [1, 2, 3]; /// - /// let mut iter = xs.iter().peekable(); + /// let mut iter = xs.into_iter().peekable(); /// /// // `peek_mut()` lets us see into the future - /// assert_eq!(iter.peek_mut(), Some(&mut &1)); - /// assert_eq!(iter.peek_mut(), Some(&mut &1)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.peek_mut(), Some(&mut 1)); + /// assert_eq!(iter.peek_mut(), Some(&mut 1)); + /// assert_eq!(iter.next(), Some(1)); /// - /// if let Some(mut p) = iter.peek_mut() { - /// assert_eq!(*p, &2); + /// if let Some(p) = iter.peek_mut() { + /// assert_eq!(*p, 2); /// // put a value into the iterator - /// *p = &1000; + /// *p = 1000; /// } /// /// // The value reappears as the iterator continues - /// assert_eq!(iter.collect::>(), vec![&1000, &3]); + /// assert_eq!(iter.collect::>(), vec![1000, 3]); /// ``` /// [`peek`]: Peekable::peek /// [`peek_mut`]: Peekable::peek_mut @@ -1051,10 +1051,10 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.iter().skip_while(|x| x.is_negative()); + /// let mut iter = a.into_iter().skip_while(|x| x.is_negative()); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(1)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1063,9 +1063,9 @@ pub trait Iterator { /// situation, where the type of the closure argument is a double reference: /// /// ``` - /// let a = [-1, 0, 1]; + /// let s = &[-1, 0, 1]; /// - /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s! + /// let mut iter = s.iter().skip_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -1077,14 +1077,14 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.iter().skip_while(|x| **x < 0); + /// let mut iter = a.into_iter().skip_while(|&x| x < 0); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(1)); /// /// // while this would have been false, since we already got a false, /// // skip_while() isn't used any more - /// assert_eq!(iter.next(), Some(&-2)); + /// assert_eq!(iter.next(), Some(-2)); /// /// assert_eq!(iter.next(), None); /// ``` @@ -1115,9 +1115,9 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.iter().take_while(|x| x.is_negative()); + /// let mut iter = a.into_iter().take_while(|x| x.is_negative()); /// - /// assert_eq!(iter.next(), Some(&-1)); + /// assert_eq!(iter.next(), Some(-1)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1126,9 +1126,9 @@ pub trait Iterator { /// situation, where the type of the closure is a double reference: /// /// ``` - /// let a = [-1, 0, 1]; + /// let s = &[-1, 0, 1]; /// - /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s! + /// let mut iter = s.iter().take_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -1139,12 +1139,12 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.iter().take_while(|x| **x < 0); + /// let mut iter = a.into_iter().take_while(|&x| x < 0); /// - /// assert_eq!(iter.next(), Some(&-1)); + /// assert_eq!(iter.next(), Some(-1)); /// /// // We have more elements that are less than zero, but since we already - /// // got a false, take_while() isn't used any more + /// // got a false, take_while() ignores the remaining elements. /// assert_eq!(iter.next(), None); /// ``` /// @@ -1154,18 +1154,15 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// let result: Vec = iter.by_ref() - /// .take_while(|n| **n != 3) - /// .cloned() - /// .collect(); + /// let result: Vec = iter.by_ref().take_while(|&n| n != 3).collect(); /// - /// assert_eq!(result, &[1, 2]); + /// assert_eq!(result, [1, 2]); /// - /// let result: Vec = iter.cloned().collect(); + /// let result: Vec = iter.collect(); /// - /// assert_eq!(result, &[4]); + /// assert_eq!(result, [4]); /// ``` /// /// The `3` is no longer there, because it was consumed in order to see if @@ -1193,7 +1190,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 4, 0, 1]; /// - /// let mut iter = a.iter().map_while(|x| 16i32.checked_div(*x)); + /// let mut iter = a.into_iter().map_while(|x| 16i32.checked_div(x)); /// /// assert_eq!(iter.next(), Some(-16)); /// assert_eq!(iter.next(), Some(4)); @@ -1208,8 +1205,8 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 4, 0, 1]; /// - /// let mut iter = a.iter() - /// .map(|x| 16i32.checked_div(*x)) + /// let mut iter = a.into_iter() + /// .map(|x| 16i32.checked_div(x)) /// .take_while(|x| x.is_some()) /// .map(|x| x.unwrap()); /// @@ -1223,12 +1220,12 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2, -3, 4, 5, -6]; /// - /// let iter = a.iter().map_while(|x| u32::try_from(*x).ok()); - /// let vec = iter.collect::>(); + /// let iter = a.into_iter().map_while(|x| u32::try_from(x).ok()); + /// let vec: Vec<_> = iter.collect(); /// - /// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3` + /// // We have more elements that could fit in u32 (such as 4, 5), but `map_while` returned `None` for `-3` /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` encountered. - /// assert_eq!(vec, vec![0, 1, 2]); + /// assert_eq!(vec, [0, 1, 2]); /// ``` /// /// Because `map_while()` needs to look at the value in order to see if it @@ -1237,17 +1234,17 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, -3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// let result: Vec = iter.by_ref() - /// .map_while(|n| u32::try_from(*n).ok()) + /// .map_while(|n| u32::try_from(n).ok()) /// .collect(); /// - /// assert_eq!(result, &[1, 2]); + /// assert_eq!(result, [1, 2]); /// - /// let result: Vec = iter.cloned().collect(); + /// let result: Vec = iter.collect(); /// - /// assert_eq!(result, &[4]); + /// assert_eq!(result, [4]); /// ``` /// /// The `-3` is no longer there, because it was consumed in order to see if @@ -1255,7 +1252,7 @@ pub trait Iterator { /// /// Note that unlike [`take_while`] this iterator is **not** fused. /// It is also not specified what this iterator returns after the first [`None`] is returned. - /// If you need fused iterator, use [`fuse`]. + /// If you need a fused iterator, use [`fuse`]. /// /// [`fuse`]: Iterator::fuse #[inline] @@ -1282,9 +1279,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().skip(2); + /// let mut iter = a.into_iter().skip(2); /// - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -1312,10 +1309,10 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().take(2); + /// let mut iter = a.into_iter().take(2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1370,7 +1367,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4]; /// - /// let mut iter = a.iter().scan(1, |state, &x| { + /// let mut iter = a.into_iter().scan(1, |state, x| { /// // each iteration, we'll multiply the state by the element ... /// *state = *state * x; /// @@ -1448,8 +1445,8 @@ pub trait Iterator { /// /// ``` /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]]; - /// let flattened = data.into_iter().flatten().collect::>(); - /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); + /// let flattened: Vec<_> = data.into_iter().flatten().collect(); + /// assert_eq!(flattened, [1, 2, 3, 4, 5, 6]); /// ``` /// /// Mapping and then flattening: @@ -1483,11 +1480,11 @@ pub trait Iterator { /// ``` /// let options = vec![Some(123), Some(321), None, Some(231)]; /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); - /// assert_eq!(flattened_options, vec![123, 321, 231]); + /// assert_eq!(flattened_options, [123, 321, 231]); /// /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); - /// assert_eq!(flattened_results, vec![123, 321, 231]); + /// assert_eq!(flattened_results, [123, 321, 231]); /// ``` /// /// Flattening only removes one level of nesting at a time: @@ -1495,11 +1492,11 @@ pub trait Iterator { /// ``` /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; /// - /// let d2 = d3.iter().flatten().collect::>(); - /// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]); + /// let d2: Vec<_> = d3.into_iter().flatten().collect(); + /// assert_eq!(d2, [[1, 2], [3, 4], [5, 6], [7, 8]]); /// - /// let d1 = d3.iter().flatten().flatten().collect::>(); - /// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]); + /// let d1: Vec<_> = d3.into_iter().flatten().flatten().collect(); + /// assert_eq!(d1, [1, 2, 3, 4, 5, 6, 7, 8]); /// ``` /// /// Here we see that `flatten()` does not perform a "deep" flatten. @@ -1881,7 +1878,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// let doubled: Vec = a.iter() - /// .map(|&x| x * 2) + /// .map(|x| x * 2) /// .collect(); /// /// assert_eq!(vec![2, 4, 6], doubled); @@ -1897,7 +1894,7 @@ pub trait Iterator { /// /// let a = [1, 2, 3]; /// - /// let doubled: VecDeque = a.iter().map(|&x| x * 2).collect(); + /// let doubled: VecDeque = a.iter().map(|x| x * 2).collect(); /// /// assert_eq!(2, doubled[0]); /// assert_eq!(4, doubled[1]); @@ -1930,8 +1927,8 @@ pub trait Iterator { /// ``` /// let chars = ['g', 'd', 'k', 'k', 'n']; /// - /// let hello: String = chars.iter() - /// .map(|&x| x as u8) + /// let hello: String = chars.into_iter() + /// .map(|x| x as u8) /// .map(|x| (x + 1) as char) /// .collect(); /// @@ -1944,14 +1941,14 @@ pub trait Iterator { /// ``` /// let results = [Ok(1), Err("nope"), Ok(3), Err("bad")]; /// - /// let result: Result, &str> = results.iter().cloned().collect(); + /// let result: Result, &str> = results.into_iter().collect(); /// /// // gives us the first error /// assert_eq!(Err("nope"), result); /// /// let results = [Ok(1), Ok(3)]; /// - /// let result: Result, &str> = results.iter().cloned().collect(); + /// let result: Result, &str> = results.into_iter().collect(); /// /// // gives us the list of answers /// assert_eq!(Ok(vec![1, 3]), result); @@ -2073,8 +2070,8 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// let mut vec: Vec:: = vec![0, 1]; /// - /// a.iter().map(|&x| x * 2).collect_into(&mut vec); - /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// a.iter().map(|x| x * 2).collect_into(&mut vec); + /// a.iter().map(|x| x * 10).collect_into(&mut vec); /// /// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]); /// ``` @@ -2087,8 +2084,8 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// let mut vec: Vec:: = Vec::with_capacity(6); /// - /// a.iter().map(|&x| x * 2).collect_into(&mut vec); - /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// a.iter().map(|x| x * 2).collect_into(&mut vec); + /// a.iter().map(|x| x * 10).collect_into(&mut vec); /// /// assert_eq!(6, vec.capacity()); /// assert_eq!(vec, vec![2, 4, 6, 10, 20, 30]); @@ -2142,8 +2139,8 @@ pub trait Iterator { /// .into_iter() /// .partition(|n| n % 2 == 0); /// - /// assert_eq!(even, vec![2]); - /// assert_eq!(odd, vec![1, 3]); + /// assert_eq!(even, [2]); + /// assert_eq!(odd, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn partition(self, f: F) -> (B, B) @@ -2201,11 +2198,11 @@ pub trait Iterator { /// let mut a = [1, 2, 3, 4, 5, 6, 7]; /// /// // Partition in-place between evens and odds - /// let i = a.iter_mut().partition_in_place(|&n| n % 2 == 0); + /// let i = a.iter_mut().partition_in_place(|n| n % 2 == 0); /// /// assert_eq!(i, 3); - /// assert!(a[..i].iter().all(|&n| n % 2 == 0)); // evens - /// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds + /// assert!(a[..i].iter().all(|n| n % 2 == 0)); // evens + /// assert!(a[i..].iter().all(|n| n % 2 == 1)); // odds /// ``` #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize @@ -2312,7 +2309,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array - /// let sum = a.iter().try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = a.into_iter().try_fold(0i8, |acc, x| acc.checked_add(x)); /// /// assert_eq!(sum, Some(6)); /// ``` @@ -2321,16 +2318,16 @@ pub trait Iterator { /// /// ``` /// let a = [10, 20, 30, 100, 40, 50]; - /// let mut it = a.iter(); + /// let mut iter = a.into_iter(); /// /// // This sum overflows when adding the 100 element - /// let sum = it.try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = iter.try_fold(0i8, |acc, x| acc.checked_add(x)); /// assert_eq!(sum, None); /// /// // Because it short-circuited, the remaining elements are still /// // available through the iterator. - /// assert_eq!(it.len(), 2); - /// assert_eq!(it.next(), Some(&40)); + /// assert_eq!(iter.len(), 2); + /// assert_eq!(iter.next(), Some(40)); /// ``` /// /// While you cannot `break` from a closure, the [`ControlFlow`] type allows @@ -2683,9 +2680,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert!(a.iter().all(|&x| x > 0)); + /// assert!(a.into_iter().all(|x| x > 0)); /// - /// assert!(!a.iter().all(|&x| x > 2)); + /// assert!(!a.into_iter().all(|x| x > 2)); /// ``` /// /// Stopping at the first `false`: @@ -2693,12 +2690,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert!(!iter.all(|&x| x != 2)); + /// assert!(!iter.all(|x| x != 2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2736,9 +2733,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert!(a.iter().any(|&x| x > 0)); + /// assert!(a.into_iter().any(|x| x > 0)); /// - /// assert!(!a.iter().any(|&x| x > 5)); + /// assert!(!a.into_iter().any(|x| x > 5)); /// ``` /// /// Stopping at the first `true`: @@ -2746,12 +2743,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert!(iter.any(|&x| x != 2)); + /// assert!(iter.any(|x| x != 2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(2)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2797,9 +2794,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().find(|&&x| x == 2), Some(&2)); - /// - /// assert_eq!(a.iter().find(|&&x| x == 5), None); + /// assert_eq!(a.into_iter().find(|&x| x == 2), Some(2)); + /// assert_eq!(a.into_iter().find(|&x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -2807,12 +2803,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.find(|&&x| x == 2), Some(&2)); + /// assert_eq!(iter.find(|&x| x == 2), Some(2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// ``` /// /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. @@ -2880,13 +2876,13 @@ pub trait Iterator { /// let a = ["1", "2", "lol", "NaN", "5"]; /// /// let is_my_num = |s: &str, search: i32| -> Result { - /// Ok(s.parse::()? == search) + /// Ok(s.parse::()? == search) /// }; /// - /// let result = a.iter().try_find(|&&s| is_my_num(s, 2)); - /// assert_eq!(result, Ok(Some(&"2"))); + /// let result = a.into_iter().try_find(|&s| is_my_num(s, 2)); + /// assert_eq!(result, Ok(Some("2"))); /// - /// let result = a.iter().try_find(|&&s| is_my_num(s, 5)); + /// let result = a.into_iter().try_find(|&s| is_my_num(s, 5)); /// assert!(result.is_err()); /// ``` /// @@ -2898,11 +2894,11 @@ pub trait Iterator { /// use std::num::NonZero; /// /// let a = [3, 5, 7, 4, 9, 0, 11u32]; - /// let result = a.iter().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); - /// assert_eq!(result, Some(Some(&4))); - /// let result = a.iter().take(3).try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// let result = a.into_iter().try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// assert_eq!(result, Some(Some(4))); + /// let result = a.into_iter().take(3).try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); /// assert_eq!(result, Some(None)); - /// let result = a.iter().rev().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// let result = a.into_iter().rev().try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); /// assert_eq!(result, None); /// ``` #[inline] @@ -2967,9 +2963,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().position(|&x| x == 2), Some(1)); + /// assert_eq!(a.into_iter().position(|x| x == 2), Some(1)); /// - /// assert_eq!(a.iter().position(|&x| x == 5), None); + /// assert_eq!(a.into_iter().position(|x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -2977,15 +2973,15 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); + /// assert_eq!(iter.position(|x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// /// // The returned index depends on iterator state - /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// assert_eq!(iter.position(|x| x == 4), Some(0)); /// /// ``` #[inline] @@ -3035,9 +3031,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().rposition(|&x| x == 3), Some(2)); + /// assert_eq!(a.into_iter().rposition(|x| x == 3), Some(2)); /// - /// assert_eq!(a.iter().rposition(|&x| x == 5), None); + /// assert_eq!(a.into_iter().rposition(|x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -3045,13 +3041,13 @@ pub trait Iterator { /// ``` /// let a = [-1, 2, 3, 4]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.rposition(|&x| x >= 2), Some(3)); + /// assert_eq!(iter.rposition(|x| x >= 2), Some(3)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&-1)); - /// assert_eq!(iter.next_back(), Some(&3)); + /// assert_eq!(iter.next(), Some(-1)); + /// assert_eq!(iter.next_back(), Some(3)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3097,10 +3093,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// let b: Vec = Vec::new(); + /// let b: [u32; 0] = []; /// - /// assert_eq!(a.iter().max(), Some(&3)); - /// assert_eq!(b.iter().max(), None); + /// assert_eq!(a.into_iter().max(), Some(3)); + /// assert_eq!(b.into_iter().max(), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3133,10 +3129,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// let b: Vec = Vec::new(); + /// let b: [u32; 0] = []; /// - /// assert_eq!(a.iter().min(), Some(&1)); - /// assert_eq!(b.iter().min(), None); + /// assert_eq!(a.into_iter().min(), Some(1)); + /// assert_eq!(b.into_iter().min(), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3158,7 +3154,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().max_by_key(|x| x.abs()).unwrap(), -10); + /// assert_eq!(a.into_iter().max_by_key(|x| x.abs()).unwrap(), -10); /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] @@ -3191,7 +3187,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); + /// assert_eq!(a.into_iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] @@ -3218,7 +3214,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().min_by_key(|x| x.abs()).unwrap(), 0); + /// assert_eq!(a.into_iter().min_by_key(|x| x.abs()).unwrap(), 0); /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] @@ -3251,7 +3247,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); + /// assert_eq!(a.into_iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] @@ -3281,11 +3277,11 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().rev(); + /// let mut iter = a.into_iter().rev(); /// - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(1)); /// /// assert_eq!(iter.next(), None); /// ``` @@ -3314,7 +3310,7 @@ pub trait Iterator { /// ``` /// let a = [(1, 2), (3, 4), (5, 6)]; /// - /// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip(); + /// let (left, right): (Vec<_>, Vec<_>) = a.into_iter().unzip(); /// /// assert_eq!(left, [1, 3, 5]); /// assert_eq!(right, [2, 4, 6]); @@ -3322,7 +3318,7 @@ pub trait Iterator { /// // you can also unzip multiple nested tuples at once /// let a = [(1, (2, 3)), (4, (5, 6))]; /// - /// let (x, (y, z)): (Vec<_>, (Vec<_>, Vec<_>)) = a.iter().cloned().unzip(); + /// let (x, (y, z)): (Vec<_>, (Vec<_>, Vec<_>)) = a.into_iter().unzip(); /// assert_eq!(x, [1, 4]); /// assert_eq!(y, [2, 5]); /// assert_eq!(z, [3, 6]); @@ -3354,8 +3350,8 @@ pub trait Iterator { /// // copied is the same as .map(|&x| x) /// let v_map: Vec<_> = a.iter().map(|&x| x).collect(); /// - /// assert_eq!(v_copied, vec![1, 2, 3]); - /// assert_eq!(v_map, vec![1, 2, 3]); + /// assert_eq!(v_copied, [1, 2, 3]); + /// assert_eq!(v_map, [1, 2, 3]); /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "iter_copied")] @@ -3390,8 +3386,8 @@ pub trait Iterator { /// // cloned is the same as .map(|&x| x), for integers /// let v_map: Vec<_> = a.iter().map(|&x| x).collect(); /// - /// assert_eq!(v_cloned, vec![1, 2, 3]); - /// assert_eq!(v_map, vec![1, 2, 3]); + /// assert_eq!(v_cloned, [1, 2, 3]); + /// assert_eq!(v_map, [1, 2, 3]); /// ``` /// /// To get the best performance, try to clone late: @@ -3427,15 +3423,14 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut it = a.iter().cycle(); + /// let mut iter = a.into_iter().cycle(); /// - /// assert_eq!(it.next(), Some(&1)); - /// assert_eq!(it.next(), Some(&2)); - /// assert_eq!(it.next(), Some(&3)); - /// assert_eq!(it.next(), Some(&1)); - /// assert_eq!(it.next(), Some(&2)); - /// assert_eq!(it.next(), Some(&3)); - /// assert_eq!(it.next(), Some(&1)); + /// loop { + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// # break; + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -3588,9 +3583,9 @@ pub trait Iterator { /// let xs = [1, 2, 3, 4]; /// let ys = [1, 4, 9, 16]; /// - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less); - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal); - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| x.cmp(&y)), Ordering::Less); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| (x * x).cmp(&y)), Ordering::Equal); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] fn cmp_by(self, other: I, cmp: F) -> Ordering @@ -3672,15 +3667,15 @@ pub trait Iterator { /// let ys = [1.0, 4.0, 9.0, 16.0]; /// /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| x.partial_cmp(&y)), /// Some(Ordering::Less) /// ); /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| (x * x).partial_cmp(&y)), /// Some(Ordering::Equal) /// ); /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| (2.0 * x).partial_cmp(&y)), /// Some(Ordering::Greater) /// ); /// ``` @@ -3738,7 +3733,7 @@ pub trait Iterator { /// let xs = [1, 2, 3, 4]; /// let ys = [1, 4, 9, 16]; /// - /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); + /// assert!(xs.iter().eq_by(ys, |x, y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] fn eq_by(self, other: I, eq: F) -> bool From 431f02d5312544d222a63d40586527ec704f2d13 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 3 May 2025 03:40:23 +0000 Subject: [PATCH 279/302] support duplicates in the opaque_types_storage --- Cargo.lock | 1 - compiler/rustc_hir_typeck/src/_match.rs | 3 +- .../src/infer/canonical/query_response.rs | 26 ++----- compiler/rustc_infer/src/infer/mod.rs | 25 ++---- .../rustc_infer/src/infer/opaque_types/mod.rs | 2 - .../src/infer/opaque_types/table.rs | 76 ++++++++++++++++--- .../src/infer/snapshot/undo_log.rs | 2 + .../rustc_next_trait_solver/src/delegate.rs | 11 ++- .../src/solve/eval_ctxt/canonical.rs | 44 +++++++---- .../src/solve/eval_ctxt/mod.rs | 36 ++++++--- compiler/rustc_trait_selection/Cargo.toml | 1 - .../src/solve/delegate.rs | 37 +++++++-- .../opaques/duplicate-opaque-type-entries.rs | 25 ++++++ 13 files changed, 207 insertions(+), 82 deletions(-) create mode 100644 tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs diff --git a/Cargo.lock b/Cargo.lock index 98b90a47e398..4bd12ee6ae30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4516,7 +4516,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_transmute", - "rustc_type_ir", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 2e7831f16aee..61dd8c573073 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -603,7 +603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone. ty::Infer(ty::TyVar(_)) => self .inner - .borrow() + .borrow_mut() + .opaque_types() .iter_opaque_types() .find(|(_, v)| v.ty == expected_ty) .map(|(k, _)| (k.def_id, k.args))?, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5220071c5005..1ae864c454f2 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -132,7 +132,13 @@ impl<'tcx> InferCtxt<'tcx> { let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; - let opaque_types = self.take_opaque_types_for_query_response(); + let opaque_types = self + .inner + .borrow_mut() + .opaque_type_storage + .take_opaque_types() + .map(|(k, v)| (k, v.ty)) + .collect(); Ok(QueryResponse { var_values: inference_vars, @@ -143,24 +149,6 @@ impl<'tcx> InferCtxt<'tcx> { }) } - /// Used by the new solver as that one takes the opaque types at the end of a probe - /// to deal with multiple candidates without having to recompute them. - pub fn clone_opaque_types_for_query_response( - &self, - ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.inner - .borrow() - .opaque_type_storage - .opaque_types - .iter() - .map(|(k, v)| (*k, v.ty)) - .collect() - } - - fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect() - } - /// Given the (canonicalized) result to a canonical query, /// instantiates the result so it can be used, plugging in the /// values from the canonical query. (Note that the result may diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d25542dadd59..070d285b5a63 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -31,9 +31,9 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, - GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Term, TermKind, - Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, - TypeVisitableExt, TypingEnv, TypingMode, fold_regions, + GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueHiddenType, OpaqueTypeKey, + PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, }; use rustc_span::{Span, Symbol}; use snapshot::undo_log::InferCtxtUndoLogs; @@ -198,7 +198,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { + pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { self.opaque_type_storage.with_log(&mut self.undo_log) } @@ -224,15 +224,6 @@ impl<'tcx> InferCtxtInner<'tcx> { .expect("region constraints already solved") .with_log(&mut self.undo_log) } - - // Iterates through the opaque type definitions without taking them; this holds the - // `InferCtxtInner` lock, so make sure to not do anything with `InferCtxt` side-effects - // while looping through this. - pub fn iter_opaque_types( - &self, - ) -> impl Iterator, ty::OpaqueHiddenType<'tcx>)> { - self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v)) - } } pub struct InferCtxt<'tcx> { @@ -954,13 +945,13 @@ impl<'tcx> InferCtxt<'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { - std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) + pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { + self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() } #[instrument(level = "debug", skip(self), ret)] - pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { - self.inner.borrow().opaque_type_storage.opaque_types.clone() + pub fn clone_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { + self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect() } #[inline(always)] diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index ce5d2e6e17a9..df7144c31da5 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -1,5 +1,4 @@ use hir::def_id::{DefId, LocalDefId}; -use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::traits::ObligationCause; @@ -19,7 +18,6 @@ use crate::traits::{self, Obligation, PredicateObligations}; mod table; -pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueHiddenType<'tcx>>; pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index ba6cc0d783dd..3c5bf9d722b9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,18 +1,17 @@ +use std::ops::Deref; + +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::bug; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; use tracing::instrument; -use super::OpaqueTypeMap; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; #[derive(Default, Debug, Clone)] -pub(crate) struct OpaqueTypeStorage<'tcx> { - /// Opaque types found in explicit return types and their - /// associated fresh inference variable. Writeback resolves these - /// variables to get the concrete type, which can be used to - /// 'de-opaque' OpaqueHiddenType, after typeck is done with all functions. - pub opaque_types: OpaqueTypeMap<'tcx>, +pub struct OpaqueTypeStorage<'tcx> { + opaque_types: FxIndexMap, OpaqueHiddenType<'tcx>>, + duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>, } impl<'tcx> OpaqueTypeStorage<'tcx> { @@ -33,6 +32,52 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } + pub(crate) fn pop_duplicate_entry(&mut self) { + let entry = self.duplicate_entries.pop(); + assert!(entry.is_some()); + } + + pub(crate) fn is_empty(&self) -> bool { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.is_empty() && duplicate_entries.is_empty() + } + + pub(crate) fn take_opaque_types( + &mut self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) + } + + /// Only returns the opaque types from the lookup table. These are used + /// when normalizing opaque types and have a unique key. + /// + /// Outside of canonicalization one should generally use `iter_opaque_types` + /// to also consider duplicate entries. + pub fn iter_lookup_table( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + self.opaque_types.iter().map(|(k, v)| (*k, *v)) + } + + /// Only returns the opaque types which are stored in `duplicate_entries`. + /// + /// These have to considered when checking all opaque type uses but are e.g. + /// irrelevant for canonical inputs as nested queries never meaningfully + /// accesses them. + pub fn iter_duplicate_entries( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + self.duplicate_entries.iter().copied() + } + + pub fn iter_opaque_types( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) + } + #[inline] pub(crate) fn with_log<'a>( &'a mut self, @@ -44,21 +89,27 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { fn drop(&mut self) { - if !self.opaque_types.is_empty() { + if !self.is_empty() { ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types))); } } } -pub(crate) struct OpaqueTypeTable<'a, 'tcx> { +pub struct OpaqueTypeTable<'a, 'tcx> { storage: &'a mut OpaqueTypeStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } +impl<'tcx> Deref for OpaqueTypeTable<'_, 'tcx> { + type Target = OpaqueTypeStorage<'tcx>; + fn deref(&self) -> &Self::Target { + self.storage + } +} impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { #[instrument(skip(self), level = "debug")] - pub(crate) fn register( + pub fn register( &mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, @@ -72,4 +123,9 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { self.undo_log.push(UndoLog::OpaqueTypes(key, None)); None } + + pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>) { + self.storage.duplicate_entries.push((key, hidden_type)); + self.undo_log.push(UndoLog::DuplicateOpaqueType); + } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index ba7d8f588e68..b7412d3d6a6d 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> { /// Records the "undo" data for a single operation that affects some form of inference variable. #[derive(Clone)] pub(crate) enum UndoLog<'tcx> { + DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), TypeVariables(sv::UndoLog>>), ConstUnificationTable(sv::UndoLog>>), @@ -58,6 +59,7 @@ impl_from! { impl<'tcx> Rollback> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { + UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 25493970a0ce..9e8fbd66b708 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -39,7 +39,10 @@ pub trait SolverDelegate: Deref + Sized { term: ::Term, ) -> Option::Predicate>>>; - fn clone_opaque_types_for_query_response( + fn clone_opaque_types_lookup_table( + &self, + ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + fn clone_duplicate_opaque_types( &self, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; @@ -68,6 +71,12 @@ pub trait SolverDelegate: Deref + Sized { hidden_ty: ::Ty, span: ::Span, ) -> Option<::Ty>; + fn add_duplicate_opaque_type( + &self, + opaque_type_key: ty::OpaqueTypeKey, + hidden_ty: ::Ty, + span: ::Span, + ); fn add_item_bounds_for_hidden_type( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index dded84f67686..65b10e4f23f0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -56,7 +56,10 @@ where &self, goal: Goal, ) -> (Vec, CanonicalInput) { - let opaque_types = self.delegate.clone_opaque_types_for_query_response(); + // We only care about one entry per `OpaqueTypeKey` here, + // so we only canonicalize the lookup table and ignore + // duplicate entries. + let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); @@ -241,19 +244,21 @@ where Default::default() }; - ExternalConstraintsData { - region_constraints, - opaque_types: self - .delegate - .clone_opaque_types_for_query_response() - .into_iter() - // Only return *newly defined* opaque types. - .filter(|(a, _)| { - self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) - }) - .collect(), - normalization_nested_goals, - } + // We only return *newly defined* opaque types from canonical queries. + // + // Constraints for any existing opaque types are already tracked by changes + // to the `var_values`. + let opaque_types = self + .delegate + .clone_opaque_types_lookup_table() + .into_iter() + .filter(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }) + .chain(self.delegate.clone_duplicate_opaque_types()) + .collect(); + + ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } /// After calling a canonical query, we apply the constraints returned @@ -432,7 +437,16 @@ where fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)]) { for &(key, ty) in opaque_types { let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span); - assert_eq!(prev, None); + // We eagerly resolve inference variables when computing the query response. + // This can cause previously distinct opaque type keys to now be structurally equal. + // + // To handle this, we store any duplicate entries in a separate list to check them + // at the end of typeck/borrowck. We could alternatively eagerly equate the hidden + // types here. However, doing so is difficult as it may result in nested goals and + // any errors may make it harder to track the control flow for diagnostics. + if let Some(prev) = prev { + self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span); + } } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6dd554299a69..c13e73080550 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -14,7 +14,7 @@ use rustc_type_ir::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; -use tracing::{instrument, trace}; +use tracing::{debug, instrument, trace}; use super::has_only_region_constraints; use crate::coherence; @@ -361,7 +361,20 @@ where for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span); - assert_eq!(prev, None); + // It may be possible that two entries in the opaque type storage end up + // with the same key after resolving contained inference variables. + // + // We could put them in the duplicate list but don't have to. The opaques we + // encounter here are already tracked in the caller, so there's no need to + // also store them here. We'd take them out when computing the query response + // and then discard them, as they're already present in the input. + // + // Ideally we'd drop duplicate opaque type definitions when computing + // the canonical input. This is more annoying to implement and may cause a + // perf regression, so we do it inside of the query for now. + if let Some(prev) = prev { + debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`"); + } } if !ecx.nested_goals.is_empty() { @@ -1065,14 +1078,17 @@ where &mut self, key: ty::OpaqueTypeKey, ) -> Option<(ty::OpaqueTypeKey, I::Ty)> { - let mut matching = - self.delegate.clone_opaque_types_for_query_response().into_iter().filter( - |(candidate_key, _)| { - candidate_key.def_id == key.def_id - && DeepRejectCtxt::relate_rigid_rigid(self.cx()) - .args_may_unify(candidate_key.args, key.args) - }, - ); + // We shouldn't have any duplicate entries when using + // this function during `TypingMode::Analysis`. + let duplicate_entries = self.delegate.clone_duplicate_opaque_types(); + assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}"); + let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter( + |(candidate_key, _)| { + candidate_key.def_id == key.def_id + && DeepRejectCtxt::relate_rigid_rigid(self.cx()) + .args_may_unify(candidate_key.args, key.args) + }, + ); let first = matching.next(); let second = matching.next(); assert_eq!(second, None); diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index e6de2a3978d1..1071105522d1 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -20,7 +20,6 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2" tracing = "0.1" diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 908c058aabec..87b8db59a78e 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -104,8 +104,23 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.0.clone_opaque_types_for_query_response() + fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0 + .inner + .borrow_mut() + .opaque_types() + .iter_lookup_table() + .map(|(k, h)| (k, h.ty)) + .collect() + } + fn clone_duplicate_opaque_types(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0 + .inner + .borrow_mut() + .opaque_types() + .iter_duplicate_entries() + .map(|(k, h)| (k, h.ty)) + .collect() } fn make_deduplicated_outlives_constraints( @@ -156,14 +171,26 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn register_hidden_type_in_storage( &self, opaque_type_key: ty::OpaqueTypeKey<'tcx>, - hidden_ty: ::Ty, - span: ::Span, - ) -> Option<::Ty> { + hidden_ty: Ty<'tcx>, + span: Span, + ) -> Option> { self.0.register_hidden_type_in_storage( opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty }, ) } + fn add_duplicate_opaque_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, + hidden_ty: Ty<'tcx>, + span: Span, + ) { + self.0 + .inner + .borrow_mut() + .opaque_types() + .add_duplicate(opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty }) + } fn add_item_bounds_for_hidden_type( &self, diff --git a/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs b/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs new file mode 100644 index 000000000000..e0668ac3d39f --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +#![crate_type = "lib"] +trait Eq {} +impl Eq for T {} +trait ConstrainAndEq {} +impl ConstrainAndEq for U +where + T: FnOnce() -> u32, + U: FnOnce() -> u32, + T: Eq, +{} + +fn constrain_and_eq, U>(_: T, _: U) {} +fn foo<'a>() -> impl Sized + use<'a> { + // This proves `foo<'a>: FnOnce() -> u32` and `foo<'1>: FnOnce() -> u32`, + // We constrain both `opaque<'a>` and `opaque<'1>` to `u32`, resulting in + // two distinct opaque type uses. Proving `foo<'a>: Eq>` then + // equates the two regions at which point the two opaque type keys are now + // equal. This previously caused an ICE. + constrain_and_eq(foo::<'a>, foo::<'_>); + 1u32 +} From 14782ad6874b768ce208f76a6998e2175ffce755 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 May 2025 18:17:48 +0200 Subject: [PATCH 280/302] Add new `test_main_with_exit_callback` public function in `libtest` to allow a callback to be called before exiting --- library/test/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index acaf026c679b..7f56d1e36269 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -98,6 +98,15 @@ const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS" // The default console test runner. It accepts the command line // arguments and a vector of test_descs. pub fn test_main(args: &[String], tests: Vec, options: Option) { + test_main_with_exit_callback(args, tests, options, || {}) +} + +pub fn test_main_with_exit_callback( + args: &[String], + tests: Vec, + options: Option, + exit_callback: F, +) { let mut opts = match cli::parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { @@ -151,6 +160,7 @@ pub fn test_main(args: &[String], tests: Vec, options: Option {} Ok(false) => process::exit(ERROR_EXIT_CODE), From a84a946a3d6fc60f6485cf1d8a47845d3a416117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 6 May 2025 16:10:58 +0200 Subject: [PATCH 281/302] Handle PR not found in post-merge workflow --- .github/workflows/post-merge.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 94553608a2f4..ca088ba31fdf 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -25,12 +25,19 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | + # Give GitHub some time to propagate the information that the PR was merged + sleep 60 + # Get closest bors merge commit PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + if [ -z "${HEAD_PR}" ]; then + echo "PR for commit SHA ${{ github.sha }} not found, exiting" + exit 1 + fi echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" cd src/ci/citool From cdd104922df2cc62a0e82ba865d4cdc6a217090e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 6 May 2025 18:36:14 +0200 Subject: [PATCH 282/302] Use the portable `AtomicU64` --- compiler/rustc_query_system/src/dep_graph/serialized.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index b01f65a5e454..f1b609a3ca90 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -43,14 +43,14 @@ use std::cell::RefCell; use std::cmp::max; use std::marker::PhantomData; use std::sync::Arc; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::atomic::Ordering; use std::{iter, mem, u64}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::outline; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::{Lock, WorkerLocal, broadcast}; +use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal, broadcast}; use rustc_data_structures::unhash::UnhashMap; use rustc_index::IndexVec; use rustc_serialize::opaque::mem_encoder::MemEncoder; From 173cdafea679a9ae96b67bc74d2f623b162e1480 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 May 2025 18:18:39 +0200 Subject: [PATCH 283/302] Ensure that temporary doctest folder is correctly removed even if doctests failed --- src/librustdoc/doctest.rs | 23 ++++++++++++++++++++--- src/librustdoc/doctest/markdown.rs | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 829a9ca6e7dd..0cdf2f92a891 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -262,11 +262,21 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions Ok(None) => return, Err(error) => { eprintln!("{error}"); + // Since some files in the temporary folder are still owned and alive, we need + // to manually remove the folder. + let _ = std::fs::remove_dir_all(temp_dir.path()); std::process::exit(1); } }; - run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests); + run_tests( + opts, + &rustdoc_options, + &unused_extern_reports, + standalone_tests, + mergeable_tests, + Some(temp_dir), + ); let compiling_test_count = compiling_test_count.load(Ordering::SeqCst); @@ -316,6 +326,8 @@ pub(crate) fn run_tests( unused_extern_reports: &Arc>>, mut standalone_tests: Vec, mergeable_tests: FxIndexMap>, + // We pass this argument so we can drop it manually before using `exit`. + mut temp_dir: Option, ) { let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1); test_args.insert(0, "rustdoctest".to_string()); @@ -382,9 +394,14 @@ pub(crate) fn run_tests( // `running 0 tests...`. if ran_edition_tests == 0 || !standalone_tests.is_empty() { standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice())); - test::test_main(&test_args, standalone_tests, None); + test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir.take()); + }); } if nb_errors != 0 { + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir); // libtest::ERROR_EXIT_CODE is not public but it's the same value. std::process::exit(101); } @@ -450,7 +467,7 @@ enum TestFailure { } enum DirState { - Temp(tempfile::TempDir), + Temp(TempDir), Perm(PathBuf), } diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index 497a8d7c4a75..b3a3ce08a05a 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -116,6 +116,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { &Arc::new(Mutex::new(Vec::new())), standalone_tests, mergeable_tests, + None, ); Ok(()) } From e648e5b7102422fe3c8a2393df04ec2e707673b3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 May 2025 10:33:04 -0700 Subject: [PATCH 284/302] rustdoc: remove unportable markdown lint and old parser Follow up https://github.com/rust-lang/rust/pull/127127 --- Cargo.lock | 16 +- src/librustdoc/Cargo.toml | 1 - src/librustdoc/lint.rs | 10 +- src/librustdoc/passes/lint.rs | 4 - .../passes/lint/unportable_markdown.rs | 145 ------------------ tests/rustdoc-ui/unportable-markdown.rs | 62 -------- tests/rustdoc-ui/unportable-markdown.stderr | 23 --- 7 files changed, 3 insertions(+), 258 deletions(-) delete mode 100644 src/librustdoc/passes/lint/unportable_markdown.rs delete mode 100644 tests/rustdoc-ui/unportable-markdown.rs delete mode 100644 tests/rustdoc-ui/unportable-markdown.stderr diff --git a/Cargo.lock b/Cargo.lock index 98b90a47e398..39519681369f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,7 +558,7 @@ dependencies = [ "if_chain", "itertools", "parking_lot", - "pulldown-cmark 0.11.3", + "pulldown-cmark", "quote", "regex", "rustc_tools_util 0.4.2", @@ -2849,17 +2849,6 @@ dependencies = [ "cc", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - [[package]] name = "pulldown-cmark" version = "0.11.3" @@ -4337,7 +4326,7 @@ version = "0.0.0" dependencies = [ "bitflags", "itertools", - "pulldown-cmark 0.11.3", + "pulldown-cmark", "rustc_arena", "rustc_ast", "rustc_ast_pretty", @@ -4622,7 +4611,6 @@ dependencies = [ "indexmap", "itertools", "minifier", - "pulldown-cmark 0.9.6", "pulldown-cmark-escape", "regex", "rustdoc-json-types", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 27ae0553c60d..dbfdd8ebd167 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,7 +14,6 @@ base64 = "0.21.7" itertools = "0.12" indexmap = "2" minifier = { version = "0.3.5", default-features = false } -pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index dcc27cd62e38..b09ea0568859 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -196,14 +196,6 @@ declare_rustdoc_lint! { "detects redundant explicit links in doc comments" } -declare_rustdoc_lint! { - /// This compatibility lint checks for Markdown syntax that works in the old engine but not - /// the new one. - UNPORTABLE_MARKDOWN, - Warn, - "detects markdown that is interpreted differently in different parser" -} - pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -217,7 +209,6 @@ pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { MISSING_CRATE_LEVEL_DOCS, UNESCAPED_BACKTICKS, REDUNDANT_EXPLICIT_LINKS, - UNPORTABLE_MARKDOWN, ] }); @@ -241,4 +232,5 @@ pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) { .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls"); lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls"); + lint_store.register_removed("rustdoc::unportable_markdown", "old parser removed"); } diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index 1ecb53e61ac3..7740d14148bf 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -6,7 +6,6 @@ mod check_code_block_syntax; mod html_tags; mod redundant_explicit_links; mod unescaped_backticks; -mod unportable_markdown; use super::Pass; use crate::clean::*; @@ -49,9 +48,6 @@ impl DocVisitor<'_> for Linter<'_, '_> { } if may_have_block_comment_or_html { html_tags::visit_item(self.cx, item, hir_id, &dox); - unportable_markdown::visit_item(self.cx, item, hir_id, &dox); - } else if may_have_link { - unportable_markdown::visit_item(self.cx, item, hir_id, &dox); } } diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs deleted file mode 100644 index 95646413a2d2..000000000000 --- a/src/librustdoc/passes/lint/unportable_markdown.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Detects specific markdown syntax that's different between pulldown-cmark -//! 0.9 and 0.11. -//! -//! This is a mitigation for old parser bugs that affected some -//! real crates' docs. The old parser claimed to comply with CommonMark, -//! but it did not. These warnings will eventually be removed, -//! though some of them may become Clippy lints. -//! -//! -//! -//! - -use std::collections::{BTreeMap, BTreeSet}; - -use rustc_hir::HirId; -use rustc_lint_defs::Applicability; -use rustc_resolve::rustdoc::source_span_for_markdown_range; -use {pulldown_cmark as cmarkn, pulldown_cmark_old as cmarko}; - -use crate::clean::Item; -use crate::core::DocContext; - -pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) { - let tcx = cx.tcx; - - // P1: unintended strikethrough was fixed by requiring single-tildes to flank - // the same way underscores do, so nothing is done here - - // P2: block quotes without following space parsed wrong - // - // This is the set of starting points for block quotes with no space after - // the `>`. It is populated by the new parser, and if the old parser fails to - // clear it out, it'll produce a warning. - let mut spaceless_block_quotes = BTreeSet::new(); - - // P3: missing footnote references - // - // This is populated by listening for FootnoteReference from - // the new parser and old parser. - let mut missing_footnote_references = BTreeMap::new(); - let mut found_footnote_references = BTreeSet::new(); - - // populate problem cases from new parser - { - pub fn main_body_opts_new() -> cmarkn::Options { - cmarkn::Options::ENABLE_TABLES - | cmarkn::Options::ENABLE_FOOTNOTES - | cmarkn::Options::ENABLE_STRIKETHROUGH - | cmarkn::Options::ENABLE_TASKLISTS - | cmarkn::Options::ENABLE_SMART_PUNCTUATION - } - let parser_new = cmarkn::Parser::new_ext(dox, main_body_opts_new()).into_offset_iter(); - for (event, span) in parser_new { - if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event { - if !dox[span.clone()].starts_with("> ") { - spaceless_block_quotes.insert(span.start); - } - } - if let cmarkn::Event::FootnoteReference(_) = event { - found_footnote_references.insert(span.start + 1); - } - } - } - - // remove cases where they don't actually differ - { - pub fn main_body_opts_old() -> cmarko::Options { - cmarko::Options::ENABLE_TABLES - | cmarko::Options::ENABLE_FOOTNOTES - | cmarko::Options::ENABLE_STRIKETHROUGH - | cmarko::Options::ENABLE_TASKLISTS - | cmarko::Options::ENABLE_SMART_PUNCTUATION - } - let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter(); - for (event, span) in parser_old { - if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event - && !dox[span.clone()].starts_with("> ") - { - spaceless_block_quotes.remove(&span.start); - } - if let cmarko::Event::FootnoteReference(_) = event - && !found_footnote_references.contains(&(span.start + 1)) - { - missing_footnote_references.insert(span.start + 1, span); - } - } - } - - for start in spaceless_block_quotes { - let (span, precise) = - source_span_for_markdown_range(tcx, dox, &(start..start + 1), &item.attrs.doc_strings) - .map(|span| (span, true)) - .unwrap_or_else(|| (item.attr_span(tcx), false)); - - tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| { - lint.primary_message("unportable markdown"); - lint.help("confusing block quote with no space after the `>` marker".to_string()); - if precise { - lint.span_suggestion( - span.shrink_to_hi(), - "if the quote is intended, add a space", - " ", - Applicability::MaybeIncorrect, - ); - lint.span_suggestion( - span.shrink_to_lo(), - "if it should not be a quote, escape it", - "\\", - Applicability::MaybeIncorrect, - ); - } - }); - } - for (_caret, span) in missing_footnote_references { - let (ref_span, precise) = - source_span_for_markdown_range(tcx, dox, &span, &item.attrs.doc_strings) - .map(|span| (span, true)) - .unwrap_or_else(|| (item.attr_span(tcx), false)); - - tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| { - lint.primary_message("unportable markdown"); - if precise { - lint.span_suggestion( - ref_span.shrink_to_lo(), - "if it should not be a footnote, escape it", - "\\", - Applicability::MaybeIncorrect, - ); - } - if dox.as_bytes().get(span.end) == Some(&b'[') { - lint.help("confusing footnote reference and link"); - if precise { - lint.span_suggestion( - ref_span.shrink_to_hi(), - "if the footnote is intended, add a space", - " ", - Applicability::MaybeIncorrect, - ); - } else { - lint.help("there should be a space between the link and the footnote"); - } - } - }); - } -} diff --git a/tests/rustdoc-ui/unportable-markdown.rs b/tests/rustdoc-ui/unportable-markdown.rs deleted file mode 100644 index 105fc1e59d53..000000000000 --- a/tests/rustdoc-ui/unportable-markdown.rs +++ /dev/null @@ -1,62 +0,0 @@ -// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929 -// -// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes. -// -// This version of the lint is targeted at two especially-common cases where docs got broken. -// Other differences in parsing should not warn. -#![allow(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::unportable_markdown)] - -/// -/// -/// Test footnote [^foot]. -/// -/// [^foot]: This is nested within the footnote now, but didn't used to be. -/// -/// This is a multi-paragraph footnote. -pub struct GfmFootnotes; - -/// -/// -/// test [^foo][^bar] -/// -/// [^foo]: test -/// [^bar]: test2 -pub struct FootnoteSmashedName; - -/// -/// -/// - _t -/// # test -/// t_ -pub struct NestingCornerCase; - -/// -/// -/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~ -pub struct Emphasis1; - -/// -/// -/// | -/// | -pub struct NotEnoughTable; - -/// -/// -/// foo -/// >bar -//~^ ERROR unportable markdown -pub struct BlockQuoteNoSpace; - -/// Negative test. -/// -/// foo -/// > bar -pub struct BlockQuoteSpace; - -/// Negative test. -/// -/// >bar -/// baz -pub struct BlockQuoteNoSpaceStart; diff --git a/tests/rustdoc-ui/unportable-markdown.stderr b/tests/rustdoc-ui/unportable-markdown.stderr deleted file mode 100644 index 952ae4bb6eec..000000000000 --- a/tests/rustdoc-ui/unportable-markdown.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: unportable markdown - --> $DIR/unportable-markdown.rs:48:5 - | -LL | /// >bar - | ^ - | - = help: confusing block quote with no space after the `>` marker -note: the lint level is defined here - --> $DIR/unportable-markdown.rs:8:9 - | -LL | #![deny(rustdoc::unportable_markdown)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: if the quote is intended, add a space - | -LL | /// > bar - | + -help: if it should not be a quote, escape it - | -LL | /// \>bar - | + - -error: aborting due to 1 previous error - From 43357b4a64b0bfaf6c9db14cff998a2d17b98dac Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 21 Apr 2025 16:44:42 +0530 Subject: [PATCH 285/302] Added `apxf` target feature support, under flag `apx_target_feature` --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 12 ++++++++++++ compiler/rustc_feature/src/unstable.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 1 + 4 files changed, 15 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f8706c5ee2fa..8f57f0983abb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -307,6 +307,18 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("avx10.1-512")), ("x86", "avx10.2") if get_version().0 < 20 => None, ("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")), + ("x86", "apxf") => Some(LLVMFeature::with_dependencies( + "egpr", + smallvec![ + TargetFeatureFoldStrength::Both("push2pop2"), + TargetFeatureFoldStrength::Both("ppx"), + TargetFeatureFoldStrength::Both("ndd"), + TargetFeatureFoldStrength::Both("ccmp"), + TargetFeatureFoldStrength::Both("cf"), + TargetFeatureFoldStrength::Both("nf"), + TargetFeatureFoldStrength::Both("zu"), + ], + )), (_, s) => Some(LLVMFeature::new(s)), } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1a011dfff3f7..d96089a64d08 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -316,6 +316,7 @@ declare_features! ( // Unstable `#[target_feature]` directives. (unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)), (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), + (unstable, apx_target_feature, "CURRENT_RUSTC_VERSION", Some(139284)), (unstable, arm_target_feature, "1.27.0", Some(44839)), (unstable, avx512_target_feature, "1.27.0", Some(44839)), (unstable, bpf_target_feature, "1.54.0", Some(44839)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3912c7dc7d69..1134209d2b85 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -459,6 +459,7 @@ symbols! { anonymous_lifetime_in_impl_trait, any, append_const_msg, + apx_target_feature, arbitrary_enum_discriminant, arbitrary_self_types, arbitrary_self_types_pointers, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index d04c8f3f2ebf..5a21925ba04e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -393,6 +393,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("apxf", Unstable(sym::apx_target_feature), &[]), ("avx", Stable, &["sse4.2"]), ( "avx10.1", From c32dc2dbda99903039a5e815451f7b376f65d35d Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 21 Apr 2025 17:23:18 +0530 Subject: [PATCH 286/302] Added apxf target feature test --- tests/ui/check-cfg/target_feature.stderr | 1 + .../feature-gate-apx-target-feature.rs | 6 ++++++ .../feature-gate-apx-target-feature.stderr | 13 +++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-apx-target-feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-apx-target-feature.stderr diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 3d7323298bab..eb66633f9dd7 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -27,6 +27,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `amx-tf32` `amx-tile` `amx-transpose` +`apxf` `atomics` `avx` `avx10.1` diff --git a/tests/ui/feature-gates/feature-gate-apx-target-feature.rs b/tests/ui/feature-gates/feature-gate-apx-target-feature.rs new file mode 100644 index 000000000000..a2ac4ac86ac0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-apx-target-feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "apxf")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr b/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr new file mode 100644 index 000000000000..1999ab535379 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `apxf` is currently unstable + --> $DIR/feature-gate-apx-target-feature.rs:2:18 + | +LL | #[target_feature(enable = "apxf")] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #139284 for more information + = help: add `#![feature(apx_target_feature)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 3c1c0726ad18dc07f3ef9b9465d5997ca13e332c Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 6 May 2025 15:06:45 +0500 Subject: [PATCH 287/302] added error handle for error code > 9999 --- compiler/rustc_driver_impl/src/lib.rs | 1 + tests/ui/{explain.rs => explain/basic.rs} | 0 .../{explain.stdout => explain/basic.stdout} | 0 tests/ui/explain/error-with-no-explanation.rs | 3 + .../explain/error-with-no-explanation.stderr | 2 + tests/ui/explain/invalid-error-code.rs | 2 + tests/ui/explain/invalid-error-code.stderr | 2 + tests/ui/explain/no-E-prefix.rs | 2 + tests/ui/explain/no-E-prefix.stdout | 57 +++++++++++++++++++ tests/ui/explain/overflow-error-code.rs | 4 ++ tests/ui/explain/overflow-error-code.stderr | 2 + 11 files changed, 75 insertions(+) rename tests/ui/{explain.rs => explain/basic.rs} (100%) rename tests/ui/{explain.stdout => explain/basic.stdout} (100%) create mode 100644 tests/ui/explain/error-with-no-explanation.rs create mode 100644 tests/ui/explain/error-with-no-explanation.stderr create mode 100644 tests/ui/explain/invalid-error-code.rs create mode 100644 tests/ui/explain/invalid-error-code.stderr create mode 100644 tests/ui/explain/no-E-prefix.rs create mode 100644 tests/ui/explain/no-E-prefix.stdout create mode 100644 tests/ui/explain/overflow-error-code.rs create mode 100644 tests/ui/explain/overflow-error-code.stderr diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index fdf8053b15a6..95cfe221d3fe 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -463,6 +463,7 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col // Allow "E0123" or "0123" form. let upper_cased_code = code.to_ascii_uppercase(); if let Ok(code) = upper_cased_code.strip_prefix('E').unwrap_or(&upper_cased_code).parse::() + && code <= ErrCode::MAX_AS_U32 && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code)) { let mut is_in_code_block = false; diff --git a/tests/ui/explain.rs b/tests/ui/explain/basic.rs similarity index 100% rename from tests/ui/explain.rs rename to tests/ui/explain/basic.rs diff --git a/tests/ui/explain.stdout b/tests/ui/explain/basic.stdout similarity index 100% rename from tests/ui/explain.stdout rename to tests/ui/explain/basic.stdout diff --git a/tests/ui/explain/error-with-no-explanation.rs b/tests/ui/explain/error-with-no-explanation.rs new file mode 100644 index 000000000000..383820eb4580 --- /dev/null +++ b/tests/ui/explain/error-with-no-explanation.rs @@ -0,0 +1,3 @@ +// It's a valid error with no added explanation +//@ compile-flags: --explain E9999 +//~? ERROR: E9999 is not a valid error code diff --git a/tests/ui/explain/error-with-no-explanation.stderr b/tests/ui/explain/error-with-no-explanation.stderr new file mode 100644 index 000000000000..afb738cfecb9 --- /dev/null +++ b/tests/ui/explain/error-with-no-explanation.stderr @@ -0,0 +1,2 @@ +error: E9999 is not a valid error code + diff --git a/tests/ui/explain/invalid-error-code.rs b/tests/ui/explain/invalid-error-code.rs new file mode 100644 index 000000000000..114118d5196b --- /dev/null +++ b/tests/ui/explain/invalid-error-code.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --explain error_code +//~? ERROR: error_code is not a valid error code diff --git a/tests/ui/explain/invalid-error-code.stderr b/tests/ui/explain/invalid-error-code.stderr new file mode 100644 index 000000000000..c33122ea88cb --- /dev/null +++ b/tests/ui/explain/invalid-error-code.stderr @@ -0,0 +1,2 @@ +error: error_code is not a valid error code + diff --git a/tests/ui/explain/no-E-prefix.rs b/tests/ui/explain/no-E-prefix.rs new file mode 100644 index 000000000000..39c9122bfe1b --- /dev/null +++ b/tests/ui/explain/no-E-prefix.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --explain 425 +//@ check-pass diff --git a/tests/ui/explain/no-E-prefix.stdout b/tests/ui/explain/no-E-prefix.stdout new file mode 100644 index 000000000000..756b970aa7e6 --- /dev/null +++ b/tests/ui/explain/no-E-prefix.stdout @@ -0,0 +1,57 @@ +An unresolved name was used. + +Erroneous code examples: + +``` +something_that_doesnt_exist::foo; +// error: unresolved name `something_that_doesnt_exist::foo` + +// or: + +trait Foo { + fn bar() { + Self; // error: unresolved name `Self` + } +} + +// or: + +let x = unknown_variable; // error: unresolved name `unknown_variable` +``` + +Please verify that the name wasn't misspelled and ensure that the +identifier being referred to is valid for the given situation. Example: + +``` +enum something_that_does_exist { + Foo, +} +``` + +Or: + +``` +mod something_that_does_exist { + pub static foo : i32 = 0i32; +} + +something_that_does_exist::foo; // ok! +``` + +Or: + +``` +let unknown_variable = 12u32; +let x = unknown_variable; // ok! +``` + +If the item is not defined in the current module, it must be imported using a +`use` statement, like so: + +``` +use foo::bar; +bar(); +``` + +If the item you are importing is not defined in some super-module of the +current module, then it must also be declared as public (e.g., `pub fn`). diff --git a/tests/ui/explain/overflow-error-code.rs b/tests/ui/explain/overflow-error-code.rs new file mode 100644 index 000000000000..284d5cddb35a --- /dev/null +++ b/tests/ui/explain/overflow-error-code.rs @@ -0,0 +1,4 @@ +// Check that we don't crash on error codes exceeding our internal limit. +// issue: +//@ compile-flags: --explain E10000 +//~? ERROR: E10000 is not a valid error code diff --git a/tests/ui/explain/overflow-error-code.stderr b/tests/ui/explain/overflow-error-code.stderr new file mode 100644 index 000000000000..67e584ea32e1 --- /dev/null +++ b/tests/ui/explain/overflow-error-code.stderr @@ -0,0 +1,2 @@ +error: E10000 is not a valid error code + From 636a138cdae2da2b261a54681a2910ce21ed8019 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 May 2025 19:27:25 +0000 Subject: [PATCH 288/302] Structurally resolve in check_ref_cast --- compiler/rustc_hir_typeck/src/cast.rs | 15 ++++++------- .../ui/cast/cast-alias-of-array-to-element.rs | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 tests/ui/cast/cast-alias-of-array-to-element.rs diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index caf36ba47bd7..5bfc3e810d9f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1051,20 +1051,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn check_ref_cast( &self, fcx: &FnCtxt<'a, 'tcx>, - m_expr: ty::TypeAndMut<'tcx>, - m_cast: ty::TypeAndMut<'tcx>, + mut m_expr: ty::TypeAndMut<'tcx>, + mut m_cast: ty::TypeAndMut<'tcx>, ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const + m_expr.ty = fcx.try_structurally_resolve_type(self.expr_span, m_expr.ty); + m_cast.ty = fcx.try_structurally_resolve_type(self.cast_span, m_cast.ty); + if m_expr.mutbl >= m_cast.mutbl && let ty::Array(ety, _) = m_expr.ty.kind() && fcx.can_eq(fcx.param_env, *ety, m_cast.ty) { - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow raw pointers to work correctly, we - // need to special-case obtaining a raw pointer - // from a region pointer to a vector. + // Due to historical reasons we allow directly casting references of + // arrays into raw pointers of their element type. // Coerce to a raw pointer so that we generate RawPtr in MIR. let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); diff --git a/tests/ui/cast/cast-alias-of-array-to-element.rs b/tests/ui/cast/cast-alias-of-array-to-element.rs new file mode 100644 index 000000000000..124d0e0346f0 --- /dev/null +++ b/tests/ui/cast/cast-alias-of-array-to-element.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// Test that we structually normalize in the hacky `&[T; N] -> *const T` in cast. + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +struct W<'a>(&'a <[f32; 0] as Mirror>::Assoc); + +fn foo(x: W<'_>) -> *const f32 { + x.0 as *const f32 +} + +fn main() {} From 6a4af821b00a1e55f44c80846c1a438a3c41dee5 Mon Sep 17 00:00:00 2001 From: Jon Bauman Date: Tue, 6 May 2025 13:19:42 -0700 Subject: [PATCH 289/302] Update rc.rs docs Update comment per review feedback --- library/alloc/src/rc.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 247afc628326..4b8ea708e7e5 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3536,11 +3536,11 @@ impl Default for Weak { } } -// NOTE: We wrapping_add here to deal with mem::forget safely. In particular -// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then -// you can free the allocation while outstanding Rcs (or Weaks) exist. -// We abort because this is such a degenerate scenario that we don't care about -// what happens -- no real program should ever experience this. +// NOTE: If you mem::forget Rcs (or Weaks), drop is skipped and the ref-count +// is not decremented, meaning the ref-count can overflow, and then you can +// free the allocation while outstanding Rcs (or Weaks) exist, which would be +// unsound. We abort because this is such a degenerate scenario that we don't +// care about what happens -- no real program should ever experience this. // // This should have negligible overhead since you don't actually need to // clone these much in Rust thanks to ownership and move-semantics. From 49ac393688510f0f36627f5899bf0ededd26a8de Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 7 May 2025 00:11:05 +0200 Subject: [PATCH 290/302] fix typo in autorefs lint doc example The documentation is talking about other way using only raw pointers, but the example was use `std::slice::from_raw_parts_mut` which also create a reference. `std::ptr::slice_from_raw_parts_mut` should be used instead, and it also highlights the benefit of raw pointer manipulation compared to dereference, as the function doesn't need to be unsafe anymore. Moreover, [`unsafe_op_in_unsafe_fn`](https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html) warning has been enabled since Edition 2024, so I've updated the examples to use unsafe blocks. --- compiler/rustc_lint/src/autorefs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index ddab13190beb..91d58d92466a 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -15,9 +15,9 @@ declare_lint! { /// /// ```rust /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// &raw mut (*ptr)[..16] - /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, - /// // implicitly creating a reference + /// unsafe { &raw mut (*ptr)[..16] } + /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, + /// // implicitly creating a reference /// } /// ``` /// @@ -34,17 +34,17 @@ declare_lint! { /// /// ```rust /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// &raw mut (&mut *ptr)[..16] + /// unsafe { &raw mut (&mut *ptr)[..16] } /// } /// ``` /// /// Otherwise try to find an alternative way to achive your goals using only raw pointers: /// /// ```rust - /// use std::slice; + /// use std::ptr; /// - /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// slice::from_raw_parts_mut(ptr.cast(), 16) + /// fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// ptr::slice_from_raw_parts_mut(ptr.cast(), 16) /// } /// ``` pub DANGEROUS_IMPLICIT_AUTOREFS, From 4de822c3d2a3c13633b0c08ae98d05aada94eabf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 May 2025 23:30:47 +0000 Subject: [PATCH 291/302] Update `compiler-builtins` to 0.1.158 Includes the following changes: * Require `target_has_atomic = "ptr"` for runtime feature detection [1]: https://github.com/rust-lang/compiler-builtins/pull/909 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index a94ed7be8c78..5100b4d8176d 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.157" +version = "0.1.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" +checksum = "164cdc689e4c6d69417f77a5f48be240c291e84fbef0b1281755dc754b19c809" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index ebfcf8759fa1..51ddc9bf9fc9 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.157", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.158", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 06bec74523bb..e548daa1ad0d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.157" } +compiler_builtins = { version = "=0.1.158" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From b41d8bde00930d80f07b7aa90cc0a8e6bd423413 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 17 Apr 2025 02:33:24 -0700 Subject: [PATCH 292/302] let deref patterns participate in usefulness/exhaustiveness This does not yet handle the case of mixed deref patterns with normal constructors; it'll ICE in `Constructor::is_covered_by`. That'll be fixed in a later commit. --- .../rustc_pattern_analysis/src/constructor.rs | 22 +++++++++++++++++++ compiler/rustc_pattern_analysis/src/rustc.rs | 18 ++++++++++----- .../rustc_pattern_analysis/src/usefulness.rs | 4 +++- .../src/language-features/deref-patterns.md | 3 +-- tests/ui/pattern/deref-patterns/bindings.rs | 2 -- .../pattern/deref-patterns/closure_capture.rs | 8 +++---- tests/ui/pattern/deref-patterns/deref-box.rs | 10 ++++----- .../deref-patterns/implicit-cow-deref.rs | 4 ---- 8 files changed, 47 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 4ce868f014f4..f7a4931c1114 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -696,6 +696,10 @@ pub enum Constructor { F128Range(IeeeFloat, IeeeFloat, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(Cx::StrLit), + /// Deref patterns (enabled by the `deref_patterns` feature) provide a way of matching on a + /// smart pointer ADT through its pointee. They don't directly correspond to ADT constructors, + /// and currently are not supported alongside them. Carries the type of the pointee. + DerefPattern(Cx::Ty), /// Constants that must not be matched structurally. They are treated as black boxes for the /// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a /// match exhaustive. @@ -740,6 +744,7 @@ impl Clone for Constructor { Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end), Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), + Constructor::DerefPattern(ty) => Constructor::DerefPattern(ty.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, Constructor::Never => Constructor::Never, @@ -856,6 +861,10 @@ impl Constructor { } (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), + // Deref patterns only interact with other deref patterns. Prior to usefulness analysis, + // we ensure they don't appear alongside any other non-wild non-opaque constructors. + (DerefPattern(_), DerefPattern(_)) => true, + // Opaque constructors don't interact with anything unless they come from the // syntactically identical pattern. (Opaque(self_id), Opaque(other_id)) => self_id == other_id, @@ -932,6 +941,7 @@ impl Constructor { F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, Str(value) => write!(f, "{value:?}")?, + DerefPattern(_) => write!(f, "deref!({:?})", fields.next().unwrap())?, Opaque(..) => write!(f, "")?, Or => { for pat in fields { @@ -1039,8 +1049,17 @@ impl ConstructorSet { let mut missing = Vec::new(); // Constructors in `ctors`, except wildcards and opaques. let mut seen = Vec::new(); + // If we see a deref pattern, it must be the only non-wildcard non-opaque constructor; we + // ensure this prior to analysis. + let mut deref_pat_present = false; for ctor in ctors.cloned() { match ctor { + DerefPattern(..) => { + if !deref_pat_present { + deref_pat_present = true; + present.push(ctor); + } + } Opaque(..) => present.push(ctor), Wildcard => {} // discard wildcards _ => seen.push(ctor), @@ -1048,6 +1067,9 @@ impl ConstructorSet { } match self { + _ if deref_pat_present => { + // Deref patterns are the only constructor; nothing is missing. + } ConstructorSet::Struct { empty } => { if !seen.is_empty() { present.push(Struct); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7c12f69f14c1..050b48d082b7 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -269,6 +269,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, + DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], @@ -296,7 +297,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => 1, + Ref | DerefPattern(_) => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing @@ -493,11 +494,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), }; } - PatKind::DerefPattern { .. } => { - // FIXME(deref_patterns): At least detect that `box _` is irrefutable. - fields = vec![]; - arity = 0; - ctor = Opaque(OpaqueId::new()); + PatKind::DerefPattern { subpattern, .. } => { + // NB(deref_patterns): This assumes the deref pattern is matching on a trusted + // `DerefPure` type. If the `Deref` impl isn't trusted, exhaustiveness must take + // into account that multiple calls to deref may return different results. Hence + // multiple deref! patterns cannot be exhaustive together unless each is exhaustive + // by itself. + fields = vec![self.lower_pat(subpattern).at_index(0)]; + arity = 1; + ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty)); } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { match ty.kind() { @@ -874,6 +879,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); s } + DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])), Slice(slice) => { let (prefix_len, has_dot_dot) = match slice.kind { SliceKind::FixedLen(len) => (len, false), diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 11ebbea07fa4..53638f2a57dd 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -702,6 +702,7 @@ //! - `ui/consts/const_in_pattern` //! - `ui/rfc-2008-non-exhaustive` //! - `ui/half-open-range-patterns` +//! - `ui/pattern/deref-patterns` //! - probably many others //! //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific @@ -866,7 +867,8 @@ impl PlaceValidity { /// inside `&` and union fields where validity is reset to `MaybeInvalid`. fn specialize(self, ctor: &Constructor) -> Self { // We preserve validity except when we go inside a reference or a union field. - if matches!(ctor, Constructor::Ref | Constructor::UnionField) { + if matches!(ctor, Constructor::Ref | Constructor::DerefPattern(_) | Constructor::UnionField) + { // Validity of `x: &T` does not imply validity of `*x: T`. MaybeInvalid } else { diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index fb6df290cc12..4c3d456b9af8 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -60,8 +60,7 @@ Like [`box_patterns`], deref patterns may move out of boxes: # #![feature(deref_patterns)] # #![allow(incomplete_features)] struct NoCopy; -// Match exhaustiveness analysis is not yet implemented. -let deref!(x) = Box::new(NoCopy) else { unreachable!() }; +let deref!(x) = Box::new(NoCopy); drop::(x); ``` diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs index ac48e3ffefcc..92c01d737bac 100644 --- a/tests/ui/pattern/deref-patterns/bindings.rs +++ b/tests/ui/pattern/deref-patterns/bindings.rs @@ -13,7 +13,6 @@ fn simple_vec(vec: Vec) -> u32 { deref!([x]) => x, deref!([1, x]) => x + 200, deref!(ref slice) => slice.iter().sum(), - _ => 2000, } } @@ -25,7 +24,6 @@ fn simple_vec(vec: Vec) -> u32 { [x] => x, [1, x] => x + 200, deref!(ref slice) => slice.iter().sum(), - _ => 2000, } } diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs index cf78eeda1d5a..497ec622b0cf 100644 --- a/tests/ui/pattern/deref-patterns/closure_capture.rs +++ b/tests/ui/pattern/deref-patterns/closure_capture.rs @@ -9,7 +9,7 @@ struct NoCopy; fn main() { let b = Rc::new("aaa".to_string()); let f = || { - let deref!(ref s) = b else { unreachable!() }; + let deref!(ref s) = b; assert_eq!(s.len(), 3); }; assert_eq!(b.len(), 3); @@ -26,7 +26,7 @@ fn main() { let mut b = "aaa".to_string(); let mut f = || { - let deref!(ref mut s) = b else { unreachable!() }; + let deref!(ref mut s) = b; s.make_ascii_uppercase(); }; f(); @@ -53,7 +53,7 @@ fn main() { let b = Box::new(NoCopy); let f = || { // this should move out of the box rather than borrow. - let deref!(x) = b else { unreachable!() }; + let deref!(x) = b; drop::(x); }; f(); @@ -61,7 +61,7 @@ fn main() { let b = Box::new((NoCopy,)); let f = || { // this should move out of the box rather than borrow. - let (x,) = b else { unreachable!() }; + let (x,) = b; drop::(x); }; f(); diff --git a/tests/ui/pattern/deref-patterns/deref-box.rs b/tests/ui/pattern/deref-patterns/deref-box.rs index 2d0a8d01972e..39b23dcab51e 100644 --- a/tests/ui/pattern/deref-patterns/deref-box.rs +++ b/tests/ui/pattern/deref-patterns/deref-box.rs @@ -6,18 +6,18 @@ #![expect(incomplete_features)] fn unbox_1(b: Box) -> T { - let deref!(x) = b else { unreachable!() }; + let deref!(x) = b; x } fn unbox_2(b: Box<(T,)>) -> T { - let (x,) = b else { unreachable!() }; + let (x,) = b; x } fn unbox_separately(b: Box<(T, T)>) -> (T, T) { - let (x, _) = b else { unreachable!() }; - let (_, y) = b else { unreachable!() }; + let (x, _) = b; + let (_, y) = b; (x, y) } @@ -31,7 +31,7 @@ fn main() { // test that borrowing from a box also works let mut b = "hi".to_owned().into_boxed_str(); - let deref!(ref mut s) = b else { unreachable!() }; + let deref!(ref mut s) = b; s.make_ascii_uppercase(); assert_eq!(&*b, "HI"); } diff --git a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs index 04c83d4c33fd..24770261edc5 100644 --- a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs +++ b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs @@ -11,7 +11,6 @@ fn main() { match cow { [..] => {} - _ => unreachable!(), } match cow { @@ -22,14 +21,12 @@ fn main() { match Rc::new(&cow) { Cow::Borrowed { 0: _ } => {} Cow::Owned { 0: _ } => unreachable!(), - _ => unreachable!(), } let cow_of_cow: Cow<'_, Cow<'static, [u8]>> = Cow::Owned(cow); match cow_of_cow { [..] => {} - _ => unreachable!(), } // This matches on the outer `Cow` (the owned one). @@ -41,6 +38,5 @@ fn main() { match Rc::new(&cow_of_cow) { Cow::Borrowed { 0: _ } => unreachable!(), Cow::Owned { 0: _ } => {} - _ => unreachable!(), } } From cf43bba1e5ec87838fca248f36d940f2923576c2 Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 18 Apr 2025 03:03:57 -0700 Subject: [PATCH 293/302] add exhaustiveness/usefulness tests for deref patterns --- .../deref-patterns/usefulness/empty-types.rs | 47 ++++++++++++++ .../usefulness/empty-types.stderr | 38 +++++++++++ .../usefulness/non-exhaustive.rs | 28 +++++++++ .../usefulness/non-exhaustive.stderr | 63 +++++++++++++++++++ .../usefulness/unreachable-patterns.rs | 33 ++++++++++ .../usefulness/unreachable-patterns.stderr | 60 ++++++++++++++++++ 6 files changed, 269 insertions(+) create mode 100644 tests/ui/pattern/deref-patterns/usefulness/empty-types.rs create mode 100644 tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr create mode 100644 tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs create mode 100644 tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr create mode 100644 tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs create mode 100644 tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs new file mode 100644 index 000000000000..03419030e72f --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs @@ -0,0 +1,47 @@ +//! Test that the place behind a deref pattern is treated as maybe-invalid, and thus empty arms +//! cannot be omitted. This is handled the same as for refs and union fields, so this leaves the +//! bulk of the testing to `tests/ui/pattern/usefulness/empty-types.rs`. +// FIXME(deref_patterns): On stabilization, cases for deref patterns could be worked into that file +// to keep the tests for empty types in one place and test more thoroughly. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +enum Void {} + +fn main() { + // Sanity check: matching on an empty type without pointer indirection lets us omit arms. + let opt_void: Option = None; + match opt_void { + None => {} + } + + // But if we hide it behind a smart pointer, we need an arm. + let box_opt_void: Box> = Box::new(None); + match box_opt_void { + //~^ ERROR non-exhaustive patterns: `deref!(Some(_))` not covered + None => {} + } + match box_opt_void { + None => {} + Some(_) => {} + } + match box_opt_void { + None => {} + _ => {} + } + + // For consistency, this behaves the same as if we manually dereferenced the scrutinee. + match *box_opt_void { + //~^ ERROR non-exhaustive patterns: `Some(_)` not covered + None => {} + } + match *box_opt_void { + None => {} + Some(_) => {} + } + match *box_opt_void { + None => {} + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr new file mode 100644 index 000000000000..e32477085661 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr @@ -0,0 +1,38 @@ +error[E0004]: non-exhaustive patterns: `deref!(Some(_))` not covered + --> $DIR/empty-types.rs:21:11 + | +LL | match box_opt_void { + | ^^^^^^^^^^^^ pattern `deref!(Some(_))` not covered + | +note: `Box>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box>` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + deref!(Some(_)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:35:11 + | +LL | match *box_opt_void { + | ^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs new file mode 100644 index 000000000000..704cae8bdbc4 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs @@ -0,0 +1,28 @@ +//! Test non-exhaustive matches involving deref patterns. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() { + match Box::new(false) { + //~^ ERROR non-exhaustive patterns: `deref!(true)` not covered + false => {} + } + + match Box::new(Box::new(false)) { + //~^ ERROR non-exhaustive patterns: `deref!(deref!(false))` not covered + true => {} + } + + match Box::new((true, Box::new(false))) { + //~^ ERROR non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + (true, false) => {} + (false, true) => {} + } + + enum T { A, B, C } + match Box::new((Box::new(T::A), Box::new(T::A))) { + //~^ ERROR non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered + (T::A | T::B, T::C) => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr new file mode 100644 index 000000000000..55fa84bafde2 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr @@ -0,0 +1,63 @@ +error[E0004]: non-exhaustive patterns: `deref!(true)` not covered + --> $DIR/non-exhaustive.rs:7:11 + | +LL | match Box::new(false) { + | ^^^^^^^^^^^^^^^ pattern `deref!(true)` not covered + | +note: `Box` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ false => {}, +LL + deref!(true) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!(deref!(false))` not covered + --> $DIR/non-exhaustive.rs:12:11 + | +LL | match Box::new(Box::new(false)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!(deref!(false))` not covered + | +note: `Box>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ true => {}, +LL + deref!(deref!(false)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + --> $DIR/non-exhaustive.rs:17:11 + | +LL | match Box::new((true, Box::new(false))) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + | +note: `Box<(bool, Box)>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box<(bool, Box)>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (false, true) => {}, +LL + deref!((false, deref!(false))) | deref!((true, deref!(true))) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered + --> $DIR/non-exhaustive.rs:24:11 + | +LL | match Box::new((Box::new(T::A), Box::new(T::A))) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!((deref!(T::C), _))` not covered + | +note: `Box<(Box, Box)>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box<(Box, Box)>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ (T::A | T::B, T::C) => {}, +LL + deref!((deref!(T::C), _)) => todo!() + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs new file mode 100644 index 000000000000..2677fc54dedc --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs @@ -0,0 +1,33 @@ +//! Test unreachable patterns involving deref patterns. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() { + match Box::new(false) { + true => {} + false => {} + false => {} //~ ERROR unreachable pattern + } + + match Box::new(Box::new(false)) { + true => {} + false => {} + true => {} //~ ERROR unreachable pattern + } + + match Box::new((true, Box::new(false))) { + (true, _) => {} + (_, true) => {} + (false, false) => {} + _ => {} //~ ERROR unreachable pattern + } + + enum T { A, B, C } + match Box::new((Box::new(T::A), Box::new(T::A))) { + (T::A | T::B, T::A | T::C) => {} + (T::A, T::C) => {} //~ ERROR unreachable pattern + (T::B, T::A) => {} //~ ERROR unreachable pattern + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr new file mode 100644 index 000000000000..045e11be3196 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr @@ -0,0 +1,60 @@ +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:10:9 + | +LL | false => {} + | ----- matches all the relevant values +LL | false => {} + | ^^^^^ no value can reach this + | +note: the lint level is defined here + --> $DIR/unreachable-patterns.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:16:9 + | +LL | true => {} + | ---- matches all the relevant values +LL | false => {} +LL | true => {} + | ^^^^ no value can reach this + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:23:9 + | +LL | _ => {} + | ^ no value can reach this + | +note: multiple earlier patterns match some of the same values + --> $DIR/unreachable-patterns.rs:23:9 + | +LL | (true, _) => {} + | --------- matches some of the same values +LL | (_, true) => {} + | --------- matches some of the same values +LL | (false, false) => {} + | -------------- matches some of the same values +LL | _ => {} + | ^ collectively making this unreachable + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:29:9 + | +LL | (T::A | T::B, T::A | T::C) => {} + | -------------------------- matches all the relevant values +LL | (T::A, T::C) => {} + | ^^^^^^^^^^^^ no value can reach this + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:30:9 + | +LL | (T::A | T::B, T::A | T::C) => {} + | -------------------------- matches all the relevant values +LL | (T::A, T::C) => {} +LL | (T::B, T::A) => {} + | ^^^^^^^^^^^^ no value can reach this + +error: aborting due to 5 previous errors + From fb261a179d2c210785b6e9005201e262dac801b5 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 20 Apr 2025 23:57:09 -0700 Subject: [PATCH 294/302] error early when mixing deref patterns with normal constructors Without adding proper support for mixed exhaustiveness, mixing deref patterns with normal constructors would either violate `ConstructorSet::split`'s invariant 4 or 7. We'd either be ignoring rows with normal constructors or we'd have problems in unspecialization from non-disjoint constructors. Checking mixed exhaustivenss similarly to how unions are currently checked should work, but the diagnostics for unions are confusing. Since mixing deref patterns with normal constructors is pretty niche (currently it only makes sense for `Cow`), emitting an error lets us avoid committing to supporting mixed exhaustiveness without a good answer for the diagnostics. --- compiler/rustc_pattern_analysis/messages.ftl | 4 ++ compiler/rustc_pattern_analysis/src/errors.rs | 14 ++++- compiler/rustc_pattern_analysis/src/rustc.rs | 53 +++++++++++++++++++ .../usefulness/mixed-constructors.rs | 48 +++++++++++++++++ .../usefulness/mixed-constructors.stderr | 43 +++++++++++++++ 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs create mode 100644 tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr diff --git a/compiler/rustc_pattern_analysis/messages.ftl b/compiler/rustc_pattern_analysis/messages.ftl index 41a1d958f109..d3a3107f8e89 100644 --- a/compiler/rustc_pattern_analysis/messages.ftl +++ b/compiler/rustc_pattern_analysis/messages.ftl @@ -6,6 +6,10 @@ pattern_analysis_excluside_range_missing_max = exclusive range missing `{$max}` .label = this range doesn't match `{$max}` because `..` is an exclusive range .suggestion = use an inclusive range instead +pattern_analysis_mixed_deref_pattern_constructors = mix of deref patterns and normal constructors + .deref_pattern_label = matches on the result of dereferencing `{$smart_pointer_ty}` + .normal_constructor_label = matches directly on `{$smart_pointer_ty}` + pattern_analysis_non_exhaustive_omitted_pattern = some variants are not matched explicitly .help = ensure that all variants are matched explicitly by adding the suggested match arms .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index e60930d6cd21..156ba9737673 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -133,3 +133,15 @@ pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { pub lint_level: &'static str, pub lint_name: &'static str, } + +#[derive(Diagnostic)] +#[diag(pattern_analysis_mixed_deref_pattern_constructors)] +pub(crate) struct MixedDerefPatternConstructors<'tcx> { + #[primary_span] + pub spans: Vec, + pub smart_pointer_ty: Ty<'tcx>, + #[label(pattern_analysis_deref_pattern_label)] + pub deref_pattern_label: Span, + #[label(pattern_analysis_normal_constructor_label)] + pub normal_constructor_label: Span, +} diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 050b48d082b7..a89d01dcbbe4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1106,6 +1106,14 @@ pub fn analyze_match<'p, 'tcx>( scrut_ty: Ty<'tcx>, ) -> Result, ErrorGuaranteed> { let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); + + // The analysis doesn't support deref patterns mixed with normal constructors; error if present. + // FIXME(deref_patterns): This only needs to run when a deref pattern was found during lowering. + if tycx.tcx.features().deref_patterns() { + let pat_column = PatternColumn::new(arms); + detect_mixed_deref_pat_ctors(tycx, &pat_column)?; + } + let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee); let report = compute_match_usefulness( tycx, @@ -1125,6 +1133,51 @@ pub fn analyze_match<'p, 'tcx>( Ok(report) } +// FIXME(deref_patterns): Currently it's the responsibility of the frontend (rustc or rust-analyzer) +// to ensure that deref patterns don't appear in the same column as normal constructors. Deref +// patterns aren't currently implemented in rust-analyzer, but should they be, the columnwise check +// here could be made generic and shared between frontends. +fn detect_mixed_deref_pat_ctors<'p, 'tcx>( + cx: &RustcPatCtxt<'p, 'tcx>, + column: &PatternColumn<'p, RustcPatCtxt<'p, 'tcx>>, +) -> Result<(), ErrorGuaranteed> { + let Some(&ty) = column.head_ty() else { + return Ok(()); + }; + + // Check for a mix of deref patterns and normal constructors. + let mut normal_ctor_span = None; + let mut deref_pat_span = None; + for pat in column.iter() { + match pat.ctor() { + // The analysis can handle mixing deref patterns with wildcards and opaque patterns. + Wildcard | Opaque(_) => {} + DerefPattern(_) => deref_pat_span = Some(pat.data().span), + // Nothing else can be compared to deref patterns in `Constructor::is_covered_by`. + _ => normal_ctor_span = Some(pat.data().span), + } + } + if let Some(normal_constructor_label) = normal_ctor_span + && let Some(deref_pattern_label) = deref_pat_span + { + return Err(cx.tcx.dcx().emit_err(errors::MixedDerefPatternConstructors { + spans: vec![deref_pattern_label, normal_constructor_label], + smart_pointer_ty: ty.inner(), + deref_pattern_label, + normal_constructor_label, + })); + } + + // Specialize and recurse into the patterns' fields. + let set = column.analyze_ctors(cx, &ty)?; + for ctor in set.present { + for specialized_column in column.specialize(cx, &ty, &ctor).iter() { + detect_mixed_deref_pat_ctors(cx, specialized_column)?; + } + } + Ok(()) +} + struct RecursiveOpaque { def_id: DefId, } diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs new file mode 100644 index 000000000000..f567dc07bb59 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs @@ -0,0 +1,48 @@ +//! Test matches with a mix of ADT constructors and deref patterns. Currently, usefulness analysis +//! doesn't support this, so make sure we catch it beforehand. As a consequence, it takes priority +//! over non-exhaustive match and unreachable pattern errors. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +use std::borrow::Cow; + +fn main() { + let cow: Cow<'static, bool> = Cow::Borrowed(&false); + + match cow { + true => {} + //~v ERROR mix of deref patterns and normal constructors + false => {} + Cow::Borrowed(_) => {} + } + + match cow { + Cow::Owned(_) => {} + Cow::Borrowed(_) => {} + true => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match cow { + _ => {} + Cow::Owned(_) => {} + false => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match (cow, 0) { + (Cow::Owned(_), 0) => {} + (Cow::Borrowed(_), 0) => {} + (true, 0) => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match (0, cow) { + (0, Cow::Owned(_)) => {} + (0, Cow::Borrowed(_)) => {} + _ => {} + (1, true) => {} + //~^ ERROR mix of deref patterns and normal constructors + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr new file mode 100644 index 000000000000..5ad24164b985 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr @@ -0,0 +1,43 @@ +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:16:9 + | +LL | false => {} + | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` +LL | Cow::Borrowed(_) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:22:9 + | +LL | Cow::Borrowed(_) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | true => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:29:9 + | +LL | Cow::Owned(_) => {} + | ^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | false => {} + | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:36:10 + | +LL | (Cow::Borrowed(_), 0) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | (true, 0) => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:43:13 + | +LL | (0, Cow::Borrowed(_)) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | _ => {} +LL | (1, true) => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: aborting due to 5 previous errors + From 09fed2d2f440fff2179ca9373bb16e40fc81d935 Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 21 Apr 2025 02:34:02 -0700 Subject: [PATCH 295/302] add stubbed-out cases for rust-analyzer rust-analyzer doesn't construct `DerefPattern(_)` constructors, so these shouldn't crash. It looks like this is how slice patterns are implemented too. --- .../crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 6323d8b71b72..068fc22f2cac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -301,6 +301,7 @@ impl<'db> MatchCheckCtx<'db> { // ignore this issue. Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), + DerefPattern(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Never => PatKind::Never, @@ -351,6 +352,7 @@ impl PatCx for MatchCheckCtx<'_> { }, Ref => 1, Slice(..) => unimplemented!(), + DerefPattern(..) => unimplemented!(), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, @@ -411,6 +413,7 @@ impl PatCx for MatchCheckCtx<'_> { } }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), + DerefPattern(_) => unreachable!("Found a `DerefPattern` constructor in match checking"), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => { From fe64184b162cc6fc43b9e44ecaa8c065afbf7ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Mon, 28 Apr 2025 22:48:45 +0800 Subject: [PATCH 296/302] Fix backtrace for cygwin --- library/backtrace | 2 +- library/std/Cargo.toml | 2 +- library/windows_targets/src/lib.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/backtrace b/library/backtrace index 9d2c34e7e63a..6c882eb11984 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 9d2c34e7e63afe1e71c333b247065e3b7ba4d883 +Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453 diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 602af4a0447e..778f77e8eafa 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -57,7 +57,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur 'archive', ] } -[target.'cfg(windows)'.dependencies.windows-targets] +[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies.windows-targets] path = "../windows_targets" [dev-dependencies] diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index c7d158584ebd..bce54c5ffcef 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -34,6 +34,7 @@ pub macro link { } #[cfg(not(feature = "windows_raw_dylib"))] +#[cfg(not(target_os = "cygwin"))] // Cygwin doesn't need these libs #[cfg_attr(target_vendor = "win7", link(name = "advapi32"))] #[link(name = "ntdll")] #[link(name = "userenv")] From 392880c004836724dfe7600e6f2e0db5f8bad168 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Wed, 7 May 2025 08:04:21 +0000 Subject: [PATCH 297/302] Fix regression from #140393 for espidf / horizon / nuttx / vita --- library/std/src/sys/process/unix/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs index 2e8b38f7de1b..ee8fd8b2ca3c 100644 --- a/library/std/src/sys/process/unix/mod.rs +++ b/library/std/src/sys/process/unix/mod.rs @@ -11,6 +11,7 @@ cfg_if::cfg_if! { } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { mod unsupported; use unsupported as imp; + pub use unsupported::output; } else { mod unix; use unix as imp; From 4e26480c74112d4050e24a6a096cd0710c688b20 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Wed, 7 May 2025 16:01:39 +0200 Subject: [PATCH 298/302] add armv5te-unknown-linux-gnueabi target maintainer --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../armv5te-unknown-linux-gnueabi.md | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index cf41f5b86a85..a3939e5a5c45 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -58,6 +58,7 @@ - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) + - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 50c7ae3ef8db..60002a5f9e5d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -156,7 +156,7 @@ target | std | notes [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat -`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) +[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27) diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md new file mode 100644 index 000000000000..1baf1049994b --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md @@ -0,0 +1,29 @@ +# `armv5te-unknown-linux-gnueabi` + +**Tier: 2** + +This target supports Linux programs with glibc on ARMv5TE CPUs without +floating-point units. + +## Target maintainers + +[@koalatux](https://github.com/koalatux) + +## Requirements + +The target is for cross-compilation only. Host tools are not supported. +std is fully supported. + +## Building the target + +Because this target is tier 2, artifacts are available from rustup. + +## Building Rust programs + +For building rust programs, you might want to specify GCC as linker in +`.cargo/config.toml` as follows: + +```toml +[target.armv5te-unknown-linux-gnueabi] +linker = "arm-linux-gnueabi-gcc" +``` From 442ae63257708962de9d43c4f9b44130e7926321 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 May 2025 16:05:15 +0200 Subject: [PATCH 299/302] Add regression test for #139899 --- .../rustdoc-tempdir-removal/compile-error.rs | 5 +++ .../run-make/rustdoc-tempdir-removal/rmake.rs | 34 +++++++++++++++++++ .../rustdoc-tempdir-removal/run-error.rs | 3 ++ 3 files changed, 42 insertions(+) create mode 100644 tests/run-make/rustdoc-tempdir-removal/compile-error.rs create mode 100644 tests/run-make/rustdoc-tempdir-removal/rmake.rs create mode 100644 tests/run-make/rustdoc-tempdir-removal/run-error.rs diff --git a/tests/run-make/rustdoc-tempdir-removal/compile-error.rs b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs new file mode 100644 index 000000000000..66a3b3f270b7 --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs @@ -0,0 +1,5 @@ +#![doc(test(attr(deny(warnings))))] + +//! ``` +//! let a = 12; +//! ``` diff --git a/tests/run-make/rustdoc-tempdir-removal/rmake.rs b/tests/run-make/rustdoc-tempdir-removal/rmake.rs new file mode 100644 index 000000000000..bd87f05b7cf5 --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/rmake.rs @@ -0,0 +1,34 @@ +// This test ensures that no temporary folder is "left behind" when doctests fail for any reason. + +//@ only-linux + +use std::path::Path; + +use run_make_support::{path, rfs, rustdoc}; + +fn run_doctest_and_check_tmpdir(tmp_dir: &Path, doctest: &str, edition: &str) { + let output = + rustdoc().input(doctest).env("TMPDIR", tmp_dir).arg("--test").edition(edition).run_fail(); + + output.assert_exit_code(101).assert_stdout_contains( + "test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out", + ); + + rfs::read_dir_entries(tmp_dir, |entry| { + panic!("Found an item inside the temporary folder: {entry:?}"); + }); +} + +fn run_doctest_and_check_tmpdir_for_edition(tmp_dir: &Path, edition: &str) { + run_doctest_and_check_tmpdir(tmp_dir, "compile-error.rs", edition); + run_doctest_and_check_tmpdir(tmp_dir, "run-error.rs", edition); +} + +fn main() { + let tmp_dir = path("tmp"); + rfs::create_dir(&tmp_dir); + + run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2018"); + // We use the 2024 edition to check that it's also working for merged doctests. + run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2024"); +} diff --git a/tests/run-make/rustdoc-tempdir-removal/run-error.rs b/tests/run-make/rustdoc-tempdir-removal/run-error.rs new file mode 100644 index 000000000000..4ac95f6dd61a --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/run-error.rs @@ -0,0 +1,3 @@ +//! ``` +//! panic!(); +//! ``` From cd2dc67eadb6105790520223965deef6c5887f7a Mon Sep 17 00:00:00 2001 From: Jesus Checa Hidalgo Date: Wed, 7 May 2025 16:32:46 +0200 Subject: [PATCH 300/302] run-make-support: set rustc dylib path for cargo wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some run-make tests invoke Cargo via run_make_support::cargo(), but fail to execute correctly when rustc is built without rpath. In these setups, runtime loading of rustc’s shared libraries fails unless the appropriate dynamic library path is set manually. This commit updates the cargo() wrapper to call set_host_compiler_dylib_path(), aligning its behavior with the existing rustc() wrapper: https://github.com/rust-lang/rust/blob/f76c7367c6363d33ddb5a93b5de0d158b2d827f6/src/tools/run-make-support/src/external_deps/rustc.rs#L39 This ensures that Cargo invocations during tests inherit the necessary dylib paths, avoiding errors related to missing shared libraries in rpath-less builds. Fixes part of #140738 --- src/tools/run-make-support/src/external_deps/cargo.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs index e91d101cb995..8da9f002c41b 100644 --- a/src/tools/run-make-support/src/external_deps/cargo.rs +++ b/src/tools/run-make-support/src/external_deps/cargo.rs @@ -1,8 +1,11 @@ use crate::command::Command; use crate::env_var; +use crate::util::set_host_compiler_dylib_path; /// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest /// through the `CARGO` env var. pub fn cargo() -> Command { - Command::new(env_var("CARGO")) + let mut cmd = Command::new(env_var("CARGO")); + set_host_compiler_dylib_path(&mut cmd); + cmd } From b922da3586ce01a4bf174db09624a1d0a424d5d9 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 6 May 2025 15:45:04 +0800 Subject: [PATCH 301/302] Use `parse_param_general` when parsing `(T, U)->R` in `parse_path_segment` Signed-off-by: xizheyin Co-authored-by: Vadim Petrochenkov --- compiler/rustc_parse/messages.ftl | 10 +++++ compiler/rustc_parse/src/errors.rs | 24 ++++++++++ compiler/rustc_parse/src/parser/item.rs | 15 +++++-- compiler/rustc_parse/src/parser/path.rs | 29 +++++++++++- .../fn-trait-use-named-params-issue-140169.rs | 14 ++++-- ...trait-use-named-params-issue-140169.stderr | 44 ++++++++++++------ ...hesized-type-arguments-ice-issue-122345.rs | 8 ++-- ...zed-type-arguments-ice-issue-122345.stderr | 45 +++++++++++++++---- .../issues/issue-103748-ICE-wrong-braces.rs | 5 +-- .../issue-103748-ICE-wrong-braces.stderr | 39 ++-------------- 10 files changed, 158 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ac4f7ed64e22..907368178505 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -702,6 +702,16 @@ parse_parenthesized_lifetime_suggestion = remove the parentheses parse_path_double_colon = path separator must be a double colon .suggestion = use a double colon instead + +parse_path_found_attribute_in_params = `Trait(...)` syntax does not support attributes in parameters + .suggestion = remove the attributes + +parse_path_found_c_variadic_params = `Trait(...)` syntax does not support c_variadic parameters + .suggestion = remove the `...` + +parse_path_found_named_params = `Trait(...)` syntax does not support named parameters + .suggestion = remove the parameter name + parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies .suggestion = give this argument a name or use an underscore to ignore it diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6a6fb0eb9b5b..7bd78f77fa63 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1591,6 +1591,30 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { pub fn_token_span: Span, } +#[derive(Diagnostic)] +#[diag(parse_path_found_named_params)] +pub(crate) struct FnPathFoundNamedParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub named_param_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_path_found_c_variadic_params)] +pub(crate) struct PathFoundCVariadicParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_path_found_attribute_in_params)] +pub(crate) struct PathFoundAttributeInParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_path_double_colon)] pub(crate) struct PathSingleColon { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4be8a90368d2..babc55ccc0f9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2894,7 +2894,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(req_name, first_param).or_else(|e| { + let param = p.parse_param_general(req_name, first_param, true).or_else(|e| { let guar = e.emit(); // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. @@ -2922,7 +2922,13 @@ impl<'a> Parser<'a> { /// Parses a single function parameter. /// /// - `self` is syntactically allowed when `first_param` holds. - fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> { + /// - `recover_arg_parse` is used to recover from a failed argument parse. + pub(super) fn parse_param_general( + &mut self, + req_name: ReqName, + first_param: bool, + recover_arg_parse: bool, + ) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { @@ -2990,12 +2996,13 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), - // Recover from attempting to parse the argument as a type without pattern. - Err(err) => { + Err(err) if recover_arg_parse => { + // Recover from attempting to parse the argument as a type without pattern. err.cancel(); this.restore_snapshot(parser_snapshot_before_ty); this.recover_arg_parse()? } + Err(err) => return Err(err), } }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1093e4f4af0a..9bce2fa74caa 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -15,7 +15,11 @@ use tracing::debug; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::{self, PathSingleColon, PathTripleColon}; +use crate::ast::{PatKind, TyKind}; +use crate::errors::{ + self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams, + PathSingleColon, PathTripleColon, +}; use crate::exp; use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; @@ -396,7 +400,28 @@ impl<'a> Parser<'a> { snapshot = Some(self.create_snapshot_for_diagnostic()); } - let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) { + let dcx = self.dcx(); + let parse_params_result = self.parse_paren_comma_seq(|p| { + let param = p.parse_param_general(|_| false, false, false); + param.map(move |param| { + if !matches!(param.pat.kind, PatKind::Missing) { + dcx.emit_err(FnPathFoundNamedParams { + named_param_span: param.pat.span, + }); + } + if matches!(param.ty.kind, TyKind::CVarArgs) { + dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span }); + } + if !param.attrs.is_empty() { + dcx.emit_err(PathFoundAttributeInParams { + span: param.attrs[0].span, + }); + } + param.ty + }) + }); + + let (inputs, _) = match parse_params_result { Ok(output) => output, Err(mut error) if prev_token_before_parsing == token::PathSep => { error.span_label( diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs index fae5f6c15193..218450abd499 100644 --- a/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs @@ -1,6 +1,12 @@ -fn g(_: fn(a: u8)) {} -fn x(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` -fn y(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` -fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` +fn f1(_: fn(a: u8)) {} +fn f2(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters +fn f3(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters +fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} +//~^ ERROR `Trait(...)` syntax does not support named parameters +//~| ERROR `Trait(...)` syntax does not support named parameters +fn f5(_: impl Fn(u8, ...)) {} +//~^ ERROR `Trait(...)` syntax does not support c_variadic parameters +fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {} +//~^ ERROR `Trait(...)` syntax does not support attributes in parameters fn main(){} diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr index e599afb1345f..b72d5b7b3bc4 100644 --- a/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr @@ -1,20 +1,38 @@ -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - --> $DIR/fn-trait-use-named-params-issue-140169.rs:2:25 +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:2:22 | -LL | fn x(_: impl Fn(u8, vvvv: u8)) {} - | ^ expected one of 7 possible tokens +LL | fn f2(_: impl Fn(u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - --> $DIR/fn-trait-use-named-params-issue-140169.rs:3:21 +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:3:18 | -LL | fn y(_: impl Fn(aaaa: u8, u8)) {} - | ^ expected one of 7 possible tokens +LL | fn f3(_: impl Fn(aaaa: u8, u8)) {} + | ^^^^ help: remove the parameter name -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:21 +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:18 | -LL | fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} - | ^ expected one of 7 possible tokens +LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name -error: aborting due to 3 previous errors +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:28 + | +LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name + +error: `Trait(...)` syntax does not support c_variadic parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:7:22 + | +LL | fn f5(_: impl Fn(u8, ...)) {} + | ^^^ help: remove the `...` + +error: `Trait(...)` syntax does not support attributes in parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:9:22 + | +LL | fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attributes + +error: aborting due to 6 previous errors diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs index 6bfe16ae37d2..db25ce440893 100644 --- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs +++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs @@ -2,8 +2,10 @@ fn main() { unsafe { - dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - //~| NOTE while parsing this parenthesized list of type arguments starting here + dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR `Trait(...)` syntax does not support named parameters + //~^ ERROR cannot find function `dealloc` in this scope [E0425] + //~| ERROR cannot find value `ptr2` in this scope [E0425] + //~| ERROR the `!` type is experimental [E0658] + //~| ERROR cannot find function, tuple struct or tuple variant `Layout` in this scope [E0425] } } diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr index c12bf7f9e3f0..a083883af219 100644 --- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr +++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr @@ -1,16 +1,43 @@ -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:33 +error: `Trait(...)` syntax does not support named parameters + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:32 | LL | dealloc(ptr2, Layout::(x: !)(1, 1)); - | --- ^ expected one of 7 possible tokens - | | - | while parsing this parenthesized list of type arguments starting here + | ^ help: remove the parameter name -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:43 +error[E0425]: cannot find function `dealloc` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:9 | LL | dealloc(ptr2, Layout::(x: !)(1, 1)); - | ^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^^^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::alloc::dealloc; + | -error: aborting due to 2 previous errors +error[E0425]: cannot find value `ptr2` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:17 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^^^^ not found in this scope +error[E0658]: the `!` type is experimental + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:35 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0425]: cannot find function, tuple struct or tuple variant `Layout` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:23 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^^^^^^ not found in this scope + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index 1c28c0632fa8..60dd88e65400 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs @@ -2,7 +2,4 @@ struct Apple((Apple, Option(Banana ? Citron))); //~^ ERROR invalid `?` in type -//~| ERROR expected one of `)` or `,`, found `Citron` -//~| ERROR cannot find type `Citron` in this scope [E0412] -//~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214] -//~| ERROR `Apple` has infinite size +//~| ERROR unexpected token: `Citron` diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index 97a73b4fd5ed..c92535c3906b 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr @@ -10,44 +10,11 @@ LL - struct Apple((Apple, Option(Banana ? Citron))); LL + struct Apple((Apple, Option(Option Citron))); | -error: expected one of `)` or `,`, found `Citron` +error: unexpected token: `Citron` --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38 | LL | struct Apple((Apple, Option(Banana ? Citron))); - | -^^^^^^ expected one of `)` or `,` - | | - | help: missing `,` + | ^^^^^^ unexpected token after this -error[E0412]: cannot find type `Citron` in this scope - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^ not found in this scope +error: aborting due to 2 previous errors -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:22 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses - | -help: use angle brackets instead - | -LL - struct Apple((Apple, Option(Banana ? Citron))); -LL + struct Apple((Apple, Option)); - | - -error[E0072]: recursive type `Apple` has infinite size - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:1 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^^^^^^^ ----- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | struct Apple((Box, Option(Banana ? Citron))); - | ++++ + - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0072, E0214, E0412. -For more information about an error, try `rustc --explain E0072`. From 0de994a368e9225fab812a7295f9350285cd55d3 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sat, 10 May 2025 09:55:50 +0800 Subject: [PATCH 302/302] Warn when #[export_name] is used with generic functions --- compiler/rustc_lint/src/builtin.rs | 27 +-- .../ui/generics/export-name-on-generics.fixed | 157 +++++++++++++++++ tests/ui/generics/export-name-on-generics.rs | 159 ++++++++++++++++++ .../generics/export-name-on-generics.stderr | 144 ++++++++++++++++ 4 files changed, 477 insertions(+), 10 deletions(-) create mode 100644 tests/ui/generics/export-name-on-generics.fixed create mode 100644 tests/ui/generics/export-name-on-generics.rs create mode 100644 tests/ui/generics/export-name-on-generics.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 41b43f647986..95e31e4af1e3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -976,6 +976,9 @@ declare_lint! { /// ```rust /// #[unsafe(no_mangle)] /// fn foo(t: T) {} + /// + /// #[unsafe(export_name = "bar")] + /// fn bar(t: T) {} /// ``` /// /// {{produces}} @@ -983,10 +986,11 @@ declare_lint! { /// ### Explanation /// /// A function with generics must have its symbol mangled to accommodate - /// the generic parameter. The [`no_mangle` attribute] has no effect in - /// this situation, and should be removed. + /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes + /// have no effect in this situation, and should be removed. /// - /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -997,7 +1001,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); - let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute, + let check_no_mangle_on_generic_fn = |attr: &hir::Attribute, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, span| { @@ -1010,7 +1014,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() }, + BuiltinNoMangleGeneric { suggestion: attr.span() }, ); break; } @@ -1019,8 +1023,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { - check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + { + check_no_mangle_on_generic_fn(attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { @@ -1048,11 +1054,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = - attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle) + let attrs = cx.tcx.hir_attrs(it.id.hir_id()); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) { check_no_mangle_on_generic_fn( - no_mangle_attr, + attr, Some(generics), cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(), it.span, diff --git a/tests/ui/generics/export-name-on-generics.fixed b/tests/ui/generics/export-name-on-generics.fixed new file mode 100644 index 000000000000..4430cd9a2998 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.fixed @@ -0,0 +1,157 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.rs b/tests/ui/generics/export-name-on-generics.rs new file mode 100644 index 000000000000..cbf110219605 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.rs @@ -0,0 +1,159 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +#[export_name = "foo"] +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "bar"] +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "foo2"] + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.stderr b/tests/ui/generics/export-name-on-generics.stderr new file mode 100644 index 000000000000..7bc7b8ca5593 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.stderr @@ -0,0 +1,144 @@ +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:6:1 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/export-name-on-generics.rs:3:9 + | +LL | #![deny(no_mangle_generic_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:9:1 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:21:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:24:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:42:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:45:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:64:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:67:5 + | +LL | #[export_name = "foo2"] + | ----------------------- help: remove this attribute +LL | fn foo2() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:70:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:73:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz(x: &i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:76:5 + | +LL | #[export_name = "qux"] + | ---------------------- help: remove this attribute +LL | fn qux<'a>(x: &'a i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:83:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:86:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:89:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | pub fn baz() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:105:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:108:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:111:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz() {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors +