From 6bd68fcceb1d0708ce898fb92275119e2658d64b Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Sun, 14 Apr 2024 11:35:01 +0200 Subject: [PATCH 001/361] Run filecheck on dest-prop/branch.rs --- tests/mir-opt/dest-prop/branch.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dest-prop/branch.rs b/tests/mir-opt/dest-prop/branch.rs index cd5513072857..b1741bb2395c 100644 --- a/tests/mir-opt/dest-prop/branch.rs +++ b/tests/mir-opt/dest-prop/branch.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Tests that assignment in both branches of an `if` are eliminated. //@ unit-test: DestinationPropagation @@ -12,6 +11,10 @@ fn cond() -> bool { // EMIT_MIR branch.foo.DestinationPropagation.diff fn foo() -> i32 { + // CHECK-LABEL: fn foo( + // CHECK: debug y => [[y:_.*]]; + // CHECK: [[y]] = val() + // CHECK-NOT: [[y]] = {{_.*}}; let x = val(); let y = if cond() { From f238eba6211635d80ff0c31e7a89e2d38e528cfc Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Sun, 14 Apr 2024 11:35:23 +0200 Subject: [PATCH 002/361] Run filecheck on dest-prop/copy_propagation.rs --- .../mir-opt/dest-prop/copy_propagation_arg.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.rs b/tests/mir-opt/dest-prop/copy_propagation_arg.rs index f84b5fde8d88..2ea5c098ff40 100644 --- a/tests/mir-opt/dest-prop/copy_propagation_arg.rs +++ b/tests/mir-opt/dest-prop/copy_propagation_arg.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // Check that DestinationPropagation does not propagate an assignment to a function argument // (doing so can break usages of the original argument value) @@ -9,18 +8,29 @@ fn dummy(x: u8) -> u8 { // EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff fn foo(mut x: u8) { + // CHECK-LABEL: fn foo( + // CHECK: debug x => [[x:_.*]]; + // CHECK: dummy(move [[x]]) + // CHECK: [[x]] = move {{_.*}}; // calling `dummy` to make a use of `x` that copyprop cannot eliminate x = dummy(x); // this will assign a local to `x` } // EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff fn bar(mut x: u8) { + // CHECK-LABEL: fn bar( + // CHECK: debug x => [[x:_.*]]; + // CHECK: dummy(move [[x]]) + // CHECK: [[x]] = const 5_u8; dummy(x); x = 5; } // EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff fn baz(mut x: i32) -> i32 { + // CHECK-LABEL: fn baz( + // CHECK: debug x => [[x:_.*]]; + // CHECK-NOT: [[x]] = {{_.*}} // self-assignment to a function argument should be eliminated x = x; x @@ -28,6 +38,12 @@ fn baz(mut x: i32) -> i32 { // EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff fn arg_src(mut x: i32) -> i32 { + // CHECK-LABEL: fn arg_src( + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + // CHECK: [[y]] = [[x]] + // CHECK: [[x]] = const 123_i32; + // CHECK-NOT: {{_.*}} = [[y]]; let y = x; x = 123; // Don't propagate this assignment to `y` y From 853311c35811ea8a05baf97aae895b017b83cc23 Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Sun, 14 Apr 2024 11:35:37 +0200 Subject: [PATCH 003/361] Run filecheck on dest-prop/cycle.rs --- tests/mir-opt/dest-prop/cycle.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dest-prop/cycle.rs b/tests/mir-opt/dest-prop/cycle.rs index e6663956d782..41d9dd81253f 100644 --- a/tests/mir-opt/dest-prop/cycle.rs +++ b/tests/mir-opt/dest-prop/cycle.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code. //@ unit-test: DestinationPropagation @@ -8,6 +7,10 @@ fn val() -> i32 { // EMIT_MIR cycle.main.DestinationPropagation.diff fn main() { + // CHECK-LABEL: main( + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[x]] = val() + // CHECK-NOT: [[x]] = {{_.*}}; let mut x = val(); let y = x; let z = y; From 069209034dfdaf520dc14aa4f0bfab935da0032c Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Sun, 14 Apr 2024 11:35:55 +0200 Subject: [PATCH 004/361] Run filecheck on dest-prop/dead_stores_79191.rs and dead_stores_better.rs --- tests/mir-opt/dest-prop/dead_stores_79191.rs | 8 +++++++- tests/mir-opt/dest-prop/dead_stores_better.rs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.rs b/tests/mir-opt/dest-prop/dead_stores_79191.rs index b3e370966d05..85411b17569d 100644 --- a/tests/mir-opt/dest-prop/dead_stores_79191.rs +++ b/tests/mir-opt/dest-prop/dead_stores_79191.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ unit-test: DestinationPropagation @@ -8,6 +7,13 @@ fn id(x: T) -> T { // EMIT_MIR dead_stores_79191.f.DestinationPropagation.after.mir fn f(mut a: usize) -> usize { + // CHECK-LABEL: fn f( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: [[b]] = [[a]]; + // CHECK: [[a]] = const 5_usize; + // CHECK: [[a]] = move [[b]]; + // CHECK: id::(move [[a]]) let b = a; a = 5; a = b; diff --git a/tests/mir-opt/dest-prop/dead_stores_better.rs b/tests/mir-opt/dest-prop/dead_stores_better.rs index c241d71594ba..3d2af421bc23 100644 --- a/tests/mir-opt/dest-prop/dead_stores_better.rs +++ b/tests/mir-opt/dest-prop/dead_stores_better.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates // that that pass enables this one to do more optimizations. @@ -12,6 +11,13 @@ fn id(x: T) -> T { // EMIT_MIR dead_stores_better.f.DestinationPropagation.after.mir pub fn f(mut a: usize) -> usize { + // CHECK-LABEL: fn f( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: [[b]] = [[a]]; + // CHECK: [[a]] = const 5_usize; + // CHECK: [[a]] = move [[b]]; + // CHECK: id::(move [[a]]) let b = a; a = 5; a = b; From f0f867e2d3d220ae8a11bfe83d2545ec1a3a19d2 Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Sun, 14 Apr 2024 11:36:24 +0200 Subject: [PATCH 005/361] Run filecheck on dest-prop/simple.rs --- tests/mir-opt/dest-prop/simple.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dest-prop/simple.rs b/tests/mir-opt/dest-prop/simple.rs index 4aa6b6a4876e..203f44a38261 100644 --- a/tests/mir-opt/dest-prop/simple.rs +++ b/tests/mir-opt/dest-prop/simple.rs @@ -1,9 +1,12 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. //@ unit-test: DestinationPropagation // EMIT_MIR simple.nrvo.DestinationPropagation.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { + // CHECK-LABEL: fn nrvo( + // CHECK: debug init => [[init:_.*]]; + // CHECK-NOT: {{_.*}} = [[init]]; + // CHECK: move [[init]](move {{_.*}}) let mut buf = [0; 1024]; init(&mut buf); buf From 2df4f7dd8c51e1c3e65b615d1c44fdc9d0b4b044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 2 May 2024 01:15:40 +0000 Subject: [PATCH 006/361] Suggest borrowing on fn argument that is `impl AsRef` When encountering a move conflict, on an expression that is `!Copy` passed as an argument to an `fn` that is `impl AsRef`, suggest borrowing the expression. ``` error[E0382]: use of moved value: `bar` --> f204.rs:14:15 | 12 | let bar = Bar; | --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait 13 | foo(bar); | --- value moved here 14 | let baa = bar; | ^^^ value used here after move | help: borrow the value to avoid moving it | 13 | foo(&bar); | + ``` Fix #41708 --- .../src/diagnostics/conflict_errors.rs | 89 +++++++++++++++---- library/core/src/borrow.rs | 1 + .../ui/moves/moved-value-on-as-ref-arg.fixed | 37 ++++++++ tests/ui/moves/moved-value-on-as-ref-arg.rs | 37 ++++++++ .../ui/moves/moved-value-on-as-ref-arg.stderr | 79 ++++++++++++++++ 5 files changed, 224 insertions(+), 19 deletions(-) create mode 100644 tests/ui/moves/moved-value-on-as-ref-arg.fixed create mode 100644 tests/ui/moves/moved-value-on-as-ref-arg.rs create mode 100644 tests/ui/moves/moved-value-on-as-ref-arg.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6f0bd0543293..9efb3362e18e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -449,6 +449,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { (None, &[][..], 0) }; + let mut can_suggest_clone = true; if let Some(def_id) = def_id && let node = self.infcx.tcx.hir_node_by_def_id(def_id) && let Some(fn_sig) = node.fn_sig() @@ -456,24 +457,73 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this parameter takes ownership of the value".to_string(), - ); - let descr = match node.fn_kind() { - Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", - Some(hir::intravisit::FnKind::Method(..)) => "method", - Some(hir::intravisit::FnKind::Closure) => "closure", - }; - span.push_span_label(ident.span, format!("in this {descr}")); - err.span_note( - span, - format!( - "consider changing this parameter type in {descr} `{ident}` to borrow \ - instead if owning the value isn't necessary", - ), - ); + let mut is_mut = false; + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = arg.kind + && let Res::Def(DefKind::TyParam, param_def_id) = path.res + && self + .infcx + .tcx + .predicates_of(def_id) + .instantiate_identity(self.infcx.tcx) + .predicates + .into_iter() + .any(|pred| { + if let ty::ClauseKind::Trait(predicate) = pred.kind().skip_binder() + && [ + self.infcx.tcx.get_diagnostic_item(sym::AsRef), + self.infcx.tcx.get_diagnostic_item(sym::AsMut), + self.infcx.tcx.get_diagnostic_item(sym::Borrow), + self.infcx.tcx.get_diagnostic_item(sym::BorrowMut), + ] + .contains(&Some(predicate.def_id())) + && let ty::Param(param) = predicate.self_ty().kind() + && let generics = self.infcx.tcx.generics_of(def_id) + && let param = generics.type_param(*param, self.infcx.tcx) + && param.def_id == param_def_id + { + if [ + self.infcx.tcx.get_diagnostic_item(sym::AsMut), + self.infcx.tcx.get_diagnostic_item(sym::BorrowMut), + ] + .contains(&Some(predicate.def_id())) + { + is_mut = true; + } + true + } else { + false + } + }) + { + // The type of the argument corresponding to the expression that got moved + // is a type parameter `T`, which is has a `T: AsRef` obligation. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "borrow the value to avoid moving it", + format!("&{}", if is_mut { "mut " } else { "" }), + Applicability::MachineApplicable, + ); + can_suggest_clone = is_mut; + } else { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this parameter takes ownership of the value".to_string(), + ); + let descr = match node.fn_kind() { + Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", + Some(hir::intravisit::FnKind::Method(..)) => "method", + Some(hir::intravisit::FnKind::Closure) => "closure", + }; + span.push_span_label(ident.span, format!("in this {descr}")); + err.span_note( + span, + format!( + "consider changing this parameter type in {descr} `{ident}` to \ + borrow instead if owning the value isn't necessary", + ), + ); + } } let place = &self.move_data.move_paths[mpi].place; let ty = place.ty(self.body, self.infcx.tcx).ty; @@ -491,9 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)), .. } = move_spans + && can_suggest_clone { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); - } else if self.suggest_hoisting_call_outside_loop(err, expr) { + } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone { // The place where the type moves would be misleading to suggest clone. // #121466 self.suggest_cloning(err, ty, expr, None, Some(move_spans)); diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index bc026d0a4463..ccb1cc4e974d 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -184,6 +184,7 @@ pub trait Borrow { /// an underlying type by providing a mutable reference. See [`Borrow`] /// for more information on borrowing as another type. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "BorrowMut"] pub trait BorrowMut: Borrow { /// Mutably borrows from an owned value. /// diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.fixed b/tests/ui/moves/moved-value-on-as-ref-arg.fixed new file mode 100644 index 000000000000..292fa98a3f71 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.fixed @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(unused_mut)] +use std::borrow::{Borrow, BorrowMut}; +use std::convert::{AsMut, AsRef}; +struct Bar; + +impl AsRef for Bar { + fn as_ref(&self) -> &Bar { + self + } +} + +impl AsMut for Bar { + fn as_mut(&mut self) -> &mut Bar { + self + } +} + +fn foo>(_: T) {} +fn qux>(_: T) {} +fn bat>(_: T) {} +fn baz>(_: T) {} + +pub fn main() { + let bar = Bar; + foo(&bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + qux(&mut bar); + let _baa = bar; //~ ERROR use of moved value + let bar = Bar; + bat(&bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + baz(&mut bar); + let _baa = bar; //~ ERROR use of moved value +} diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.rs b/tests/ui/moves/moved-value-on-as-ref-arg.rs new file mode 100644 index 000000000000..632af9efcda3 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.rs @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(unused_mut)] +use std::borrow::{Borrow, BorrowMut}; +use std::convert::{AsMut, AsRef}; +struct Bar; + +impl AsRef for Bar { + fn as_ref(&self) -> &Bar { + self + } +} + +impl AsMut for Bar { + fn as_mut(&mut self) -> &mut Bar { + self + } +} + +fn foo>(_: T) {} +fn qux>(_: T) {} +fn bat>(_: T) {} +fn baz>(_: T) {} + +pub fn main() { + let bar = Bar; + foo(bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + qux(bar); + let _baa = bar; //~ ERROR use of moved value + let bar = Bar; + bat(bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + baz(bar); + let _baa = bar; //~ ERROR use of moved value +} diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.stderr b/tests/ui/moves/moved-value-on-as-ref-arg.stderr new file mode 100644 index 000000000000..4004b7a43bc0 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.stderr @@ -0,0 +1,79 @@ +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:27:16 + | +LL | let bar = Bar; + | --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | foo(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +help: borrow the value to avoid moving it + | +LL | foo(&bar); + | + + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:30:16 + | +LL | let mut bar = Bar; + | ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | qux(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +note: if `Bar` implemented `Clone`, you could clone the value + --> $DIR/moved-value-on-as-ref-arg.rs:5:1 + | +LL | struct Bar; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | qux(bar); + | --- you could clone this value +help: borrow the value to avoid moving it + | +LL | qux(&mut bar); + | ++++ + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:33:16 + | +LL | let bar = Bar; + | --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | bat(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +help: borrow the value to avoid moving it + | +LL | bat(&bar); + | + + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:36:16 + | +LL | let mut bar = Bar; + | ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | baz(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +note: if `Bar` implemented `Clone`, you could clone the value + --> $DIR/moved-value-on-as-ref-arg.rs:5:1 + | +LL | struct Bar; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | baz(bar); + | --- you could clone this value +help: borrow the value to avoid moving it + | +LL | baz(&mut bar); + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0382`. From a1ad6346d6a0df509d2615acbce9e443d202323a Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 10 May 2024 13:44:19 -0500 Subject: [PATCH 007/361] Add fn allocator method to rc/sync::Weak. Relax Rc/Arc::allocator to allow unsized T. --- library/alloc/src/rc.rs | 28 ++++++++++++++++++---------- library/alloc/src/sync.rs | 28 ++++++++++++++++++---------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c245b42c3e88..888bb7636c0b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -661,16 +661,6 @@ impl Rc { } impl Rc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } /// Constructs a new `Rc` in the provided allocator. /// /// # Examples @@ -1333,6 +1323,17 @@ impl Rc { } impl Rc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -2923,6 +2924,13 @@ impl Weak { } impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 297a273d274b..45ba13f69639 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -683,16 +683,6 @@ impl Arc { } impl Arc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } /// Constructs a new `Arc` in the provided allocator. /// /// # Examples @@ -1473,6 +1463,17 @@ impl Arc { } impl Arc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + /// Consumes the `Arc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Arc` using @@ -2661,6 +2662,13 @@ impl Weak { } impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, From 952becc0bdf814f194a42d34ea78fed792a1f760 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 2 Apr 2024 05:08:56 +0100 Subject: [PATCH 008/361] Ensure floats are returned losslessly by the Rust ABI on 32-bit x86 --- compiler/rustc_ty_utils/src/abi.rs | 34 ++ tests/assembly/x86-return-float.rs | 323 ++++++++++++++++++ .../ui/abi/numbers-arithmetic/return-float.rs | 57 ++++ 3 files changed, 414 insertions(+) create mode 100644 tests/assembly/x86-return-float.rs create mode 100644 tests/ui/abi/numbers-arithmetic/return-float.rs diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index c5ea85c90dc5..ca503dd16b99 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -744,6 +744,40 @@ fn fn_abi_adjust_for_abi<'tcx>( return; } + // Avoid returning floats in x87 registers on x86 as loading and storing from x87 + // registers will quiet signalling NaNs. + if cx.tcx.sess.target.arch == "x86" + && arg_idx.is_none() + // Intrinsics themselves are not actual "real" functions, so theres no need to + // change their ABIs. + && abi != SpecAbi::RustIntrinsic + { + match arg.layout.abi { + // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled + // below, by returning arguments up to the size of a pointer (32 bits on x86) + // cast to an appropriately sized integer. + Abi::Scalar(s) if s.primitive() == Float(F32) => { + // Same size as a pointer, return in a register. + arg.cast_to(Reg::i32()); + return; + } + Abi::Scalar(s) if s.primitive() == Float(F64) => { + // Larger than a pointer, return indirectly. + arg.make_indirect(); + return; + } + Abi::ScalarPair(s1, s2) + if matches!(s1.primitive(), Float(F32 | F64)) + || matches!(s2.primitive(), Float(F32 | F64)) => + { + // Larger than a pointer, return indirectly. + arg.make_indirect(); + return; + } + _ => {} + }; + } + match arg.layout.abi { Abi::Aggregate { .. } => {} diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs new file mode 100644 index 000000000000..270aea2475f0 --- /dev/null +++ b/tests/assembly/x86-return-float.rs @@ -0,0 +1,323 @@ +//@ assembly-output: emit-asm +//@ only-x86 +// Force frame pointers to make ASM more consistent between targets +//@ compile-flags: -O -C force-frame-pointers +//@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst +//@ revisions: unix windows +//@[unix] ignore-windows +//@[windows] only-windows + +#![crate_type = "lib"] +#![feature(f16, f128)] + +// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87 +// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens +// signalling NaNs. + +// Returning individual floats + +// CHECK-LABEL: return_f32: +#[no_mangle] +pub fn return_f32(x: f32) -> f32 { + // CHECK: movl {{.*}}(%ebp), %eax + // CHECK-NOT: ax + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64: +#[no_mangle] +pub fn return_f64(x: f64) -> f64 { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL:.*]] + // CHECK-NEXT: movsd %[[VAL]], (%[[PTR]]) + // CHECK: retl + x +} + +// Returning scalar pairs containing floats + +// CHECK-LABEL: return_f32_f32: +#[no_mangle] +pub fn return_f32_f32(x: (f32, f32)) -> (f32, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f64: +#[no_mangle] +pub fn return_f64_f64(x: (f64, f64)) -> (f64, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_f64: +#[no_mangle] +pub fn return_f32_f64(x: (f32, f64)) -> (f32, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f32: +#[no_mangle] +pub fn return_f64_f32(x: (f64, f32)) -> (f64, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_other: +#[no_mangle] +pub fn return_f32_other(x: (f32, usize)) -> (f32, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_other: +#[no_mangle] +pub fn return_f64_other(x: (f64, usize)) -> (f64, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f32: +#[no_mangle] +pub fn return_other_f32(x: (usize, f32)) -> (usize, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f64: +#[no_mangle] +pub fn return_other_f64(x: (usize, f64)) -> (usize, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// Calling functions returning floats + +// CHECK-LABEL: call_f32: +#[no_mangle] +pub unsafe fn call_f32(x: &mut f32) { + extern "Rust" { + fn get_f32() -> f32; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32 + // CHECK-NEXT: movl %eax, (%[[PTR]]) + *x = get_f32(); +} + +// CHECK-LABEL: call_f64: +#[no_mangle] +pub unsafe fn call_f64(x: &mut f64) { + extern "Rust" { + fn get_f64() -> f64; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64 + // CHECK: movsd {{.*}}(%{{ebp|esp}}), %[[VAL:.*]] + // CHECK-NEXT: movsd %[[VAL:.*]], (%[[PTR]]) + *x = get_f64(); +} + +// Calling functions returning scalar pairs containing floats + +// CHECK-LABEL: call_f32_f32: +#[no_mangle] +pub unsafe fn call_f32_f32(x: &mut (f32, f32)) { + extern "Rust" { + fn get_f32_f32() -> (f32, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f32 + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_f32(); +} + +// CHECK-LABEL: call_f64_f64: +#[no_mangle] +pub unsafe fn call_f64_f64(x: &mut (f64, f64)) { + extern "Rust" { + fn get_f64_f64() -> (f64, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f64 + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f64(); +} + +// CHECK-LABEL: call_f32_f64: +#[no_mangle] +pub unsafe fn call_f32_f64(x: &mut (f32, f64)) { + extern "Rust" { + fn get_f32_f64() -> (f32, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f64 + // unix: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // windows: movss (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f32_f64(); +} + +// CHECK-LABEL: call_f64_f32: +#[no_mangle] +pub unsafe fn call_f64_f32(x: &mut (f64, f32)) { + extern "Rust" { + fn get_f64_f32() -> (f64, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f32 + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movss 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f32(); +} + +// CHECK-LABEL: call_f32_other: +#[no_mangle] +pub unsafe fn call_f32_other(x: &mut (f32, usize)) { + extern "Rust" { + fn get_f32_other() -> (f32, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_other + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_other(); +} + +// CHECK-LABEL: call_f64_other: +#[no_mangle] +pub unsafe fn call_f64_other(x: &mut (f64, usize)) { + extern "Rust" { + fn get_f64_other() -> (f64, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_other + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movl 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_other(); +} + +// CHECK-LABEL: call_other_f32: +#[no_mangle] +pub unsafe fn call_other_f32(x: &mut (usize, f32)) { + extern "Rust" { + fn get_other_f32() -> (usize, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f32 + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_other_f32(); +} + +// CHECK-LABEL: call_other_f64: +#[no_mangle] +pub unsafe fn call_other_f64(x: &mut (usize, f64)) { + extern "Rust" { + fn get_other_f64() -> (usize, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f64 + // unix: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // windows: movl (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_other_f64(); +} + +// The "C" ABI for `f16` and `f128` on x86 has never used the x87 floating point stack. Do some +// basic checks to ensure this remains the case for the "Rust" ABI. + +// CHECK-LABEL: return_f16: +#[no_mangle] +pub fn return_f16(x: f16) -> f16 { + // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0 + // CHECK-NOT: xmm0 + // CHECK: retl + x +} + +// CHECK-LABEL: return_f128: +#[no_mangle] +pub fn return_f128(x: f128) -> f128 { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]] + // CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]]) + // CHECK: retl + x +} diff --git a/tests/ui/abi/numbers-arithmetic/return-float.rs b/tests/ui/abi/numbers-arithmetic/return-float.rs new file mode 100644 index 000000000000..3b025b763f13 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/return-float.rs @@ -0,0 +1,57 @@ +//@ run-pass +//@ compile-flags: -Copt-level=0 + +// Test that floats (in particular signalling NaNs) are losslessly returned from functions. + +fn main() { + let bits_f32 = std::hint::black_box([ + 4.2_f32.to_bits(), + f32::INFINITY.to_bits(), + f32::NEG_INFINITY.to_bits(), + f32::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the other + // is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f32/tests.rs + f32::NAN.to_bits() ^ 0x002A_AAAA, + f32::NAN.to_bits() ^ 0x0055_5555, + // Same as above but with the sign bit flipped. + f32::NAN.to_bits() ^ 0x802A_AAAA, + f32::NAN.to_bits() ^ 0x8055_5555, + ]); + for bits in bits_f32 { + assert_eq!(identity(f32::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f32::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f32::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f32::from_bits(bits), f32::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } + + let bits_f64 = std::hint::black_box([ + 4.2_f64.to_bits(), + f64::INFINITY.to_bits(), + f64::NEG_INFINITY.to_bits(), + f64::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the other + // is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f64/tests.rs + f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x0005_5555_5555_5555, + // Same as above but with the sign bit flipped. + f64::NAN.to_bits() ^ 0x800A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x8005_5555_5555_5555, + ]); + for bits in bits_f64 { + assert_eq!(identity(f64::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f64::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f64::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f64::from_bits(bits), f64::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } +} + +#[inline(never)] +fn identity(x: T) -> T { + x +} From 0e1c832dbd08c90497d46978eda7da5acd467c4e Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 13 Apr 2024 01:48:22 +0100 Subject: [PATCH 009/361] Update `platform-support.md` to reflect improvements in returning floats on 32-bit x86 --- src/doc/rustc/src/platform-support.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 77859956c95f..0f2fb3d364dc 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -41,10 +41,10 @@ target | notes `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) -[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue]. +[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. [77071]: https://github.com/rust-lang/rust/issues/77071 -[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479 +[x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567 ## Tier 1 @@ -207,6 +207,8 @@ target | std | notes [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. +[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479 + [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607 [Fortanix ABI]: https://edp.fortanix.com/ From 0eb9f41a07ae7087d7f9ce557cbfcaa2b173c95a Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 08:43:44 +0700 Subject: [PATCH 010/361] make it more readable by faster early exitting --- clippy_lints/src/no_effect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 87f886b1128d..dc017fa66348 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -258,10 +258,10 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind + && !in_external_macro(cx.sess(), stmt.span) && let ctxt = stmt.span.ctxt() && expr.span.ctxt() == ctxt && let Some(reduced) = reduce_expression(cx, expr) - && !in_external_macro(cx.sess(), stmt.span) && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { From aff0e6d6d3aec4ce29af95a4dcf615650f1c5e4d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 09:24:54 +0700 Subject: [PATCH 011/361] add uitest for indexing in unnecessary const items --- tests/ui/unnecessary_operation.fixed | 13 ++++++++++++- tests/ui/unnecessary_operation.rs | 13 ++++++++++++- tests/ui/unnecessary_operation.stderr | 20 +++++++++++++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 11761c6c90e3..e54491ab0235 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -113,4 +113,15 @@ fn main() { 'label: { break 'label }; + let () = const { + assert!([42, 55].len() > get_usize()); + }; +} + +const _: () = { + assert!([42, 55].len() > get_usize()); +}; + +const fn foo() { + assert!([42, 55].len() > get_usize()); } diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index de0081289ac3..679d303f3ad9 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -117,4 +117,15 @@ fn main() { 'label: { break 'label }; + let () = const { + [42, 55][get_usize()]; + }; +} + +const _: () = { + [42, 55][get_usize()]; +}; + +const fn foo() { + [42, 55][get_usize()]; } diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index 27be5e6f4b92..3c031d006d42 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -119,5 +119,23 @@ LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` -error: aborting due to 19 previous errors +error: unnecessary operation + --> tests/ui/unnecessary_operation.rs:121:9 + | +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:126: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:130:5 + | +LL | [42, 55][get_usize()]; + | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` + +error: aborting due to 22 previous errors From b161dc659c87df29cc9738a49105124ab30638e8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 09:54:42 +0700 Subject: [PATCH 012/361] add utils is_inside_always_const_context --- clippy_lints/src/default_numeric_fallback.rs | 2 ++ clippy_utils/src/lib.rs | 31 ++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index fbc4ede37b1c..51252f59db47 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { let hir = cx.tcx.hir(); + // NOTE: this is different from `clippy_utils::is_inside_always_const_context`. + // Inline const supports type inference. let is_parent_const = matches!( hir.body_const_context(hir.body_owner_def_id(body.id())), Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index bd0911d5268f..8185a523f1ff 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -100,10 +100,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, - ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, - ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, - PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, + PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -208,7 +208,10 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool { false } -/// Returns `true` if the given `NodeId` is inside a constant context +/// Returns `true` if the given `HirId` is inside a constant context. +/// +/// This is the same as `is_inside_always_const_context`, but also includes +/// `const fn`. /// /// # Example /// @@ -221,6 +224,24 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx.hir().is_inside_const_context(id) } +/// Returns `true` if the given `HirId` is inside an always constant context. +/// +/// This context includes: +/// * const/static items +/// * const blocks (or inline consts) +/// * associated constants +pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + use ConstContext::{Const, ConstFn, Static}; + let hir = tcx.hir(); + let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else { + return false; + }; + match ctx { + ConstFn => false, + Static(_) | Const { inline: _ } => true, + } +} + /// Checks if a `Res` refers to a constructor of a `LangItem` /// For example, use this to check whether a function call or a pattern is `Some(..)`. pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool { From 2c61b4557688aca993f59d2170673e86c4df9101 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 03:25:58 +0000 Subject: [PATCH 013/361] do not lint on indexing inside const contexts --- clippy_lints/src/no_effect.rs | 7 ++++++- tests/ui/unnecessary_operation.fixed | 4 ++-- tests/ui/unnecessary_operation.stderr | 14 +------------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index dc017fa66348..139c33d3f4a4 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; -use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks}; +use clippy_utils::{ + any_parent_is_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ @@ -265,6 +267,9 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { + if is_inside_always_const_context(cx.tcx, expr.hir_id) { + return; + } let snippet = if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { format!("assert!({}.len() > {});", &arr, &func) diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index e54491ab0235..5a3c49626a1c 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -114,12 +114,12 @@ fn main() { break 'label }; let () = const { - assert!([42, 55].len() > get_usize()); + [42, 55][get_usize()]; }; } const _: () = { - assert!([42, 55].len() > get_usize()); + [42, 55][get_usize()]; }; const fn foo() { diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index 3c031d006d42..036a9a44bbad 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -119,23 +119,11 @@ LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` -error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:121:9 - | -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:126: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:130:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` -error: aborting due to 22 previous errors +error: aborting due to 20 previous errors From e18b27aa2a37fb7597c16f72a55f26bde6badf51 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 10:37:19 +0700 Subject: [PATCH 014/361] add uitest for issue 12816 --- tests/ui/assertions_on_constants.rs | 6 ++++++ tests/ui/assertions_on_constants.stderr | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index 1309ae45d0ae..2e0fee08a595 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -53,3 +53,9 @@ fn main() { const N: usize = 1024; const _: () = assert!(N.is_power_of_two()); } + +#[allow(clippy::eq_op)] +const _: () = { + assert!(true); + assert!(8 == (7 + 1)); +}; diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 00f117c94920..3a64f1892ad9 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -80,5 +80,21 @@ LL | const _: () = assert!(true); | = help: remove it -error: aborting due to 10 previous errors +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:59:5 + | +LL | assert!(true); + | ^^^^^^^^^^^^^ + | + = help: remove it + +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:60:5 + | +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove it + +error: aborting due to 12 previous errors From ac600282a0cc35bd99b3e3152a655991d3c1dfea Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 24 May 2024 10:51:15 +0700 Subject: [PATCH 015/361] ignore `assertions-on-constants` in const contexts --- clippy_lints/src/assertions_on_constants.rs | 5 ++++ tests/ui/assertions_on_constants.rs | 1 - tests/ui/assertions_on_constants.stderr | 26 +-------------------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2003dd1fb0e2..863c25aba861 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::{constant_with_source, Constant, ConstantSource}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_inside_always_const_context; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; use rustc_hir::{Expr, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -31,6 +32,10 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if is_inside_always_const_context(cx.tcx, e.hir_id) { + return; + } + let Some(macro_call) = root_macro_call_first_node(cx, e) else { return; }; diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index 2e0fee08a595..c3574b0b466c 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -47,7 +47,6 @@ fn main() { assert!(!CFG_FLAG); const _: () = assert!(true); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 3a64f1892ad9..aa4868af5a8c 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -72,29 +72,5 @@ LL | debug_assert!(true); | = help: remove it -error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:49:19 - | -LL | const _: () = assert!(true); - | ^^^^^^^^^^^^^ - | - = help: remove it - -error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:59:5 - | -LL | assert!(true); - | ^^^^^^^^^^^^^ - | - = help: remove it - -error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:60:5 - | -LL | assert!(8 == (7 + 1)); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove it - -error: aborting due to 12 previous errors +error: aborting due to 9 previous errors From a0234b4e8b8c58a8726ec64828c7144c910faf67 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 8 Jun 2024 09:39:17 +0000 Subject: [PATCH 016/361] Ignore non ExprKind::{Path,Lit) inside const context - remove now dead code in ASSERTIONS_ON_CONSTANTS cc #11966 - Partially revert "ignore `assertions-on-constants` in const contexts" This reverts commit c7074de420a2192fb40d3f2194a20dd0d1b65cc6. --- clippy_lints/src/assertions_on_constants.rs | 23 +++++++----------- tests/ui/assertions_on_constants.rs | 8 +++++-- tests/ui/assertions_on_constants.stderr | 26 ++++++++++++++++++++- tests/ui/unnecessary_operation.fixed | 1 + tests/ui/unnecessary_operation.rs | 1 + 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 863c25aba861..ed4cdce8cb88 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,8 +1,8 @@ -use clippy_utils::consts::{constant_with_source, Constant, ConstantSource}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_inside_always_const_context; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; -use rustc_hir::{Expr, Item, ItemKind, Node}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -32,10 +32,6 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if is_inside_always_const_context(cx.tcx, e.hir_id) { - return; - } - let Some(macro_call) = root_macro_call_first_node(cx, e) else { return; }; @@ -47,17 +43,16 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return; }; - let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else { + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return; }; - if let ConstantSource::Constant = source - && let Node::Item(Item { - kind: ItemKind::Const(..), - .. - }) = cx.tcx.parent_hir_node(e.hir_id) - { - return; + + match condition.kind { + ExprKind::Path(..) | ExprKind::Lit(_) => {}, + _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return, + _ => {}, } + if val { span_lint_and_help( cx, diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index c3574b0b466c..957154e60dec 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -1,4 +1,4 @@ -#![allow(non_fmt_panics, clippy::needless_bool)] +#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)] macro_rules! assert_const { ($len:expr) => { @@ -47,14 +47,18 @@ fn main() { assert!(!CFG_FLAG); const _: () = assert!(true); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler + + assert!(8 == (7 + 1)); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; const _: () = assert!(N.is_power_of_two()); } -#[allow(clippy::eq_op)] const _: () = { assert!(true); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler assert!(8 == (7 + 1)); }; diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index aa4868af5a8c..e164a999c43e 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -72,5 +72,29 @@ LL | debug_assert!(true); | = help: remove it -error: aborting due to 9 previous errors +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:49:19 + | +LL | const _: () = assert!(true); + | ^^^^^^^^^^^^^ + | + = help: remove it + +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:52:5 + | +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove it + +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:61:5 + | +LL | assert!(true); + | ^^^^^^^^^^^^^ + | + = help: remove it + +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 5a3c49626a1c..006f123cbcdf 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -124,4 +124,5 @@ const _: () = { const fn foo() { assert!([42, 55].len() > get_usize()); + //~^ ERROR: unnecessary operation } diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 679d303f3ad9..b4067c740741 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -128,4 +128,5 @@ const _: () = { const fn foo() { [42, 55][get_usize()]; + //~^ ERROR: unnecessary operation } From ed9ccf66e9b61406176d57499e91c3bf773e95da Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 20 Jun 2024 00:09:31 +0200 Subject: [PATCH 017/361] [`unnecessary_to_owned`]: catch to_owned from byte slice to string --- .../src/methods/unnecessary_to_owned.rs | 70 ++++++++++++++++++- clippy_utils/src/paths.rs | 1 + tests/ui/unnecessary_to_owned.fixed | 19 +++++ tests/ui/unnecessary_to_owned.rs | 19 +++++ tests/ui/unnecessary_to_owned.stderr | 60 ++++++++++++---- 5 files changed, 154 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index ae9aa83efd68..5d899415d772 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,13 +1,15 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, }; 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, return_ty}; +use clippy_utils::{ + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -52,6 +54,9 @@ pub fn check<'tcx>( if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { return; } + if check_string_from_utf8(cx, expr, receiver) { + return; + } check_other_call_arg(cx, expr, method_name, receiver); } } else { @@ -240,6 +245,65 @@ fn check_into_iter_call_arg( false } +/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`, +/// which can be written as just `std::str::from_utf8(bytes).unwrap()`. +fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool { + if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr) + && !arg.span.from_expansion() + && let ExprKind::Call(callee, _) = call.kind + && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8)) + && let Some(unwrap_call) = get_parent_expr(cx, call) + && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind + && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect) + && let Some(ref_string) = get_parent_expr(cx, unwrap_call) + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind + && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string) + // `&...` creates a `&String`, so only actually lint if this coerces to a `&str` + && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) + { + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + ref_string.span, + "allocating a new `String` only to create a temporary `&str` from it", + |diag| { + let arg_suggestion = format!( + "{borrow}{recv_snippet}", + recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."), + borrow = if cx.typeck_results().expr_ty(receiver).is_ref() { + "" + } else { + // If not already a reference, prefix with a borrow so that it can coerce to one + "&" + } + ); + + diag.multipart_suggestion( + "convert from `&[u8]` to `&str` directly", + vec![ + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^^^^ + (callee.span, "core::str::from_utf8".into()), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^ + ( + ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()), + String::new(), + ), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^ + (arg.span, arg_suggestion), + ], + Applicability::MachineApplicable, + ); + }, + ); + true + } else { + false + } +} + /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9bf068ee3cde..bf72194f370c 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern" pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; +pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 1afa5ab54c46..fdcac8fb08dc 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x")); require_str(&String::from("x")); require_slice(&[String::from("x")]); + + let slice = [0u8; 1024]; + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index aa88dde43bf6..10a9727a9a79 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x").to_path_buf()); require_str(&String::from("x").to_string()); require_slice(&[String::from("x")].to_owned()); + + let slice = [0u8; 1024]; + let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 2829f3cd6e98..511b4ae119f8 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -477,8 +477,44 @@ error: unnecessary use of `to_owned` LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:162:26 + | +LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); +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:163:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); +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:164:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); +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:202:14 + --> tests/ui/unnecessary_to_owned.rs:221:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,64 +530,64 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:225:14 + --> tests/ui/unnecessary_to_owned.rs:244:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:230:14 + --> tests/ui/unnecessary_to_owned.rs:249:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:278:24 + --> tests/ui/unnecessary_to_owned.rs:297:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:387:12 + --> tests/ui/unnecessary_to_owned.rs:406:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:530:37 + --> tests/ui/unnecessary_to_owned.rs:549:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:540:18 + --> tests/ui/unnecessary_to_owned.rs:559:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:544:14 + --> tests/ui/unnecessary_to_owned.rs:563:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:545:14 + --> tests/ui/unnecessary_to_owned.rs:564:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:550:14 + --> tests/ui/unnecessary_to_owned.rs:569: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:551:14 + --> tests/ui/unnecessary_to_owned.rs:570:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 85 previous errors +error: aborting due to 88 previous errors From e71d06be1079db18c39b7088414380d94ce5a8f4 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 18 Jun 2024 12:43:06 -0500 Subject: [PATCH 018/361] On `target_os = "linux"`, ensure that only one Rust thread calls `libc::exit` or returns from `main`. --- library/std/src/rt.rs | 3 + library/std/src/sys/pal/common/exit_guard.rs | 88 ++++++++++++++++++++ library/std/src/sys/pal/common/mod.rs | 1 + library/std/src/sys/pal/unix/os.rs | 1 + 4 files changed, 93 insertions(+) create mode 100644 library/std/src/sys/pal/common/exit_guard.rs diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index b03fa1c01f26..376bf3440693 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -161,5 +161,8 @@ fn lang_start( argv, sigpipe, ); + // Guard against multple threads calling `libc::exit` concurrently. + // See the documentation for `unique_thread_exit` for more information. + crate::sys::common::exit_guard::unique_thread_exit(); v } diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs new file mode 100644 index 000000000000..3a0398a65983 --- /dev/null +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -0,0 +1,88 @@ +cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + /// Mitigation for https://github.com/rust-lang/rust/issues/126600 + /// + /// On `unix` (where `libc::exit` may not be thread-safe), ensure that only one Rust thread + /// calls `libc::exit` (or returns from `main`) by calling this function before calling + /// `libc::exit` (or returning from `main`). + /// + /// Technically not enough to ensure soundness, since other code directly calling + /// libc::exit will still race with this. + /// + /// *This function does not itself call `libc::exit`.* This is so it can also be used + /// to guard returning from `main`. + /// + /// This function will return only the first time it is called in a process. + /// + /// * If it is called again on the same thread as the first call, it will abort. + /// * If it is called again on a different thread, it will `thread::park()` in a loop + /// (waiting for the process to exit). + pub(crate) fn unique_thread_exit() { + let this_thread_id = unsafe { libc::gettid() }; + debug_assert_ne!(this_thread_id, 0, "thread ID cannot be zero"); + #[cfg(target_has_atomic = "32")] + { + use crate::sync::atomic::{AtomicI32, Ordering}; + static EXITING_THREAD_ID: AtomicI32 = AtomicI32::new(0); + match EXITING_THREAD_ID.compare_exchange( + 0, + this_thread_id, + Ordering::Relaxed, + Ordering::Relaxed, + ) { + Ok(_zero) => { + // 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 (done by the + // compare_exchange) and return. + } + Err(id) if 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") + } + Err(_) => { + // This is not the first thread to call `unique_thread_exit`. + // Park until the process exits. + loop { + crate::thread::park(); + } + } + } + } + #[cfg(not(target_has_atomic = "32"))] + { + use crate::sync::{Mutex, PoisonError}; + static EXITING_THREAD_ID: Mutex = Mutex::new(0); + let mut exiting_thread_id = + EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); + if *exiting_thread_id == 0 { + // 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 = this_thread_id; + } else 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") + } else { + // This is not the first thread to call `unique_thread_exit`. + // Park until the process exits. + drop(exiting_thread_id); + loop { + crate::thread::park(); + } + } + } + } + } else { + /// Mitigation for https://github.com/rust-lang/rust/issues/126600 + /// + /// Mitigation is ***NOT*** implemented on this platform, either because this platform is not affected, or because mitigation is not yet implemented for this platform. + pub(crate) fn unique_thread_exit() { + // Mitigation not required on platforms where `exit` is thread-safe. + } + } +} diff --git a/library/std/src/sys/pal/common/mod.rs b/library/std/src/sys/pal/common/mod.rs index 29fc0835d766..cc1dceb63e2f 100644 --- a/library/std/src/sys/pal/common/mod.rs +++ b/library/std/src/sys/pal/common/mod.rs @@ -11,6 +11,7 @@ #![allow(dead_code)] pub mod alloc; +pub mod exit_guard; pub mod small_c_string; #[cfg(test)] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 2e71ceceb58b..3f598a095c15 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -758,6 +758,7 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { + crate::sys::common::exit_guard::unique_thread_exit(); unsafe { libc::exit(code as c_int) } } From bff35313972b0d3e248a39cf5a2d03d916ba56d2 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 20 Jun 2024 22:18:46 -0500 Subject: [PATCH 019/361] fix rustdoc URL --- library/std/src/sys/pal/common/exit_guard.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index 3a0398a65983..49d3b4a96f07 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -1,6 +1,6 @@ cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - /// Mitigation for https://github.com/rust-lang/rust/issues/126600 + /// Mitigation for /// /// On `unix` (where `libc::exit` may not be thread-safe), ensure that only one Rust thread /// calls `libc::exit` (or returns from `main`) by calling this function before calling @@ -78,9 +78,10 @@ cfg_if::cfg_if! { } } } else { - /// Mitigation for https://github.com/rust-lang/rust/issues/126600 + /// Mitigation for /// - /// Mitigation is ***NOT*** implemented on this platform, either because this platform is not affected, or because mitigation is not yet implemented for this platform. + /// Mitigation is ***NOT*** implemented on this platform, either because this platform + /// is not affected, or because mitigation is not yet implemented for this platform. pub(crate) fn unique_thread_exit() { // Mitigation not required on platforms where `exit` is thread-safe. } From dcb6a54b80543ff0021d1b79e3c51d79b65ca468 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Fri, 21 Jun 2024 12:03:40 +0800 Subject: [PATCH 020/361] fix wrong msrv import in `new_lint` template --- clippy_dev/src/new_lint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 2e56eb8ec15f..d762e30ef02e 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _: fmt::Result = writedoc!( lint_file_contents, r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; From c36fdeb9a3da04839e0892e1351286881c848e39 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 20 Jun 2024 23:19:18 -0500 Subject: [PATCH 021/361] Don't perform mitigation for thread-unsafe libc::exit under Miri. 1. Miri's exit is thread-safe 2. Miri doesn't (yet) support `libc::gettid`, used in the implementation of the mitigation on Linux. --- library/std/src/sys/pal/common/exit_guard.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index 49d3b4a96f07..37c8f97e45d9 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -1,5 +1,13 @@ cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { + if #[cfg(miri)] { + /// Mitigation for + /// + /// This mitigation is not necessary when running under Miri, so this function does nothing + /// when running under Miri. + pub(crate) fn unique_thread_exit() { + // Mitigation not required on Miri, where `exit` is thread-safe. + } + } else if #[cfg(target_os = "linux")] { /// Mitigation for /// /// On `unix` (where `libc::exit` may not be thread-safe), ensure that only one Rust thread From 625091d2368e3f0f6d0127b27b183d5d855c4d08 Mon Sep 17 00:00:00 2001 From: John Arundel Date: Sun, 23 Jun 2024 12:21:10 +0100 Subject: [PATCH 022/361] Fix doc nits --- clippy_lints/src/await_holding_invalid.rs | 46 +++---- clippy_lints/src/casts/mod.rs | 113 +++++++++--------- clippy_lints/src/endian_bytes.rs | 4 +- clippy_lints/src/methods/mod.rs | 8 +- clippy_lints/src/same_name_method.rs | 2 +- .../await_holding_invalid_type.stderr | 6 +- tests/ui/await_holding_lock.rs | 26 ++-- tests/ui/await_holding_lock.stderr | 78 ++++++------ tests/ui/await_holding_refcell_ref.rs | 12 +- tests/ui/await_holding_refcell_ref.stderr | 24 ++-- 10 files changed, 163 insertions(+), 156 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index f25a474d9bbd..dac1f4ed404a 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -11,21 +11,25 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a non-async-aware MutexGuard. + /// Checks for calls to `await` while holding a non-async-aware + /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in std::sync and parking_lot - /// are not designed to operate in an async context across await points. + /// The Mutex types found in [`std::sync`] and + /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are + /// not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an async-aware Mutex - /// type. Many asynchronous foundation crates provide such a Mutex type. The - /// other solution is to ensure the mutex is unlocked before calling await, - /// either by introducing a scope or an explicit call to Drop::drop. + /// There are two potential solutions. One is to use an async-aware `Mutex` + /// type. Many asynchronous foundation crates provide such a `Mutex` type. + /// The other solution is to ensure the mutex is unlocked before calling + /// `await`, either by introducing a scope or an explicit call to + /// [`Drop::drop`]. /// /// ### Known problems /// Will report false positive for explicitly dropped guards - /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is - /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A + /// workaround for this is to wrap the `.lock()` call in a block instead of + /// explicitly dropping the guard. /// /// ### Example /// ```no_run @@ -73,11 +77,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`. /// /// ### Why is this bad? /// `RefCell` refs only check for exclusive mutable access - /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point + /// at runtime. Holding a `RefCell` ref across an await suspension point /// risks panics from a mutable ref shared while other refs are outstanding. /// /// ### Known problems @@ -131,13 +135,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Allows users to configure types which should not be held across `await` + /// Allows users to configure types which should not be held across await /// suspension points. /// /// ### Why is this bad? - /// There are some types which are perfectly "safe" to be used concurrently - /// from a memory access perspective but will cause bugs at runtime if they - /// are held in such a way. + /// There are some types which are perfectly safe to use concurrently from + /// a memory access perspective, but that will cause bugs at runtime if + /// they are held in such a way. /// /// ### Example /// @@ -228,15 +232,15 @@ impl AwaitHolding { cx, AWAIT_HOLDING_LOCK, ty_cause.source_info.span, - "this `MutexGuard` is held across an `await` point", + "this `MutexGuard` is held across an await point", |diag| { diag.help( "consider using an async-aware `Mutex` type or ensuring the \ - `MutexGuard` is dropped before calling await", + `MutexGuard` is dropped before calling `await`", ); diag.span_note( await_points(), - "these are all the `await` points this lock is held through", + "these are all the await points this lock is held through", ); }, ); @@ -245,12 +249,12 @@ impl AwaitHolding { cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.source_info.span, - "this `RefCell` reference is held across an `await` point", + "this `RefCell` reference is held across an await point", |diag| { diag.help("ensure the reference is dropped before calling `await`"); diag.span_note( await_points(), - "these are all the `await` points this reference is held through", + "these are all the await points this reference is held through", ); }, ); @@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa AWAIT_HOLDING_INVALID_TYPE, span, format!( - "`{}` may not be held across an `await` point per `clippy.toml`", + "`{}` may not be held across an await point per `clippy.toml`", disallowed.path() ), |diag| { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index e60c36ced75d..d8bae3b48bf4 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for casts from any numerical to a float type where + /// Checks for casts from any numeric type to a float type where /// the receiving type cannot store all values from the original type without /// rounding errors. This possible rounding is to be expected, so this lint is /// `Allow` by default. @@ -58,14 +58,14 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts from a signed to an unsigned numerical + /// Checks for casts from a signed to an unsigned numeric /// type. In this case, negative values wrap around to large positive values, - /// which can be quite surprising in practice. However, as the cast works as + /// which can be quite surprising in practice. However, since the cast works as /// defined, this lint is `Allow` by default. /// /// ### Why is this bad? /// Possibly surprising results. You can activate this lint - /// as a one-time check to see where numerical wrapping can arise. + /// as a one-time check to see where numeric wrapping can arise. /// /// ### Example /// ```no_run @@ -80,7 +80,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may + /// Checks for casts between numeric types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by /// default. It suggests user either explicitly ignore the lint, /// or use `try_from()` and handle the truncation, default, or panic explicitly. @@ -120,17 +120,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for casts from an unsigned type to a signed type of - /// the same size, or possibly smaller due to target dependent integers. - /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is - /// changed at the bit level, and the binary representation of the value is + /// the same size, or possibly smaller due to target-dependent integers. + /// Performing such a cast is a no-op for the compiler (that is, nothing is + /// changed at the bit level), and the binary representation of the value is /// reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// /// ### Why is this bad? /// While such a cast is not bad in itself, the results can - /// be surprising when this is not the intended behavior, as demonstrated by the - /// example below. + /// be surprising when this is not the intended behavior: /// /// ### Example /// ```no_run @@ -144,16 +143,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may - /// be replaced by safe conversion functions. + /// Checks for casts between numeric types that can be replaced by safe + /// conversion functions. /// /// ### Why is this bad? - /// Rust's `as` keyword will perform many kinds of - /// conversions, including silently lossy conversions. Conversion functions such - /// as `i32::from` will only perform lossless conversions. Using the conversion - /// functions prevents conversions from turning into silent lossy conversions if - /// the types of the input expressions ever change, and make it easier for - /// people reading the code to know that the conversion is lossless. + /// Rust's `as` keyword will perform many kinds of conversions, including + /// silently lossy conversions. Conversion functions such as `i32::from` + /// will only perform lossless conversions. Using the conversion functions + /// prevents conversions from becoming silently lossy if the input types + /// ever change, and makes it clear for people reading the code that the + /// conversion is lossless. /// /// ### Example /// ```no_run @@ -177,19 +176,21 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer types, casts of float - /// literals to float types and casts between raw pointers without changing type or constness. + /// Checks for casts to the same type, casts of int literals to integer + /// types, casts of float literals to float types, and casts between raw + /// pointers that don't change type or constness. /// /// ### Why is this bad? /// It's just unnecessary. /// /// ### Known problems - /// When the expression on the left is a function call, the lint considers the return type to be - /// a type alias if it's aliased through a `use` statement - /// (like `use std::io::Result as IoResult`). It will not lint such cases. + /// When the expression on the left is a function call, the lint considers + /// the return type to be a type alias if it's aliased through a `use` + /// statement (like `use std::io::Result as IoResult`). It will not lint + /// such cases. /// - /// This check is also rather primitive. It will only work on primitive types without any - /// intermediate references, raw pointers and trait objects may or may not work. + /// This check will only work on primitive types without any intermediate + /// references: raw pointers and trait objects may or may not work. /// /// ### Example /// ```no_run @@ -211,17 +212,17 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts, using `as` or `pointer::cast`, - /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer + /// Checks for casts, using `as` or `pointer::cast`, from a + /// less strictly aligned pointer to a more strictly aligned pointer. /// /// ### Why is this bad? - /// Dereferencing the resulting pointer may be undefined - /// behavior. + /// Dereferencing the resulting pointer may be undefined behavior. /// /// ### Known problems - /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like - /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + /// Using [`std::ptr::read_unaligned`] and [`std::ptr::write_unaligned`] or + /// similar on the resulting pointer is fine. Is over-zealous: casts with + /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be + /// fine. Miri is able to do a more in-depth analysis. /// /// ### Example /// ```no_run @@ -234,20 +235,21 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CAST_PTR_ALIGNMENT, pedantic, - "cast from a pointer to a more-strictly-aligned pointer" + "cast from a pointer to a more strictly aligned pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of function pointers to something other than usize + /// Checks for casts of function pointers to something other than `usize`. /// /// ### Why is this bad? - /// Casting a function pointer to anything other than usize/isize is not portable across - /// architectures, because you end up losing bits if the target type is too small or end up with a - /// bunch of extra bits that waste space and add more instructions to the final binary than - /// strictly necessary for the problem + /// Casting a function pointer to anything other than `usize`/`isize` is + /// not portable across architectures. It either loses bits if the target + /// type is too small, or creates extra bits that waste space and bloat the + /// resulting binary. /// - /// Casting to isize also doesn't make sense since there are no signed addresses. + /// Casting to `isize` also doesn't make sense, since addresses are never + /// signed. /// /// ### Example /// ```no_run @@ -263,17 +265,17 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, style, - "casting a function pointer to a numeric type other than usize" + "casting a function pointer to a numeric type other than `usize`" } declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to a numeric type not wide enough to - /// store address. + /// store an address. /// /// ### Why is this bad? /// Such a cast discards some bits of the function's address. If this is intended, it would be more - /// clearly expressed by casting to usize first, then casting the usize to the intended type (with + /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with /// a comment) to perform the truncation. /// /// ### Example @@ -306,7 +308,7 @@ declare_clippy_lint! { /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt-out of casting functions to integers in + /// low-level with function pointers then you can opt out of casting functions to integers in /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function /// pointer casts in your code. /// @@ -349,8 +351,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// In general, casting values to smaller types is /// error-prone and should be avoided where possible. In the particular case of - /// converting a character literal to u8, it is easy to avoid by just using a - /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter + /// converting a character literal to `u8`, it is easy to avoid by just using a + /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter /// than `'a' as u8`. /// /// ### Example @@ -371,12 +373,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers without changing its mutability, - /// namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// Checks for `as` casts on a raw pointer that don't change its + /// mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because - /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + /// Though `as` casts between raw pointers are not terrible, + /// `pointer::cast` is safer because it cannot accidentally change the + /// pointer's mutability, nor cast the pointer to other types like `usize`. /// /// ### Example /// ```no_run @@ -395,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` on a raw pointer that doesn't change its mutability, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to + /// Checks for `as` casts on a raw pointer that change its constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? @@ -423,12 +426,12 @@ declare_clippy_lint! { #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, pedantic, - "casting using `as` from and to raw pointers to change constness when specialized methods apply" + "casting using `as` on raw pointers to change constness when specialized methods apply" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// Checks for casts from an enum type to an integral type that will definitely truncate the /// value. /// /// ### Why is this bad? @@ -442,7 +445,7 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub CAST_ENUM_TRUNCATION, suspicious, - "casts from an enum type to an integral type which will truncate the value" + "casts from an enum type to an integral type that will truncate the value" } declare_clippy_lint! { @@ -621,7 +624,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer + /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. /// /// ### Why is this bad? /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index bb766e963387..99328e3e643f 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// /// ### Why restrict this? - /// To ensure use of big endian or the target’s endianness rather than little endian. + /// To ensure use of big-endian or the target’s endianness rather than little-endian. /// /// ### Example /// ```rust,ignore @@ -51,7 +51,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// /// ### Why restrict this? - /// To ensure use of little endian or the target’s endianness rather than big endian. + /// To ensure use of little-endian or the target’s endianness rather than big-endian. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1408f4548200..b8b24fe92ee3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -628,12 +628,12 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or - /// `_.or_else(|x| Err(y))`. + /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` + /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// Readability, this can be written more concisely as - /// `_.map(|x| y)` or `_.map_err(|x| y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| + /// y)`. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 8fdd19c549f5..508f3ae6def0 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { /// ### What it does /// It lints if a struct has two methods with the same name: - /// one from a trait, another not from trait. + /// one from a trait, another not from a trait. /// /// ### Why restrict this? /// Confusing. diff --git a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index a74d8757e4a5..016ee502c242 100644 --- a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -1,4 +1,4 @@ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 | LL | let _x = String::from("hello"); @@ -8,13 +8,13 @@ LL | let _x = String::from("hello"); = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` -error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` +error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13 | LL | let _x = String::from("hi!"); diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index 8e5510e6cd01..cecf00c934fe 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -8,7 +8,7 @@ mod std_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -24,13 +24,13 @@ mod std_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -52,7 +52,7 @@ mod std_mutex { let first = baz().await; let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -66,7 +66,7 @@ mod std_mutex { let second = { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -79,7 +79,7 @@ mod std_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -92,7 +92,7 @@ mod parking_lot_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -108,13 +108,13 @@ mod parking_lot_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -136,7 +136,7 @@ mod parking_lot_mutex { let first = baz().await; let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -150,7 +150,7 @@ mod parking_lot_mutex { let second = { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -163,7 +163,7 @@ mod parking_lot_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex) { // `*guard += 1` is removed it is picked up. async fn dropped_before_await(x: std::sync::Mutex) { let mut guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point *guard += 1; drop(guard); baz().await; diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index 0af48a36acca..af61d8939483 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,11 +1,11 @@ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:10:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:12:15 | LL | baz().await @@ -13,40 +13,40 @@ LL | baz().await = note: `-D clippy::await-holding-lock` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:26:13 | LL | let guard = x.read().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:28:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:32:13 | LL | let mut guard = x.write().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:34:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:54:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:57:28 | LL | let second = baz().await; @@ -55,79 +55,79 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:68:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:70:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:81:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:83:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:94:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:96:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:110:13 | LL | let guard = x.read(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:112:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:116:13 | LL | let mut guard = x.write(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:118:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:138:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:141:28 | LL | let second = baz().await; @@ -136,40 +136,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:152:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:154:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:165:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:167:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:186:9 | LL | let mut guard = x.lock().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:190:11 | LL | baz().await; diff --git a/tests/ui/await_holding_refcell_ref.rs b/tests/ui/await_holding_refcell_ref.rs index 5bd26c628362..b0c92d8c1f6e 100644 --- a/tests/ui/await_holding_refcell_ref.rs +++ b/tests/ui/await_holding_refcell_ref.rs @@ -4,13 +4,13 @@ use std::cell::RefCell; async fn bad(x: &RefCell) -> u32 { let b = x.borrow(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } async fn bad_mut(x: &RefCell) -> u32 { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } @@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -61,7 +61,7 @@ async fn not_good(x: &RefCell) -> u32 { let second = { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await }; @@ -74,7 +74,7 @@ async fn not_good(x: &RefCell) -> u32 { fn block_bad(x: &RefCell) -> impl std::future::Future + '_ { async move { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } } diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 6b474c27ddc1..6c7209c9ff9e 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,11 +1,11 @@ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:8:11 | LL | baz().await @@ -13,27 +13,27 @@ LL | baz().await = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:12:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:14:11 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:34:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:37:24 | LL | let second = baz().await; @@ -42,40 +42,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:47:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:50:24 | LL | let second = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:63:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:65:15 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:76:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:78:15 | LL | baz().await From cfccdbb1641289e92d414b01f67c6a22b485a327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Thu, 20 Jun 2024 02:15:23 -0400 Subject: [PATCH 023/361] Clarify that `modulo_one` only applies to ints --- clippy_lints/src/operators/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 48a442705b29..52dc12fe51ef 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -627,7 +627,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for getting the remainder of a division by one or minus + /// Checks for getting the remainder of integer division by one or minus /// one. /// /// ### Why is this bad? @@ -646,7 +646,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub MODULO_ONE, correctness, - "taking a number modulo +/-1, which can either panic/overflow or always returns 0" + "taking an integer modulo +/-1, which can either panic/overflow or always returns 0" } declare_clippy_lint! { From 5c46acac0431a5fe0fbf8f5239a7d3364c9186cf Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 22 Jun 2024 14:38:14 +0200 Subject: [PATCH 024/361] document the cvt methods --- library/std/src/sys/pal/unix/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index b370f06e92ba..ae257cab1e50 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -307,10 +307,13 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } +/// Convert native return values to Result using the *-1 means error is in `errno`* convention. +/// Non-error values are `Ok`-wrapped. pub fn cvt(t: T) -> crate::io::Result { if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } } +/// `-1` → look at `errno` → retry on `EINTR`. Otherwise `Ok()`-wrap the closure return value. pub fn cvt_r(mut f: F) -> crate::io::Result where T: IsMinusOne, @@ -325,6 +328,7 @@ where } #[allow(dead_code)] // Not used on all platforms. +/// Zero means `Ok()`, all other values are treated as raw OS errors. Does not look at `errno`. pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } } From 6687a3f7da60a4d0f06fd84fea75bec1dd0fce2a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 22 Jun 2024 14:37:12 +0200 Subject: [PATCH 025/361] use pidfd_spawn for faster process creation when pidfds are requested --- .../std/src/sys/pal/unix/linux/pidfd/tests.rs | 13 ++- .../src/sys/pal/unix/process/process_unix.rs | 99 ++++++++++++++++++- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index 6d9532f2ef1f..672cb0efed1d 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -1,7 +1,7 @@ use crate::assert_matches::assert_matches; use crate::os::fd::{AsRawFd, RawFd}; -use crate::os::linux::process::{ChildExt, CommandExt}; -use crate::os::unix::process::ExitStatusExt; +use crate::os::linux::process::{ChildExt, CommandExt as _}; +use crate::os::unix::process::{CommandExt as _, ExitStatusExt}; use crate::process::Command; #[test] @@ -42,6 +42,15 @@ fn test_command_pidfd() { .unwrap() .pidfd() .expect_err("pidfd should not have been created"); + + // exercise the fork/exec path since the earlier attempts may have used pidfd_spawnp() + let mut child = + unsafe { Command::new("false").pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap(); + + if pidfd_open_available { + assert!(child.pidfd().is_ok()) + } + child.wait().expect("error waiting on child"); } #[test] diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 32382d9a50cf..3de66d9789fb 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -449,17 +449,70 @@ impl Command { use crate::mem::MaybeUninit; use crate::sys::weak::weak; use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used}; + #[cfg(target_os = "linux")] + use core::sync::atomic::{AtomicU8, Ordering}; if self.get_gid().is_some() || self.get_uid().is_some() || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() || self.get_groups().is_some() - || self.get_create_pidfd() { return Ok(None); } + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + weak! { + fn pidfd_spawnp( + *mut libc::c_int, + *const libc::c_char, + *const libc::posix_spawn_file_actions_t, + *const libc::posix_spawnattr_t, + *const *mut libc::c_char, + *const *mut libc::c_char + ) -> libc::c_int + } + + weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } + + static PIDFD_SPAWN_SUPPORTED: AtomicU8 = AtomicU8::new(0); + const UNKNOWN: u8 = 0; + const YES: u8 = 1; + // NO currently forces a fallback to fork/exec. We could be more nuanced here and keep using spawn + // if we know pidfd's aren't supported at all and the fallback would be futile. + const NO: u8 = 2; + + if self.get_create_pidfd() { + let flag = PIDFD_SPAWN_SUPPORTED.load(Ordering::Relaxed); + if flag == NO || pidfd_spawnp.get().is_none() || pidfd_getpid.get().is_none() { + return Ok(None); + } + if flag == UNKNOWN { + let mut support = NO; + let our_pid = crate::process::id(); + let pidfd = + unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as libc::c_int; + if pidfd >= 0 { + let pid = unsafe { pidfd_getpid.get().unwrap()(pidfd) } as u32; + unsafe { libc::close(pidfd) }; + if pid == our_pid { + support = YES + }; + } + PIDFD_SPAWN_SUPPORTED.store(support, Ordering::Relaxed); + if support != YES { + return Ok(None); + } + } + } + } else { + if self.get_create_pidfd() { + unreachable!("only implemented on linux") + } + } + } + // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. #[cfg(all(target_os = "linux", target_env = "gnu"))] { @@ -543,9 +596,6 @@ impl Command { let pgroup = self.get_pgroup(); - // Safety: -1 indicates we don't have a pidfd. - let mut p = unsafe { Process::new(0, -1) }; - struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit); impl Drop for PosixSpawnFileActions<'_> { @@ -640,6 +690,47 @@ impl Command { #[cfg(target_os = "nto")] let spawn_fn = retrying_libc_posix_spawnp; + #[cfg(target_os = "linux")] + if self.get_create_pidfd() { + let mut pidfd: libc::c_int = -1; + let spawn_res = pidfd_spawnp.get().unwrap()( + &mut pidfd, + self.get_program_cstr().as_ptr(), + file_actions.0.as_ptr(), + attrs.0.as_ptr(), + self.get_argv().as_ptr() as *const _, + envp as *const _, + ); + + let spawn_res = cvt_nz(spawn_res); + if let Err(ref e) = spawn_res + && e.raw_os_error() == Some(libc::ENOSYS) + { + PIDFD_SPAWN_SUPPORTED.store(NO, Ordering::Relaxed); + return Ok(None); + } + spawn_res?; + + let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) { + Ok(pid) => pid, + Err(e) => { + // The child has been spawned and we are holding its pidfd. + // But we cannot obtain its pid even though pidfd_getpid support was verified earlier. + // This might happen if libc can't open procfs because the file descriptor limit has been reached. + libc::close(pidfd); + return Err(Error::new( + e.kind(), + "pidfd_spawnp succeeded but the child's PID could not be obtained", + )); + } + }; + + return Ok(Some(Process::new(pid, pidfd))); + } + + // Safety: -1 indicates we don't have a pidfd. + let mut p = Process::new(0, -1); + let spawn_res = spawn_fn( &mut p.pid, self.get_program_cstr().as_ptr(), From 0ce361938eddf08da88e4c35e0ed63dbb204b2f2 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 24 Jun 2024 23:10:17 +0200 Subject: [PATCH 026/361] document safety properties of the internal Process::new constructor --- library/std/src/sys/pal/unix/process/process_unix.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 3de66d9789fb..23dce4ea5fb7 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -877,6 +877,12 @@ pub struct Process { impl Process { #[cfg(target_os = "linux")] + /// # Safety + /// + /// `pidfd` must either be -1 (representing no file descriptor) or a valid, exclusively owned file + /// descriptor (See [I/O Safety]). + /// + /// [I/O Safety]: crate::io#io-safety unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self { use crate::os::unix::io::FromRawFd; use crate::sys_common::FromInner; From 3e4e31b7bf34dafa4dc3fc97e454a046886692da Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 25 Jun 2024 00:14:55 +0200 Subject: [PATCH 027/361] more fine-grained feature-detection for pidfd spawning we now distinguish between pidfd_spawn support, pidfd-via-fork/exec and not-supported --- .../src/sys/pal/unix/process/process_unix.rs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 23dce4ea5fb7..abd4a334783e 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -476,35 +476,47 @@ impl Command { weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } - static PIDFD_SPAWN_SUPPORTED: AtomicU8 = AtomicU8::new(0); + static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0); const UNKNOWN: u8 = 0; - const YES: u8 = 1; - // NO currently forces a fallback to fork/exec. We could be more nuanced here and keep using spawn - // if we know pidfd's aren't supported at all and the fallback would be futile. - const NO: u8 = 2; + const SPAWN: u8 = 1; + // Obtaining a pidfd via the fork+exec path might work + const FORK_EXEC: u8 = 2; + // Neither pidfd_spawn nor fork/exec will get us a pidfd. + // Instead we'll just posix_spawn if the other preconditions are met. + const NO: u8 = 3; if self.get_create_pidfd() { - let flag = PIDFD_SPAWN_SUPPORTED.load(Ordering::Relaxed); - if flag == NO || pidfd_spawnp.get().is_none() || pidfd_getpid.get().is_none() { + let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed); + if support == FORK_EXEC { return Ok(None); } - if flag == UNKNOWN { - let mut support = NO; + if support == UNKNOWN { + support = NO; let our_pid = crate::process::id(); - let pidfd = - unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as libc::c_int; - if pidfd >= 0 { - let pid = unsafe { pidfd_getpid.get().unwrap()(pidfd) } as u32; - unsafe { libc::close(pidfd) }; - if pid == our_pid { - support = YES - }; + let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int); + match pidfd { + Ok(pidfd) => { + support = FORK_EXEC; + if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) { + if pidfd_spawnp.get().is_some() && pid as u32 == our_pid { + support = SPAWN + } + } + unsafe { libc::close(pidfd) }; + } + Err(e) if e.raw_os_error() == Some(libc::EMFILE) => { + // We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail + // Don't update the support flag so we can probe again later. + return Err(e) + } + _ => {} } - PIDFD_SPAWN_SUPPORTED.store(support, Ordering::Relaxed); - if support != YES { + PIDFD_SUPPORTED.store(support, Ordering::Relaxed); + if support == FORK_EXEC { return Ok(None); } } + core::assert_matches::debug_assert_matches!(support, SPAWN | NO); } } else { if self.get_create_pidfd() { @@ -691,7 +703,7 @@ impl Command { let spawn_fn = retrying_libc_posix_spawnp; #[cfg(target_os = "linux")] - if self.get_create_pidfd() { + if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN { let mut pidfd: libc::c_int = -1; let spawn_res = pidfd_spawnp.get().unwrap()( &mut pidfd, @@ -706,7 +718,7 @@ impl Command { if let Err(ref e) = spawn_res && e.raw_os_error() == Some(libc::ENOSYS) { - PIDFD_SPAWN_SUPPORTED.store(NO, Ordering::Relaxed); + PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed); return Ok(None); } spawn_res?; From ec0c755704bba1b6c4faa0b10aa0d886cdfa309e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 25 Jun 2024 00:17:31 +0200 Subject: [PATCH 028/361] Check that we get somewhat sane PIDs when spawning with pidfds --- library/std/src/sys/pal/unix/linux/pidfd/tests.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index 672cb0efed1d..fb928c76fbd0 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -21,6 +21,7 @@ fn test_command_pidfd() { let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); assert!(flags & libc::FD_CLOEXEC != 0); } + assert!(child.id() > 0 && child.id() < -1i32 as u32); let status = child.wait().expect("error waiting on pidfd"); assert_eq!(status.code(), Some(1)); @@ -47,6 +48,8 @@ fn test_command_pidfd() { let mut child = unsafe { Command::new("false").pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap(); + assert!(child.id() > 0 && child.id() < -1i32 as u32); + if pidfd_open_available { assert!(child.pidfd().is_ok()) } From 9d3c79bcd01d444a1e075e15a71e31d4ef6ab0d8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 25 Jun 2024 10:55:33 -0700 Subject: [PATCH 029/361] Stabilize const unchecked conversion from u32 to char --- library/core/src/char/methods.rs | 5 ++++- library/core/src/char/mod.rs | 2 +- library/core/src/lib.rs | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 458be49fb152..4186565c131e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -223,7 +223,10 @@ impl char { /// assert_eq!('❤', c); /// ``` #[stable(feature = "assoc_char_funcs", since = "1.52.0")] - #[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")] + #[rustc_const_stable( + feature = "const_char_from_u32_unchecked", + since = "CURRENT_RUSTC_VERSION" + )] #[must_use] #[inline] pub const unsafe fn from_u32_unchecked(i: u32) -> char { diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index f3683fe3f9c8..26b463e25ea6 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -123,7 +123,7 @@ pub const fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]. /// instead. #[stable(feature = "char_from_unchecked", since = "1.5.0")] -#[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")] +#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const unsafe fn from_u32_unchecked(i: u32) -> char { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d1692729a31b..a5df782c1898 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -122,7 +122,6 @@ #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_cell_into_inner)] -#![feature(const_char_from_u32_unchecked)] #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_bits_conv)] From 2d5a4832f30d246b81c775aa5bf9003997568b65 Mon Sep 17 00:00:00 2001 From: CastilloDel Date: Wed, 26 Jun 2024 19:39:37 +0200 Subject: [PATCH 030/361] Acknowledge comments --- tests/mir-opt/dest-prop/copy_propagation_arg.rs | 2 +- tests/mir-opt/dest-prop/simple.rs | 3 +++ tests/mir-opt/dest-prop/union.rs | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.rs b/tests/mir-opt/dest-prop/copy_propagation_arg.rs index 2ea5c098ff40..5d99920ebc46 100644 --- a/tests/mir-opt/dest-prop/copy_propagation_arg.rs +++ b/tests/mir-opt/dest-prop/copy_propagation_arg.rs @@ -30,7 +30,7 @@ fn bar(mut x: u8) { fn baz(mut x: i32) -> i32 { // CHECK-LABEL: fn baz( // CHECK: debug x => [[x:_.*]]; - // CHECK-NOT: [[x]] = {{_.*}} + // CHECK-NOT: [[x]] = // self-assignment to a function argument should be eliminated x = x; x diff --git a/tests/mir-opt/dest-prop/simple.rs b/tests/mir-opt/dest-prop/simple.rs index 203f44a38261..a2c0e976b5fc 100644 --- a/tests/mir-opt/dest-prop/simple.rs +++ b/tests/mir-opt/dest-prop/simple.rs @@ -5,8 +5,11 @@ fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { // CHECK-LABEL: fn nrvo( // CHECK: debug init => [[init:_.*]]; + // CHECK: debug buf => [[buf:_.*]]; + // CHECK: [[buf]] = [const 0_u8; 1024]; // CHECK-NOT: {{_.*}} = [[init]]; // CHECK: move [[init]](move {{_.*}}) + // CHECK: {{_.*}} = [[buf]] let mut buf = [0; 1024]; init(&mut buf); buf diff --git a/tests/mir-opt/dest-prop/union.rs b/tests/mir-opt/dest-prop/union.rs index abd1f1b2c937..54c284e5b552 100644 --- a/tests/mir-opt/dest-prop/union.rs +++ b/tests/mir-opt/dest-prop/union.rs @@ -8,6 +8,8 @@ fn val() -> u32 { // EMIT_MIR union.main.DestinationPropagation.diff fn main() { + // CHECK-LABEL: fn args( + // CHECK: {{_.*}} = Un { us: const 1_u32 }; union Un { us: u32, } From 31851d4770774ac95a694f2596138fc43fcd39b4 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 14 Jun 2024 15:49:45 -0700 Subject: [PATCH 031/361] Add `-Zdump-mir-exclude-alloc-bytes` --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_middle/src/mir/pretty.rs | 3 +++ compiler/rustc_session/src/options.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6ffc518097ef..619b125a8780 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -683,6 +683,7 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dir, String::from("abc")); + untracked!(dump_mir_exclude_alloc_bytes, true); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into()))); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4657f4dcf813..3ea98de1a177 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1521,6 +1521,9 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display // We are done. return write!(w, " {{}}"); } + if tcx.sess.opts.unstable_opts.dump_mir_exclude_alloc_bytes { + return write!(w, " {{ .. }}"); + } // Write allocation bytes. writeln!(w, " {{")?; write_allocation_bytes(tcx, alloc, w, " ")?; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a10adeb6d1a..a3f1369776de 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1662,6 +1662,8 @@ options! { (default: no)"), dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED], "the directory the MIR is dumped into (default: `mir_dump`)"), + dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED], + "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"), dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], From 1a05cb2d9358879468c87645b0c1d5d1e8e12a12 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 14 Jun 2024 16:01:26 -0700 Subject: [PATCH 032/361] Use `-Zdump-mir-exclude-alloc-bytes` in some mir-opt tests --- tests/mir-opt/const_debuginfo.rs | 2 +- tests/mir-opt/const_prop/address_of_pair.rs | 1 + tests/mir-opt/const_prop/checked_add.rs | 2 +- tests/mir-opt/const_prop/mutable_variable_aggregate.rs | 1 + tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs | 1 + tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs | 1 + tests/mir-opt/const_prop/return_place.rs | 2 +- tests/mir-opt/const_prop/slice_len.rs | 2 +- tests/mir-opt/const_prop/tuple_literal_propagation.rs | 1 + tests/mir-opt/dataflow-const-prop/checked.rs | 2 +- tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs | 2 +- tests/mir-opt/dataflow-const-prop/enum.rs | 1 + tests/mir-opt/dataflow-const-prop/struct.rs | 1 + tests/mir-opt/dataflow-const-prop/tuple.rs | 1 + tests/mir-opt/enum_opt.rs | 2 +- tests/mir-opt/gvn.rs | 1 + tests/mir-opt/pre-codegen/optimizes_into_variable.rs | 2 +- 17 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs index 907d7fef0674..3b2bc4559ced 100644 --- a/tests/mir-opt/const_debuginfo.rs +++ b/tests/mir-opt/const_debuginfo.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: SingleUseConsts -//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN +//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN -Zdump-mir-exclude-alloc-bytes #![allow(unused)] diff --git a/tests/mir-opt/const_prop/address_of_pair.rs b/tests/mir-opt/const_prop/address_of_pair.rs index 6d0c0f8ad52a..9acaaa0ccaf9 100644 --- a/tests/mir-opt/const_prop/address_of_pair.rs +++ b/tests/mir-opt/const_prop/address_of_pair.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR address_of_pair.fn0.GVN.diff pub fn fn0() -> bool { diff --git a/tests/mir-opt/const_prop/checked_add.rs b/tests/mir-opt/const_prop/checked_add.rs index 0560b0495731..d450f7d03f38 100644 --- a/tests/mir-opt/const_prop/checked_add.rs +++ b/tests/mir-opt/const_prop/checked_add.rs @@ -1,6 +1,6 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: GVN -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR checked_add.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs index 7de647ed9c37..80cd75215c1b 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_aggregate.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs index 5656c0e7a686..856afd53ab46 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_aggregate_mut_ref.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs index cc92949128f7..2c6cc0db6b21 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs @@ -1,5 +1,6 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_unprop_assign.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs index e7eea11ae492..c5293aa73e55 100644 --- a/tests/mir-opt/const_prop/return_place.rs +++ b/tests/mir-opt/const_prop/return_place.rs @@ -1,6 +1,6 @@ //@ test-mir-pass: GVN // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR return_place.add.GVN.diff // EMIT_MIR return_place.add.PreCodegen.before.mir diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index 63cdbf01b3e8..265a496f39a3 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: GVN -//@ compile-flags: -Zmir-enable-passes=+InstSimplify +//@ compile-flags: -Zmir-enable-passes=+InstSimplify -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs index e42a62cb6fdf..baed5670dda8 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR tuple_literal_propagation.main.GVN.diff diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs index a73693464f95..f5a6cdb2c8d3 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.rs +++ b/tests/mir-opt/dataflow-const-prop/checked.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: DataflowConstProp -//@ compile-flags: -Coverflow-checks=on +//@ compile-flags: -Coverflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR checked.main.DataflowConstProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs index 3a0cbac328cb..087bd7a18572 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: DataflowConstProp -//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline +//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index 946cfa4c76c0..37304e3a270e 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(custom_mir, core_intrinsics, rustc_attrs)] diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index eed782c9036b..4b160c3dab7e 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH #[derive(Copy, Clone)] diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index d624e21f21ac..19b675770abe 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR tuple.main.DataflowConstProp.diff diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs index 2cc5df84d6b5..e42be8ac06dc 100644 --- a/tests/mir-opt/enum_opt.rs +++ b/tests/mir-opt/enum_opt.rs @@ -1,7 +1,7 @@ // skip-filecheck //@ test-mir-pass: EnumSizeOpt // EMIT_MIR_FOR_EACH_BIT_WIDTH -//@ compile-flags: -Zunsound-mir-opts +//@ compile-flags: -Zunsound-mir-opts -Zdump-mir-exclude-alloc-bytes #![feature(arbitrary_enum_discriminant, repr128)] diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 86f42d23f383..29f28e7af414 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ only-64bit diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs index de5e2d5c3121..44b4b0ad888a 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs @@ -1,6 +1,6 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes struct Point { x: u32, From 7c3673ff6f2ff4e8e85344c091c9feb4b5da1290 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 14 Jun 2024 16:05:22 -0700 Subject: [PATCH 033/361] Bless mir-opt for excluded alloc bytes --- .../const_debuginfo.main.SingleUseConsts.diff | 8 +-- .../const_prop/address_of_pair.fn0.GVN.diff | 6 +- .../checked_add.main.GVN.panic-abort.diff | 6 +- .../checked_add.main.GVN.panic-unwind.diff | 6 +- .../mutable_variable_aggregate.main.GVN.diff | 6 +- ...e_variable_aggregate_mut_ref.main.GVN.diff | 6 +- ...le_unprop_assign.main.GVN.panic-abort.diff | 6 +- ...e_unprop_assign.main.GVN.panic-unwind.diff | 6 +- .../return_place.add.GVN.panic-abort.diff | 6 +- .../return_place.add.GVN.panic-unwind.diff | 6 +- ...lace.add.PreCodegen.before.panic-abort.mir | 4 +- ...ace.add.PreCodegen.before.panic-unwind.mir | 4 +- .../slice_len.main.GVN.32bit.panic-abort.diff | 6 +- ...slice_len.main.GVN.32bit.panic-unwind.diff | 6 +- .../slice_len.main.GVN.64bit.panic-abort.diff | 6 +- ...slice_len.main.GVN.64bit.panic-unwind.diff | 6 +- ...eral_propagation.main.GVN.panic-abort.diff | 6 +- ...ral_propagation.main.GVN.panic-unwind.diff | 6 +- ...ed.main.DataflowConstProp.panic-abort.diff | 12 ++-- ...d.main.DataflowConstProp.panic-unwind.diff | 12 ++-- ...n.DataflowConstProp.32bit.panic-abort.diff | 12 +--- ....DataflowConstProp.32bit.panic-unwind.diff | 12 +--- ...n.DataflowConstProp.64bit.panic-abort.diff | 12 +--- ....DataflowConstProp.64bit.panic-unwind.diff | 12 +--- ...oxed_slice.main.GVN.32bit.panic-abort.diff | 18 ++---- ...xed_slice.main.GVN.32bit.panic-unwind.diff | 18 ++---- ...oxed_slice.main.GVN.64bit.panic-abort.diff | 18 ++---- ...xed_slice.main.GVN.64bit.panic-unwind.diff | 18 ++---- .../enum.simple.DataflowConstProp.32bit.diff | 6 +- .../enum.simple.DataflowConstProp.64bit.diff | 6 +- .../enum.statics.DataflowConstProp.32bit.diff | 25 +++----- .../enum.statics.DataflowConstProp.64bit.diff | 25 +++----- .../struct.main.DataflowConstProp.32bit.diff | 58 ++++++------------- .../struct.main.DataflowConstProp.64bit.diff | 58 ++++++------------- .../tuple.main.DataflowConstProp.32bit.diff | 24 +++----- .../tuple.main.DataflowConstProp.64bit.diff | 24 +++----- .../enum_opt.cand.EnumSizeOpt.32bit.diff | 6 +- .../enum_opt.cand.EnumSizeOpt.64bit.diff | 6 +- .../enum_opt.unin.EnumSizeOpt.32bit.diff | 6 +- .../enum_opt.unin.EnumSizeOpt.64bit.diff | 6 +- ...vn.arithmetic_checked.GVN.panic-abort.diff | 6 +- ...n.arithmetic_checked.GVN.panic-unwind.diff | 6 +- .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +++--- .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +++--- .../gvn.indirect_static.GVN.panic-abort.diff | 4 +- .../gvn.indirect_static.GVN.panic-unwind.diff | 4 +- .../gvn.wide_ptr_integer.GVN.panic-abort.diff | 12 ++-- ...gvn.wide_ptr_integer.GVN.panic-unwind.diff | 12 ++-- ...o_variable.main.GVN.32bit.panic-abort.diff | 6 +- ..._variable.main.GVN.32bit.panic-unwind.diff | 6 +- ...o_variable.main.GVN.64bit.panic-abort.diff | 6 +- ..._variable.main.GVN.64bit.panic-unwind.diff | 6 +- 52 files changed, 202 insertions(+), 402 deletions(-) diff --git a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff index ac33f51984cd..8088984bc77a 100644 --- a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff +++ b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff @@ -119,11 +119,7 @@ } } - ALLOC0 (size: 8, align: 4) { - 20 00 00 00 20 00 00 00 │ ... ... - } + ALLOC0 (size: 8, align: 4) { .. } - ALLOC1 (size: 4, align: 2) { - 01 00 63 00 │ ..c. - } + ALLOC1 (size: 4, align: 2) { .. } diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff index 3f4958f60e85..ac372f837268 100644 --- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff +++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff @@ -44,9 +44,7 @@ StorageDead(_2); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff index 0e93c167ebc9..798f957caa58 100644 --- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff index 589eed5776c9..a09f8ee5be12 100644 --- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff index b6ff7b0fc234..7584353620ec 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 2a 00 00 00 2b 00 00 00 │ *...+... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff index 4ed7c9851479..e16e2969eb89 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff @@ -31,9 +31,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 2a 00 00 00 2b 00 00 00 │ *...+... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff index d1d23675bfd9..19d79694666f 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff @@ -48,9 +48,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff index 4d69c9ce2efe..2bb277bf27f7 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff @@ -48,9 +48,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff index b2d40daa80c4..037fe60c2fdb 100644 --- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff @@ -17,9 +17,7 @@ + _0 = const 4_u32; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff index 2eafc51cd3db..438a1cebea8c 100644 --- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff @@ -17,9 +17,7 @@ + _0 = const 4_u32; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir index f87c26bb004c..66fd61cc3aee 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir @@ -15,6 +15,4 @@ fn add() -> u32 { } } -ALLOC0 (size: 8, align: 4) { - 04 00 00 00 00 __ __ __ │ .....░░░ -} +ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir index 33f97591387c..f9b07a59de9c 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir @@ -15,6 +15,4 @@ fn add() -> u32 { } } -ALLOC0 (size: 8, align: 4) { - 04 00 00 00 00 __ __ __ │ .....░░░ -} +ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff index ef298dddd5a4..8415789de6ec 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff index 5379df3f60b4..fea7caac3cdc 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff index ef298dddd5a4..8415789de6ec 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff index 5379df3f60b4..fea7caac3cdc 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff index c2f3fb1b3b57..bf8fece3d37b 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff @@ -31,9 +31,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff index 55d9a3b0cac6..02a75849d887 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff @@ -31,9 +31,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff index 53663c6476bd..79ea55617481 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff @@ -76,13 +76,9 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 80 01 __ __ __ │ .....░░░ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 03 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff index 34feb2a64062..bd22c50dd8fc 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff @@ -76,13 +76,9 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 80 01 __ __ __ │ .....░░░ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 03 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 8005bc23cf69..4097e060f4d4 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -94,15 +94,9 @@ } } - ALLOC2 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC2 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index 42b1be32387c..ff44d0df5e3e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -98,15 +98,9 @@ } } - ALLOC2 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC2 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 7b57b0db50c9..3662c3b59d27 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -94,15 +94,9 @@ } } - ALLOC2 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC2 (size: 16, align: 8) { .. } - ALLOC1 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC1 (size: 16, align: 8) { .. } - ALLOC0 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 2e75a63e2905..68dee57dee9e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -98,15 +98,9 @@ } } - ALLOC2 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC2 (size: 16, align: 8) { .. } - ALLOC1 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC1 (size: 16, align: 8) { .. } - ALLOC0 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index 06011f9d7596..9d96e895c8aa 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -102,17 +102,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; } -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index eb4a3ffd91d2..0bdff584b01e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -106,17 +106,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; } -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index a7cc243e548e..99e96fe5d70f 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -102,17 +102,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; } -+ } -+ -+ ALLOC2 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC2 (size: 16, align: 8) { .. } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index c905a48862ca..5eefabeac386 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -106,17 +106,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; } -+ } -+ -+ ALLOC2 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC2 (size: 16, align: 8) { .. } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff index 89ed26f065b2..a64dda0d06c4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff @@ -60,9 +60,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff index 89ed26f065b2..a64dda0d06c4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff @@ -60,9 +60,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index fe8ed0114897..b4d14f25fe2a 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {ALLOC1: &E}; + _2 = const {ALLOC0: &E}; - _1 = (*_2); + _1 = const E::V1(0_i32); StorageDead(_2); @@ -79,7 +79,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {ALLOC2: &&E}; + _8 = const {ALLOC1: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -111,21 +111,14 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC3 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (static: RC, size: 4, align: 4) { .. } - ALLOC2 (static: RC, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ - } +- ALLOC2 (size: 8, align: 4) { .. } ++ ALLOC3 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 04 00 00 00 │ ........ - } - - ALLOC1 (static: statics::C, size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (static: statics::C, size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index df3a989d09eb..57d02b87d136 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {ALLOC1: &E}; + _2 = const {ALLOC0: &E}; - _1 = (*_2); + _1 = const E::V1(0_i32); StorageDead(_2); @@ -79,7 +79,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {ALLOC2: &&E}; + _8 = const {ALLOC1: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -111,21 +111,14 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC3 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (static: RC, size: 8, align: 8) { .. } - ALLOC2 (static: RC, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ - } +- ALLOC2 (size: 8, align: 4) { .. } ++ ALLOC3 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 04 00 00 00 │ ........ - } - - ALLOC1 (static: statics::C, size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (static: statics::C, size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index f674169e28b2..a6da1483c1ac 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -112,7 +112,7 @@ _9 = (_10.2: &[f32]); StorageDead(_10); StorageLive(_14); - _14 = const {ALLOC4: &&SmallStruct}; + _14 = const {ALLOC0: &&SmallStruct}; _31 = deref_copy (*_14); StorageLive(_11); _32 = deref_copy (*_14); @@ -149,7 +149,7 @@ _21 = (_22.2: &[f32]); StorageDead(_22); StorageLive(_26); - _26 = const {ALLOC5: &&BigStruct}; + _26 = const {ALLOC1: &&BigStruct}; _35 = deref_copy (*_26); StorageLive(_23); _36 = deref_copy (*_26); @@ -197,51 +197,31 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC6 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC3 (size: 8, align: 4) { .. } + -+ ALLOC7 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC4 (size: 8, align: 4) { .. } + -+ ALLOC8 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC5 (size: 8, align: 4) { .. } + -+ ALLOC9 (size: 8, align: 4) { -+ 01 00 00 00 01 00 00 00 │ ........ -+ } ++ ALLOC6 (size: 4, align: 4) { .. } + -+ ALLOC10 (size: 4, align: 4) { -+ 01 00 00 00 │ .... - } + ALLOC1 (static: BIG_STAT, size: 4, align: 4) { .. } - ALLOC5 (static: BIG_STAT, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ - } +- ALLOC2 (size: 20, align: 4) { .. } ++ ALLOC7 (size: 20, align: 4) { .. } - ALLOC0 (size: 20, align: 4) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼.... - 0x10 │ 00 00 a4 42 │ ...B - } +- ALLOC3 (size: 8, align: 4) { .. } ++ ALLOC8 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 00 00 34 42 00 00 90 42 │ ..4B...B - } + ALLOC0 (static: SMALL_STAT, size: 4, align: 4) { .. } - ALLOC4 (static: SMALL_STAT, size: 4, align: 4) { - ╾ALLOC2╼ │ ╾──╼ - } +- ALLOC4 (size: 20, align: 4) { .. } ++ ALLOC9 (size: 20, align: 4) { .. } - ALLOC2 (size: 20, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 10 41 │ ...A - } - - ALLOC3 (size: 4, align: 4) { - 00 00 50 41 │ ..PA - } +- ALLOC5 (size: 4, align: 4) { .. } ++ ALLOC10 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index c2608190a6b9..7ca25e442995 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -112,7 +112,7 @@ _9 = (_10.2: &[f32]); StorageDead(_10); StorageLive(_14); - _14 = const {ALLOC4: &&SmallStruct}; + _14 = const {ALLOC0: &&SmallStruct}; _31 = deref_copy (*_14); StorageLive(_11); _32 = deref_copy (*_14); @@ -149,7 +149,7 @@ _21 = (_22.2: &[f32]); StorageDead(_22); StorageLive(_26); - _26 = const {ALLOC5: &&BigStruct}; + _26 = const {ALLOC1: &&BigStruct}; _35 = deref_copy (*_26); StorageLive(_23); _36 = deref_copy (*_26); @@ -197,51 +197,31 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC6 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC3 (size: 8, align: 4) { .. } + -+ ALLOC7 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC4 (size: 8, align: 4) { .. } + -+ ALLOC8 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } ++ ALLOC5 (size: 8, align: 4) { .. } + -+ ALLOC9 (size: 8, align: 4) { -+ 01 00 00 00 01 00 00 00 │ ........ -+ } ++ ALLOC6 (size: 4, align: 4) { .. } + -+ ALLOC10 (size: 4, align: 4) { -+ 01 00 00 00 │ .... - } + ALLOC1 (static: BIG_STAT, size: 8, align: 8) { .. } - ALLOC5 (static: BIG_STAT, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ - } +- ALLOC2 (size: 32, align: 8) { .. } ++ ALLOC7 (size: 32, align: 8) { .. } - ALLOC0 (size: 32, align: 8) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼ - 0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░ - } +- ALLOC3 (size: 8, align: 4) { .. } ++ ALLOC8 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 00 00 34 42 00 00 90 42 │ ..4B...B - } + ALLOC0 (static: SMALL_STAT, size: 8, align: 8) { .. } - ALLOC4 (static: SMALL_STAT, size: 8, align: 8) { - ╾ALLOC2╼ │ ╾──────╼ - } +- ALLOC4 (size: 32, align: 8) { .. } ++ ALLOC9 (size: 32, align: 8) { .. } - ALLOC2 (size: 32, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼ - 0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░ - } - - ALLOC3 (size: 4, align: 4) { - 00 00 50 41 │ ..PA - } +- ALLOC5 (size: 4, align: 4) { .. } ++ ALLOC10 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff index f5723cac7d9c..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff @@ -92,21 +92,13 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC3 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff index f5723cac7d9c..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff @@ -92,21 +92,13 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC3 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff index 775a60f1c960..085c55caaa03 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 05 20 00 00 │ ..... .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff index c4b57579943d..798b7c10fe8d 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 02 00 00 00 00 00 00 00 05 20 00 00 00 00 00 00 │ ......... ...... } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff index f7d0d1fb56c3..a04829af4b53 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 05 20 00 00 01 00 00 00 │ . ...... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff index 15f1bd0df51a..f5521a1e22a4 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 05 20 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ . .............. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff index 5bf22af6ae83..0e3f2459fae3 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff @@ -140,9 +140,7 @@ _0 = const (); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff index 18d2029e4450..2873d7ef0ab1 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff @@ -140,9 +140,7 @@ _0 = const (); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index 0c49e706c9ec..b5c0cee78468 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; + let _7: {closure@$DIR/gvn.rs:615:19: 615:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; +- _7 = {closure@$DIR/gvn.rs:615:19: 615:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index e5f865b74b9f..7bc6573c13d4 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; + let _7: {closure@$DIR/gvn.rs:615:19: 615:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; +- _7 = {closure@$DIR/gvn.rs:615:19: 615:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff index f853942bbb66..e84f91e495d9 100644 --- a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff @@ -13,7 +13,5 @@ } } - ALLOC0 (static: A, size: 2, align: 1) { - 00 __ │ .░ - } + ALLOC0 (static: A, size: 2, align: 1) { .. } diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff index f853942bbb66..e84f91e495d9 100644 --- a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff @@ -13,7 +13,5 @@ } } - ALLOC0 (static: A, size: 2, align: 1) { - 00 __ │ .░ - } + ALLOC0 (static: A, size: 2, align: 1) { .. } diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff index 07c4c7663c15..3eed0473f7fc 100644 --- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff @@ -176,13 +176,9 @@ + nop; return; } -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff index df0f93f1077e..9a6e255a872e 100644 --- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff @@ -176,13 +176,9 @@ + nop; return; } -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff index 2f34a62b3d13..45b8d89c0f4f 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index da7add371a5b..e6ee1e6f9a34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff index 2f34a62b3d13..45b8d89c0f4f 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index da7add371a5b..e6ee1e6f9a34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } From b60a6ad7f5ea1842fc3a23dbfd759bc8cb8b1f34 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Jun 2024 12:01:49 -0400 Subject: [PATCH 034/361] Make queries more explicit --- clippy_lints/src/implied_bounds_in_impls.rs | 2 +- clippy_lints/src/methods/type_id_on_box.rs | 2 +- clippy_lints/src/needless_maybe_sized.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 170ecf896b4e..67b48878ca51 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + && let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates // If the trait has no supertrait, there is no need to collect anything from that bound && !predicates.is_empty() { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 6f9b38fcf83c..b62ecef0069a 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -24,7 +24,7 @@ fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { cx.tcx.is_diagnostic_item(sym::Any, tr.def_id) || cx .tcx - .super_predicates_of(tr.def_id) + .explicit_super_predicates_of(tr.def_id) .predicates .iter() .any(|(clause, _)| { diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index 4922c87b206c..a1d8ec3b32ec 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -91,7 +91,7 @@ fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> return true; } - for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates { + for &(predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).predicates { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() && trait_predicate.polarity == PredicatePolarity::Positive && !path.contains(&trait_predicate.def_id()) From dab77c50daeb563a05b20b31527f731b683cded5 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 27 Jun 2024 18:31:29 +0200 Subject: [PATCH 035/361] fix least significant digits of f128 associated constants While the numbers are parsed to the correct value, the decimal numbers in the source were rounded to zero instead of to the nearest, making the literals different from the values shown in the documentation. --- library/core/src/num/f128.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 58ed98c888cc..048e3cca93d2 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -167,7 +167,7 @@ impl f128 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS #[unstable(feature = "f128", issue = "116909")] - pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128; + pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128; /// Smallest finite `f128` value. /// @@ -175,7 +175,7 @@ impl f128 { /// /// [`MAX`]: f128::MAX #[unstable(feature = "f128", issue = "116909")] - pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128; + pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128; /// Smallest positive normal `f128` value. /// /// Equal to 2[`MIN_EXP`] − 1. @@ -191,7 +191,7 @@ impl f128 { /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS /// [`MAX_EXP`]: f128::MAX_EXP #[unstable(feature = "f128", issue = "116909")] - pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128; + pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; /// One greater than the minimum possible normal power of 2 exponent. /// From abdd057163e638da1ba8e0cae316348579fab9e9 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 27 Jun 2024 18:56:04 +0200 Subject: [PATCH 036/361] Merge commit '68a799aea9b65e2444fbecfe32217ce7d5a3604f' into clippy-subtree-update --- .github/workflows/lintcheck.yml | 118 ++++++++ CHANGELOG.md | 3 + book/src/lint_configuration.md | 3 +- book/src/usage.md | 2 +- clippy_config/src/conf.rs | 3 +- clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/assigning_clones.rs | 78 +++++- clippy_lints/src/attrs/allow_attributes.rs | 4 +- .../attrs/allow_attributes_without_reason.rs | 2 +- clippy_lints/src/attrs/mod.rs | 16 +- clippy_lints/src/casts/ref_as_ptr.rs | 4 +- clippy_lints/src/cognitive_complexity.rs | 22 +- clippy_lints/src/copies.rs | 16 +- clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/dereference.rs | 48 ++-- .../src/field_scoped_visibility_modifiers.rs | 75 +++++ clippy_lints/src/implicit_hasher.rs | 40 ++- clippy_lints/src/implicit_return.rs | 6 +- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/loops/mod.rs | 6 +- clippy_lints/src/manual_unwrap_or_default.rs | 9 +- clippy_lints/src/matches/manual_unwrap_or.rs | 111 +++++--- clippy_lints/src/matches/mod.rs | 10 +- clippy_lints/src/matches/single_match.rs | 4 +- clippy_lints/src/methods/manual_inspect.rs | 238 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 54 ++++ .../src/methods/unnecessary_min_or_max.rs | 90 ++++++ clippy_lints/src/missing_const_for_fn.rs | 24 +- clippy_lints/src/missing_doc.rs | 7 +- clippy_lints/src/multiple_bound_locations.rs | 8 +- .../src/needless_borrows_for_generic_args.rs | 8 +- clippy_lints/src/needless_else.rs | 16 +- clippy_lints/src/needless_for_each.rs | 6 +- clippy_lints/src/needless_if.rs | 24 +- .../src/non_octal_unix_permissions.rs | 12 +- clippy_lints/src/octal_escapes.rs | 160 ++++------- clippy_lints/src/ranges.rs | 19 +- clippy_lints/src/string_patterns.rs | 25 +- clippy_lints/src/upper_case_acronyms.rs | 102 ++++--- .../src/utils/internal_lints/invalid_paths.rs | 1 + clippy_utils/src/ast_utils.rs | 4 +- clippy_utils/src/check_proc_macro.rs | 84 +++--- clippy_utils/src/consts.rs | 21 +- clippy_utils/src/higher.rs | 63 +++-- clippy_utils/src/hir_utils.rs | 6 +- clippy_utils/src/lib.rs | 164 ++++++----- clippy_utils/src/mir/possible_borrower.rs | 2 +- clippy_utils/src/paths.rs | 1 - clippy_utils/src/source.rs | 201 +++++++++++-- clippy_utils/src/ty.rs | 14 + lintcheck/Cargo.toml | 15 +- lintcheck/README.md | 6 +- lintcheck/src/config.rs | 46 ++- lintcheck/src/json.rs | 122 ++++++++ lintcheck/src/main.rs | 263 ++++++++++-------- lintcheck/src/popular-crates.rs | 65 ----- lintcheck/src/popular_crates.rs | 52 ++++ rust-toolchain | 2 +- tests/integration.rs | 1 + .../ui-cargo/duplicate_mod/fail/Cargo.stderr | 32 +-- tests/ui-cargo/duplicate_mod/fail/src/main.rs | 1 - tests/ui/assigning_clones.fixed | 56 ++++ tests/ui/assigning_clones.rs | 56 ++++ tests/ui/auxiliary/external_consts.rs | 1 + tests/ui/cast.rs | 1 + tests/ui/cast.stderr | 184 ++++++------ tests/ui/cast_size.32bit.stderr | 60 ++-- tests/ui/copy_iterator.rs | 1 + tests/ui/copy_iterator.stderr | 2 +- tests/ui/crashes/ice-12284.rs | 10 + tests/ui/field_scoped_visibility_modifiers.rs | 21 ++ .../field_scoped_visibility_modifiers.stderr | 28 ++ tests/ui/implicit_return.fixed | 13 + tests/ui/implicit_return.rs | 13 + tests/ui/implicit_return.stderr | 32 +-- tests/ui/manual_inspect.fixed | 174 ++++++++++++ tests/ui/manual_inspect.rs | 186 +++++++++++++ tests/ui/manual_inspect.stderr | 182 ++++++++++++ tests/ui/manual_pattern_char_comparison.fixed | 12 + tests/ui/manual_pattern_char_comparison.rs | 12 + .../ui/manual_pattern_char_comparison.stderr | 8 +- tests/ui/manual_unwrap_or.fixed | 52 ++++ tests/ui/manual_unwrap_or.rs | 60 ++++ tests/ui/manual_unwrap_or.stderr | 40 ++- tests/ui/manual_unwrap_or_default.fixed | 23 +- tests/ui/manual_unwrap_or_default.rs | 23 +- tests/ui/match_result_ok.fixed | 7 +- tests/ui/match_result_ok.rs | 7 +- tests/ui/match_result_ok.stderr | 6 +- .../missing_const_for_fn/could_be_const.fixed | 173 ++++++++++++ .../could_be_const.stderr | 84 ++++++ tests/ui/octal_escapes.rs | 27 +- tests/ui/octal_escapes.stderr | 180 ++++++------ tests/ui/option_if_let_else.fixed | 3 +- tests/ui/option_if_let_else.rs | 3 +- tests/ui/option_if_let_else.stderr | 50 ++-- tests/ui/unnecessary_min_or_max.fixed | 67 +++++ tests/ui/unnecessary_min_or_max.rs | 67 +++++ tests/ui/unnecessary_min_or_max.stderr | 107 +++++++ triagebot.toml | 3 +- util/gh-pages/index.html | 34 ++- util/gh-pages/script.js | 33 +++ 103 files changed, 3637 insertions(+), 1014 deletions(-) create mode 100644 .github/workflows/lintcheck.yml create mode 100644 clippy_lints/src/field_scoped_visibility_modifiers.rs create mode 100644 clippy_lints/src/methods/manual_inspect.rs create mode 100644 clippy_lints/src/methods/unnecessary_min_or_max.rs create mode 100644 lintcheck/src/json.rs delete mode 100644 lintcheck/src/popular-crates.rs create mode 100644 lintcheck/src/popular_crates.rs create mode 100644 tests/ui/auxiliary/external_consts.rs create mode 100644 tests/ui/crashes/ice-12284.rs create mode 100644 tests/ui/field_scoped_visibility_modifiers.rs create mode 100644 tests/ui/field_scoped_visibility_modifiers.stderr create mode 100644 tests/ui/manual_inspect.fixed create mode 100644 tests/ui/manual_inspect.rs create mode 100644 tests/ui/manual_inspect.stderr create mode 100644 tests/ui/missing_const_for_fn/could_be_const.fixed create mode 100644 tests/ui/unnecessary_min_or_max.fixed create mode 100644 tests/ui/unnecessary_min_or_max.rs create mode 100644 tests/ui/unnecessary_min_or_max.stderr diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml new file mode 100644 index 000000000000..91c98b3a2560 --- /dev/null +++ b/.github/workflows/lintcheck.yml @@ -0,0 +1,118 @@ +name: Lintcheck + +on: pull_request + +env: + RUST_BACKTRACE: 1 + CARGO_INCREMENTAL: 0 + +concurrency: + # For a given workflow, if we push to the same PR, cancel all previous builds on that PR. + group: "${{ github.workflow }}-${{ github.event.pull_request.number}}" + cancel-in-progress: true + +jobs: + # Runs lintcheck on the PR's target branch and stores the results as an artifact + base: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^` + # being the commit from `master` that is the base of the merge + - name: Checkout base + run: git checkout HEAD^ + + # Use the lintcheck from the PR to generate the JSON in case the PR modifies lintcheck in some + # way + - name: Checkout current lintcheck + run: | + rm -rf lintcheck + git checkout ${{ github.sha }} -- lintcheck + + - name: Cache lintcheck bin + id: cache-lintcheck-bin + uses: actions/cache@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + + - name: Build lintcheck + if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true' + run: cargo build --manifest-path=lintcheck/Cargo.toml + + - name: Create cache key + id: key + run: echo "key=lintcheck-base-${{ hashfiles('lintcheck/**') }}-$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Cache results JSON + id: cache-json + uses: actions/cache@v4 + with: + path: lintcheck-logs/lintcheck_crates_logs.json + key: ${{ steps.key.outputs.key }} + + - name: Run lintcheck + if: steps.cache-json.outputs.cache-hit != 'true' + run: ./target/debug/lintcheck --format json + + - name: Upload base JSON + uses: actions/upload-artifact@v4 + with: + name: base + path: lintcheck-logs/lintcheck_crates_logs.json + + # Runs lintcheck on the PR and stores the results as an artifact + head: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache lintcheck bin + id: cache-lintcheck-bin + uses: actions/cache@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + + - name: Build lintcheck + if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true' + run: cargo build --manifest-path=lintcheck/Cargo.toml + + - name: Run lintcheck + run: ./target/debug/lintcheck --format json + + - name: Upload head JSON + uses: actions/upload-artifact@v4 + with: + name: head + path: lintcheck-logs/lintcheck_crates_logs.json + + # Retrieves the head and base JSON results and prints the diff to the GH actions step summary + diff: + runs-on: ubuntu-latest + + needs: [base, head] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Restore lintcheck bin + uses: actions/cache/restore@v4 + with: + path: target/debug/lintcheck + key: lintcheck-bin-${{ hashfiles('lintcheck/**') }} + fail-on-cache-miss: true + + - name: Download JSON + uses: actions/download-artifact@v4 + + - name: Diff results + run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY diff --git a/CHANGELOG.md b/CHANGELOG.md index d1cd87473cef..70ef2c793640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5362,6 +5362,7 @@ Released 2018-09-13 [`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default +[`field_scoped_visibility_modifiers`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_scoped_visibility_modifiers [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map [`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then @@ -5520,6 +5521,7 @@ Released 2018-09-13 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`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_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite @@ -5915,6 +5917,7 @@ Released 2018-09-13 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 6dad3463aa47..cfd34c7d2a7d 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -454,7 +454,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -695,6 +695,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison) * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) diff --git a/book/src/usage.md b/book/src/usage.md index 36448e4cccfa..7a0be6994fe1 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -36,7 +36,7 @@ You can configure lint levels on the command line by adding cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf ``` -For [CI] all warnings can be elevated to errors which will inturn fail +For [CI] all warnings can be elevated to errors which will in turn fail the build and cause Clippy to exit with a code other than `0`. ``` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 279193e516e9..dbab3b106a80 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -18,6 +18,7 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", @@ -265,7 +266,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 8bdb5b317e5d..a5761d3270cd 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -19,7 +19,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,81,0 { LINT_REASONS_STABILIZATION } 1,77,0 { C_STR_LITERALS } - 1,76,0 { PTR_FROM_REF } + 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 389338973894..d57ab539fff4 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `Arc` is a thread-safe `Rc` and guarantees that updates to the reference counter /// use atomic operations. To send an `Arc` across thread boundaries and /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety), - /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` + /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index e94a6f3e3fc5..05ea74b0d534 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,16 +1,18 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::HirNode; +use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; 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::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, SyntaxContext}; +use rustc_span::{ExpnKind, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -144,6 +146,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< }; Some(CallCandidate { + span: expr.span, target, kind, method_def_id: resolved_method.def_id(), @@ -215,6 +218,10 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC return false; }; + if clone_source_borrows_from_dest(cx, lhs, call.span) { + return false; + } + // Now take a look if the impl block defines an implementation for the method that we're interested // in. If not, then we're using a default implementation, which is not interesting, so we will // not suggest the lint. @@ -222,6 +229,74 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC implemented_fns.contains_key(&provided_fn.def_id) } +/// Checks if the data being cloned borrows from the place that is being assigned to: +/// +/// ``` +/// let mut s = String::new(); +/// let s2 = &s; +/// s = s2.to_owned(); +/// ``` +/// +/// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows. +fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool { + /// If this basic block only exists to drop a local as part of an assignment, returns its + /// successor. Otherwise returns the basic block that was passed in. + fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock { + if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind { + target + } else { + bb + } + } + + let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else { + return false; + }; + let PossibleBorrowerMap { map: borrow_map, .. } = PossibleBorrowerMap::new(cx, mir); + + // The operation `dest = src.to_owned()` in MIR is split up across 3 blocks *if* the type has `Drop` + // code. For types that don't, the second basic block is simply skipped. + // For the doc example above that would be roughly: + // + // bb0: + // s2 = &s + // s_temp = ToOwned::to_owned(move s2) -> bb1 + // + // bb1: + // drop(s) -> bb2 // drop the old string + // + // bb2: + // s = s_temp + for bb in mir.basic_blocks.iter() { + let terminator = bb.terminator(); + + // Look for the to_owned/clone call. + if terminator.source_info.span != call_span { + continue; + } + + if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind + && let [source] = &**args + && let mir::Operand::Move(source) = &source.node + && let assign_bb = skip_drop_block(mir, assign_bb) + // Skip any storage statements as they are just noise + && let Some(assignment) = mir.basic_blocks[assign_bb].statements + .iter() + .find(|stmt| { + !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) + }) + && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind + && let Some(borrowers) = borrow_map.get(&borrowed.local) + && borrowers.contains(source.local) + { + return true; + } + + return false; + } + false +} + fn suggest<'tcx>( cx: &LateContext<'tcx>, ctxt: SyntaxContext, @@ -255,6 +330,7 @@ enum TargetTrait { #[derive(Debug)] struct CallCandidate<'tcx> { + span: Span, target: TargetTrait, kind: CallKind<'tcx>, // DefId of the called method from an impl block that implements the target trait diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs index c5b6980b0b90..df9994086cd4 100644 --- a/clippy_lints/src/attrs/allow_attributes.rs +++ b/clippy_lints/src/attrs/allow_attributes.rs @@ -1,17 +1,17 @@ +use super::ALLOW_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use super::ALLOW_ATTRIBUTES; // Separate each crate's features. pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) { if !in_external_macro(cx.sess(), attr.span) && let AttrStyle::Outer = attr.style && let Some(ident) = attr.ident() - && !is_from_proc_macro(cx, &attr) + && !is_from_proc_macro(cx, attr) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 8bf985a36c7a..4b42616a636b 100644 --- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -17,7 +17,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet } // Check if the attribute is in an external macro and therefore out of the developer's control - if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) { + if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) { return; } diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index da19f17998af..8ec60314cc9a 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -1,7 +1,7 @@ //! checks for attributes -mod allow_attributes_without_reason; mod allow_attributes; +mod allow_attributes_without_reason; mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; mod deprecated_semver; @@ -505,6 +505,7 @@ pub struct Attributes { } impl_lint_pass!(Attributes => [ + ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, DEPRECATED_SEMVER, @@ -534,15 +535,12 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if is_lint_level(ident.name, attr.id) { blanket_clippy_restriction_lints::check(cx, ident.name, items); } - if matches!(ident.name, sym::allow) { - if self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes::check(cx, attr); - } + 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) { - if self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes_without_reason::check(cx, ident.name, items, 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 items.is_empty() || !attr.has_name(sym::deprecated) { return; diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index f42bafce4dde..5f48b8bd2063 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -22,9 +22,9 @@ pub(super) fn check<'tcx>( if matches!(cast_from.kind(), ty::Ref(..)) && let ty::RawPtr(_, to_mutbl) = cast_to.kind() - && let Some(use_cx) = expr_use_ctxt(cx, expr) + && let use_cx = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary - && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) + && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) { let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index e41abf422349..60815f4f2afb 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ //! calculate cognitive complexity and warn about overly complex functions use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; @@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -50,7 +50,6 @@ impl CognitiveComplexity { impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { - #[expect(clippy::cast_possible_truncation)] fn check<'tcx>( &mut self, cx: &LateContext<'tcx>, @@ -100,17 +99,12 @@ impl CognitiveComplexity { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); - let pos = snippet_opt(cx, header_span).and_then(|snip| { - let low_offset = snip.find('|')?; - let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?; - let low = header_span.lo() + BytePos(low_offset as u32); - let high = low + BytePos(high_offset as u32 + 1); - - Some((low, high)) - }); - - if let Some((low, high)) = pos { - Span::new(low, high, header_span.ctxt(), header_span.parent()) + #[expect(clippy::range_plus_one)] + if let Some(range) = header_span.map_range(cx, |src, range| { + let mut idxs = src.get(range.clone())?.match_indices('|'); + Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) + }) { + range.with_ctxt(header_span.ctxt()) } else { return; } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 480df675d754..d896452be920 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; +use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Span, Symbol}; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; declare_clippy_lint! { @@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>( let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indention (i.e. normal Rust formatting) - let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent()); - let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == " ") { - span.with_lo(test_span.lo()) - } else { - span - }; + let span = span + .map_range(cx, |src, range| { + (range.start > 4 && src.get(range.start - 4..range.start)? == " ") + .then_some(range.start - 4..range.end) + }) + .map_or(span, |range| range.with_ctxt(span.ctxt())); (span, suggestion.to_string()) }); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 76a0e450e59a..638de5e818c8 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -178,6 +178,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::explicit_write::EXPLICIT_WRITE_INFO, crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO, crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO, + crate::field_scoped_visibility_modifiers::FIELD_SCOPED_VISIBILITY_MODIFIERS_INFO, crate::float_literal::EXCESSIVE_PRECISION_INFO, crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO, @@ -402,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_C_STR_LITERALS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_INSPECT_INFO, crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, @@ -469,6 +471,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MIN_OR_MAX_INFO, crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index f451758c3350..a115f8d06314 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -6,7 +6,7 @@ use clippy_utils::{ expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, }; use core::mem; -use rustc_ast::util::parser::{PREC_UNAMBIGUOUS, PREC_PREFIX}; +use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; @@ -260,18 +260,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { (None, kind) => { let expr_ty = typeck.expr_ty(expr); let use_cx = expr_use_ctxt(cx, expr); - let adjusted_ty = match &use_cx { - Some(use_cx) => match use_cx.adjustments { - [.., a] => a.target, - _ => expr_ty, - }, - _ => typeck.expr_ty_adjusted(expr), - }; + let adjusted_ty = use_cx.adjustments.last().map_or(expr_ty, |a| a.target); - match (use_cx, kind) { - (Some(use_cx), RefOp::Deref) => { + match kind { + RefOp::Deref if use_cx.same_ctxt => { + let use_node = use_cx.use_node(cx); let sub_ty = typeck.expr_ty(sub_expr); - if let ExprUseNode::FieldAccess(name) = use_cx.node + if let ExprUseNode::FieldAccess(name) = use_node && !use_cx.moved_before_use && !ty_contains_field(sub_ty, name.name) { @@ -288,9 +283,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } else if sub_ty.is_ref() // Linting method receivers would require verifying that name lookup // would resolve the same way. This is complicated by trait methods. - && !use_cx.node.is_recv() - && let Some(ty) = use_cx.node.defined_ty(cx) - && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable() + && !use_node.is_recv() + && let Some(ty) = use_node.defined_ty(cx) + && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() { self.state = Some(( State::ExplicitDeref { mutability: None }, @@ -301,7 +296,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { )); } }, - (_, RefOp::Method { mutbl, is_ufcs }) + RefOp::Method { mutbl, is_ufcs } if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) // Allow explicit deref in method chains. e.g. `foo.deref().bar()` && (is_ufcs || !in_postfix_position(cx, expr)) => @@ -319,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }, )); }, - (Some(use_cx), RefOp::AddrOf(mutability)) => { + RefOp::AddrOf(mutability) if use_cx.same_ctxt => { // Find the number of times the borrow is auto-derefed. let mut iter = use_cx.adjustments.iter(); let mut deref_count = 0usize; @@ -338,10 +333,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }; }; - let stability = use_cx.node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| { - TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()) + let use_node = use_cx.use_node(cx); + let stability = use_node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| { + TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()) }); - let can_auto_borrow = match use_cx.node { + let can_auto_borrow = match use_node { ExprUseNode::FieldAccess(_) if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) => { @@ -353,7 +349,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // deref through `ManuallyDrop<_>` will not compile. !adjust_derefs_manually_drop(use_cx.adjustments, expr_ty) }, - ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true, + ExprUseNode::Callee | ExprUseNode::FieldAccess(_) if !use_cx.moved_before_use => true, ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => { // Check for calls to trait methods where the trait is implemented // on a reference. @@ -363,9 +359,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && let arg_ty = cx - .tcx - .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) + && let arg_ty = cx.tcx.erase_regions(adjusted_ty) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() @@ -443,7 +437,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { count: deref_count - required_refs, msg, stability, - for_field_access: if let ExprUseNode::FieldAccess(name) = use_cx.node + for_field_access: if let ExprUseNode::FieldAccess(name) = use_node && !use_cx.moved_before_use { Some(name.name) @@ -453,7 +447,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }), StateData { first_expr: expr, - adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target), + adjusted_ty, }, )); } else if stability.is_deref_stable() @@ -465,12 +459,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { State::Borrow { mutability }, StateData { first_expr: expr, - adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target), + adjusted_ty, }, )); } }, - (None, _) | (_, RefOp::Method { .. }) => (), + _ => {}, } }, ( diff --git a/clippy_lints/src/field_scoped_visibility_modifiers.rs b/clippy_lints/src/field_scoped_visibility_modifiers.rs new file mode 100644 index 000000000000..bb74e345703f --- /dev/null +++ b/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -0,0 +1,75 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of scoped visibility modifiers, like `pub(crate)`, on fields. These + /// make a field visible within a scope between public and private. + /// + /// ### Why restrict this? + /// Scoped visibility modifiers cause a field to be accessible within some scope between + /// public and private, potentially within an entire crate. This allows for fields to be + /// non-private while upholding internal invariants, but can be a code smell. Scoped visibility + /// requires checking a greater area, potentially an entire crate, to verify that an invariant + /// is upheld, and global analysis requires a lot of effort. + /// + /// ### Example + /// ```no_run + /// pub mod public_module { + /// struct MyStruct { + /// pub(crate) first_field: bool, + /// pub(super) second_field: bool + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// pub mod public_module { + /// struct MyStruct { + /// first_field: bool, + /// second_field: bool + /// } + /// impl MyStruct { + /// pub(crate) fn get_first_field(&self) -> bool { + /// self.first_field + /// } + /// pub(super) fn get_second_field(&self) -> bool { + /// self.second_field + /// } + /// } + /// } + /// ``` + #[clippy::version = "1.78.0"] + pub FIELD_SCOPED_VISIBILITY_MODIFIERS, + restriction, + "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" +} + +declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MODIFIERS]); + +impl EarlyLintPass for FieldScopedVisibilityModifiers { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + let ItemKind::Struct(ref st, _) = item.kind else { + return; + }; + for field in st.fields() { + let VisibilityKind::Restricted { path, .. } = &field.vis.kind else { + continue; + }; + if !path.segments.is_empty() && path.segments[0].ident.name == rustc_span::symbol::kw::SelfLower { + // pub(self) is equivalent to not using pub at all, so we ignore it + continue; + } + span_lint_and_help( + cx, + FIELD_SCOPED_VISIBILITY_MODIFIERS, + field.vis.span, + "scoped visibility modifier on a field", + None, + "consider making the field private and adding a scoped visibility method for it", + ); + } + } +} diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index ca830af3b2f3..344a04e6e7e8 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -59,10 +59,8 @@ declare_clippy_lint! { declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]); impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { - #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - use rustc_span::BytePos; - fn suggestion( cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, @@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let pos = snippet_opt(cx, item.span.until(target.span())) - .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4))); - if let Some(pos) = pos { - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| { + Some(src.get(range.clone())?.find("impl")? + 4..range.end) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) } else { return; } @@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let pos = snippet_opt( - cx, - Span::new( - item.span.lo(), - body.params[0].pat.span.lo(), - item.span.ctxt(), - item.span.parent(), - ), - ) - .and_then(|snip| { - let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32)) - }) - .expect("failed to create span for type parameters"); - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| { + let (pre, post) = src.get(range.clone())?.split_once("fn")?; + let pos = post.find('(')? + pre.len() + 2; + Some(pos..pos) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) + } else { + return; + } }); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 2f543781c44c..a102b434cfab 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}; +use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -245,6 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { } else { body.value }; + + if is_from_proc_macro(cx, expr) { + return; + } lint_implicit_returns(cx, expr, expr.span.ctxt(), None); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 63461c14d779..32fad0f02cea 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -137,6 +137,7 @@ mod exit; mod explicit_write; mod extra_unused_type_parameters; mod fallible_impl_from; +mod field_scoped_visibility_modifiers; mod float_literal; mod floating_point_arithmetic; mod format; @@ -1168,7 +1169,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ..Default::default() }) }); - store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); + store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); + store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 086829421530..64ea591993da 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -356,10 +356,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for loops which have a range bound that is a mutable variable + /// Checks for loops with a range bound that is a mutable variable. /// /// ### Why is this bad? - /// One might think that modifying the mutable variable changes the loop bounds + /// One might think that modifying the mutable variable changes the loop bounds. It doesn't. /// /// ### Known problems /// False positive when mutation is followed by a `break`, but the `break` is not immediately @@ -381,7 +381,7 @@ declare_clippy_lint! { /// let mut foo = 42; /// for i in 0..foo { /// foo -= 1; - /// println!("{}", i); // prints numbers from 0 to 42, not 0 to 21 + /// println!("{i}"); // prints numbers from 0 to 41, not 0 to 21 /// } /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 17399fb2cc21..58b2ebebbf08 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -53,6 +53,7 @@ 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. @@ -60,13 +61,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option { && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id)) { - let mut bindings = Vec::new(); - pat.each_binding(|_, id, _, _| bindings.push(id)); - if let &[id] = bindings.as_slice() { - Some(id) - } else { - None - } + Some(pat_id) } else { None } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 9edd6c954042..0940fc3219bb 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -3,46 +3,78 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; 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, sugg}; +use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; -use rustc_hir::{Arm, Expr, PatKind}; +use rustc_hir::{Arm, Expr, Pat, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_span::sym; use super::MANUAL_UNWRAP_OR; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { +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(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { + 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); + } +} + +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); + 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) = snippet_opt(cx, else_expr.span) + && let Some(indent) = indent_of(cx, expr.span) + && constant_simple(cx, cx.typeck_results(), else_expr).is_some() + { + lint(cx, expr, let_expr, ty_name, or_body_snippet, indent); + } +} + +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 - } && let Some(or_arm) = applicable_or_arm(cx, arms) - && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span) - && let Some(indent) = indent_of(cx, expr.span) - && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some() - { - let reindented_or_body = reindent_multiline(or_body_snippet.into(), 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, - ); } } -fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { +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 { @@ -54,18 +86,33 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' _ => false, }) && let unwrap_arm = &arms[1 - idx] - && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind - && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.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(unwrap_arm.body, binding_hir_id) - && cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty() && !contains_return_break_continue_macro(or_arm.body) { - Some(or_arm) + Some((or_arm, unwrap_arm)) } else { None } } + +fn lint<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + ty_name: &str, + or_body_snippet: String, + indent: usize, +) { + let reindented_or_body = reindent_multiline(or_body_snippet.into(), 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, + ); +} diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 691ecd57535a..bf7156cc53ec 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1069,7 +1069,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { redundant_guards::check(cx, arms, &self.msrv); if !in_constant(cx, expr.hir_id) { - manual_unwrap_or::check(cx, expr, ex, arms); + manual_unwrap_or::check_match(cx, expr, ex, arms); manual_map::check_match(cx, expr, ex, arms); manual_filter::check_match(cx, ex, arms, expr); } @@ -1097,6 +1097,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { ); } if !in_constant(cx, expr.hir_id) { + manual_unwrap_or::check_if_let( + cx, + expr, + if_let.let_pat, + if_let.let_expr, + if_let.if_then, + else_expr, + ); manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr); manual_filter::check_if_let( cx, diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 69791414f72c..99fdbcff890b 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, get_source_text, snippet}; +use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; @@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = get_source_text(cx, span) + if let Some(ff) = span.get_source_text(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs new file mode 100644 index 000000000000..e3ce64c246a5 --- /dev/null +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -0,0 +1,238 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::ty::get_field_by_name; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; +use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use core::ops::ControlFlow; +use rustc_errors::Applicability; +use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; + +use super::MANUAL_INSPECT; + +#[expect(clippy::too_many_lines)] +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: &Msrv) { + if let ExprKind::Closure(c) = arg.kind + && matches!(c.kind, ClosureKind::Closure) + && let typeck = cx.typeck_results() + && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id) + && (is_diag_trait_item(cx, fn_id, sym::Iterator) + || (msrv.meets(msrvs::OPTION_RESULT_INSPECT) + && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)))) + && let body = cx.tcx.hir().body(c.body) + && let [param] = body.params + && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind + && let arg_ty = typeck.node_type(arg_id) + && let ExprKind::Block(block, _) = body.value.kind + && let Some(final_expr) = block.expr + && !block.stmts.is_empty() + && path_to_local_id(final_expr, arg_id) + && typeck.expr_adjustments(final_expr).is_empty() + { + let mut requires_copy = false; + let mut requires_deref = false; + + // The number of unprocessed return expressions. + let mut ret_count = 0u32; + + // The uses for which processing is delayed until after the visitor. + let mut delayed = vec![]; + + let ctxt = arg.span.ctxt(); + let can_lint = for_each_expr_without_closures(block.stmts, |e| { + if let ExprKind::Closure(c) = e.kind { + // Nested closures don't need to treat returns specially. + let _: Option = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| { + if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (_, false) | (UseKind::Deref | UseKind::Return(..), true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }); + } else if matches!(e.kind, ExprKind::Ret(_)) { + ret_count += 1; + } else if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (UseKind::Return(..), false) => { + return ControlFlow::Break(()); + }, + (_, false) | (UseKind::Deref, true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind @ UseKind::Return(_), true) => { + ret_count -= 1; + delayed.push(kind); + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }) + .is_none(); + + if ret_count != 0 { + // A return expression that didn't return the original value was found. + return; + } + + let mut edits = Vec::with_capacity(delayed.len() + 3); + let mut addr_of_edits = Vec::with_capacity(delayed.len()); + for x in delayed { + match x { + UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), + UseKind::Borrowed(s) => { + #[expect(clippy::range_plus_one)] + let range = s.map_range(cx, |src, range| { + let src = src.get(range.clone())?; + let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); + trimmed.starts_with('&').then(|| { + let pos = range.start + src.len() - trimmed.len(); + pos..pos + 1 + }) + }); + if let Some(range) = range { + addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new())); + } else { + requires_copy = true; + requires_deref = true; + } + }, + UseKind::FieldAccess(name, e) => { + let Some(mut ty) = get_field_by_name(cx.tcx, arg_ty.peel_refs(), name) else { + requires_copy = true; + continue; + }; + let mut prev_expr = e; + + for (_, parent) in cx.tcx.hir().parent_iter(e.hir_id) { + if let Node::Expr(e) = parent { + match e.kind { + ExprKind::Field(_, name) + if let Some(fty) = get_field_by_name(cx.tcx, ty.peel_refs(), name.name) => + { + ty = fty; + prev_expr = e; + continue; + }, + ExprKind::AddrOf(BorrowKind::Ref, ..) => break, + _ if matches!( + typeck.expr_adjustments(prev_expr).first(), + Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)) + | Adjust::Deref(_), + .. + }) + ) => + { + break; + }, + _ => {}, + } + } + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + break; + } + }, + // Already processed uses. + UseKind::AutoBorrowed | UseKind::WillAutoDeref | UseKind::Deref => {}, + } + } + + if can_lint + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + // This case could be handled, but a fair bit of care would need to be taken. + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + { + if requires_deref { + edits.push((param.span.shrink_to_lo(), "&".into())); + } else { + edits.extend(addr_of_edits); + } + edits.push(( + name_span, + String::from(match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }), + )); + edits.push(( + final_expr + .span + .with_leading_whitespace(cx) + .with_ctxt(final_expr.span.ctxt()), + String::new(), + )); + let app = if edits.iter().any(|(s, _)| s.from_expansion()) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { + diag.multipart_suggestion("try", edits, app); + }); + } + } +} + +enum UseKind<'tcx> { + AutoBorrowed, + WillAutoDeref, + Deref, + Return(Span), + Borrowed(Span), + FieldAccess(Symbol, &'tcx Expr<'tcx>), +} + +/// Checks how the value is used, and whether it was used in the same `SyntaxContext`. +fn check_use<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (UseKind<'tcx>, bool) { + let use_cx = expr_use_ctxt(cx, e); + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Deref(_))) + { + return (UseKind::AutoBorrowed, use_cx.same_ctxt); + } + let res = match use_cx.use_node(cx) { + ExprUseNode::Return(_) => { + if let ExprKind::Ret(Some(e)) = use_cx.node.expect_expr().kind { + UseKind::Return(e.span) + } else { + return (UseKind::Return(DUMMY_SP), false); + } + }, + ExprUseNode::FieldAccess(name) => UseKind::FieldAccess(name.name, use_cx.node.expect_expr()), + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)))) => + { + UseKind::AutoBorrowed + }, + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) => UseKind::WillAutoDeref, + ExprUseNode::AddrOf(BorrowKind::Ref, _) => UseKind::Borrowed(use_cx.node.expect_expr().span), + _ => UseKind::Deref, + }; + (res, use_cx.same_ctxt) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6200716afbe9..1408f4548200 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -53,6 +53,7 @@ mod iter_with_drain; mod iterator_step_by_zero; mod join_absolute_paths; mod manual_c_str_literals; +mod manual_inspect; mod manual_is_variant_and; mod manual_next_back; mod manual_ok_or; @@ -116,6 +117,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_min_or_max; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; mod unnecessary_to_owned; @@ -3944,6 +3946,31 @@ declare_clippy_lint! { "cloning an `Option` via `as_ref().cloned()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for unnecessary calls to `min()` or `max()` in the following cases + /// - Either both side is constant + /// - One side is clearly larger than the other, like i32::MIN and an i32 variable + /// + /// ### Why is this bad? + /// + /// In the aformentioned cases it is not necessary to call `min()` or `max()` + /// to compare values, it may even cause confusion. + /// + /// ### Example + /// ```no_run + /// let _ = 0.min(7_u32); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = 0; + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_MIN_OR_MAX, + complexity, + "using 'min()/max()' when there is no need for it" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `.map_or_else()` "map closure" for `Result` type. @@ -4079,6 +4106,27 @@ declare_clippy_lint! { "is_ascii() called on a char iterator" } +declare_clippy_lint! { + /// ### What it does + /// Checks for uses of `map` which return the original item. + /// + /// ### Why is this bad? + /// `inspect` is both clearer in intent and shorter. + /// + /// ### Example + /// ```no_run + /// let x = Some(0).map(|x| { println!("{x}"); x }); + /// ``` + /// Use instead: + /// ```no_run + /// let x = Some(0).inspect(|x| println!("{x}")); + /// ``` + #[clippy::version = "1.78.0"] + pub MANUAL_INSPECT, + complexity, + "use of `map` returning the original item" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4244,6 +4292,8 @@ impl_lint_pass!(Methods => [ MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, + MANUAL_INSPECT, + UNNECESSARY_MIN_OR_MAX, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4543,6 +4593,9 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, + ("min" | "max", [arg]) => { + unnecessary_min_or_max::check(cx, expr, name, recv, arg); + }, ("drain", ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) @@ -4747,6 +4800,7 @@ impl Methods { } } map_identity::check(cx, expr, recv, m_arg, name, span); + manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv); }, ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs new file mode 100644 index 000000000000..78851d4122f1 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -0,0 +1,90 @@ +use std::cmp::Ordering; + +use super::UNNECESSARY_MIN_OR_MAX; +use clippy_utils::diagnostics::span_lint_and_sugg; + +use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt}; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + name: &str, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + let typeck_results = cx.typeck_results(); + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; + + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } +} + +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { + let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; + + let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { + snippet(cx, rhs, "..") + } else { + snippet(cx, lhs, "..") + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_MIN_OR_MAX, + expr.span, + format!( + "`{}` is never {} than `{}` and has therefore no effect", + snippet(cx, lhs, ".."), + cmp_str, + snippet(cx, rhs, "..") + ), + "try", + suggested_value.to_string(), + Applicability::MachineApplicable, + ); +} + +#[derive(Debug)] +enum Extrema { + Minimum, + Maximum, +} +fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + let ty = cx.typeck_results().expr_ty(expr); + + let cv = constant(cx, cx.typeck_results(), expr)?; + + match (cv.int_value(cx, ty)?, ty.kind()) { + (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum), + (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(0), &ty::Uint(_)) => Some(Extrema::Minimum), + _ => None, + } +} diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 4592324809fa..bb0d714a31fd 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,11 +1,11 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; -use rustc_hir as hir; +use rustc_errors::Applicability; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; +use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) { + if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() { return; } }, @@ -147,10 +147,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) { - span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); + if let Ok(()) = is_min_const_fn(cx.tcx, mir, &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) + { + let suggestion = if vis_span.is_empty() { "const " } else { " const" }; + span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| { + diag.span_suggestion_verbose( + vis_span.shrink_to_hi(), + "make the function `const`", + suggestion, + Applicability::MachineApplicable, + ); + }); } } + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ca344dc5c810..250fd5cbd483 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -8,7 +8,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -266,8 +266,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { - let Some(snippet) = snippet_opt(cx, search_span) else { - return false; - }; - snippet.lines().rev().any(|line| line.trim().starts_with("///")) + search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///"))) } diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index d608f3bf7b4d..d276e29bacec 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; declare_clippy_lint! { /// ### What it does @@ -54,8 +54,10 @@ impl EarlyLintPass for MultipleBoundLocations { match clause { WherePredicate::BoundPredicate(pred) => { if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty()) - && let Some(name) = snippet_opt(cx, pred.bounded_ty.span) - && let Some(bound_span) = generic_params_with_bounds.get(name.as_str()) + && let Some(Some(bound_span)) = pred + .bounded_ty + .span + .with_source_text(cx, |src| generic_params_with_bounds.get(src)) { emit_lint(cx, *bound_span, pred.bounded_ty.span); } diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index f4846a1753f7..064ce59c234e 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -80,11 +80,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if matches!(expr.kind, ExprKind::AddrOf(..)) && !expr.span.from_expansion() - && let Some(use_cx) = expr_use_ctxt(cx, expr) + && let use_cx = expr_use_ctxt(cx, expr) + && use_cx.same_ctxt && !use_cx.is_ty_unified - && let Some(DefinedTy::Mir(ty)) = use_cx.node.defined_ty(cx) + && let use_node = use_cx.use_node(cx) + && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx) && let ty::Param(ty) = *ty.value.skip_binder().kind() - && let Some((hir_id, fn_id, i)) = match use_cx.node { + && let Some((hir_id, fn_id, i)) = match use_node { ExprUseNode::MethodArg(_, _, 0) => None, ExprUseNode::MethodArg(hir_id, None, i) => cx .typeck_results() diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index b6aad69d1668..f8bb72a16db2 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, trim_span}; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -41,16 +41,16 @@ impl EarlyLintPass for NeedlessElse { && !expr.span.from_expansion() && !else_clause.span.from_expansion() && block.stmts.is_empty() - && let Some(trimmed) = expr.span.trim_start(then_block.span) - && let span = trim_span(cx.sess().source_map(), trimmed) - && let Some(else_snippet) = snippet_opt(cx, span) - // Ignore else blocks that contain comments or #[cfg]s - && !else_snippet.contains(['/', '#']) + && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) + && range.clone().check_source_text(cx, |src| { + // Ignore else blocks that contain comments or #[cfg]s + !src.contains(['/', '#']) + }) { span_lint_and_sugg( cx, NEEDLESS_ELSE, - span, + range.with_ctxt(expr.span.ctxt()), "this `else` branch is empty", "you can remove it", String::new(), diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 630018238f4c..143acc2b1cb7 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -25,14 +25,14 @@ declare_clippy_lint! { /// ```no_run /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { - /// println!("{}", elem); + /// println!("{elem}"); /// }) /// ``` /// Use instead: /// ```no_run /// let v = vec![0, 1, 2]; - /// for elem in v.iter() { - /// println!("{}", elem); + /// for elem in &v { + /// println!("{elem}"); /// } /// ``` /// diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 51bee4b51f6f..1d6233d432a7 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -39,18 +39,24 @@ declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]); impl LateLintPass<'_> for NeedlessIf { fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) { if let StmtKind::Expr(expr) = stmt.kind - && let Some(If {cond, then, r#else: None }) = If::hir(expr) + && let Some(If { + cond, + then, + r#else: None, + }) = If::hir(expr) && let ExprKind::Block(block, ..) = then.kind && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && let Some(then_snippet) = snippet_opt(cx, then.span) - // Ignore - // - empty macro expansions - // - empty reptitions in macro expansions - // - comments - // - #[cfg]'d out code - && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) + && then.span.check_source_text(cx, |src| { + // Ignore + // - empty macro expansions + // - empty reptitions in macro expansions + // - comments + // - #[cfg]'d out code + src.bytes() + .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) + }) && let Some(cond_snippet) = snippet_opt(cx, cond.span) && !is_from_proc_macro(cx, expr) { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 2701d6bdca39..b915df527629 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -53,8 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } @@ -65,8 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 2fc039ae886e..2eae9b23746d 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_ast::token::{Lit, LitKind}; +use clippy_utils::source::SpanRangeExt; +use rustc_ast::token::LitKind; +use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::Span; -use std::fmt::Write; +use rustc_span::{BytePos, Pos, SpanData}; declare_clippy_lint! { /// ### What it does @@ -52,104 +52,66 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]); impl EarlyLintPass for OctalEscapes { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(token_lit) = &expr.kind { - if matches!(token_lit.kind, LitKind::Str) { - check_lit(cx, token_lit, expr.span, true); - } else if matches!(token_lit.kind, LitKind::ByteStr) { - check_lit(cx, token_lit, expr.span, false); - } - } - } -} - -fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { - let contents = lit.symbol.as_str(); - let mut iter = contents.char_indices().peekable(); - let mut found = vec![]; - - // go through the string, looking for \0[0-7][0-7]? - while let Some((from, ch)) = iter.next() { - if ch == '\\' { - if let Some((_, '0')) = iter.next() { - // collect up to two further octal digits - if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) { - if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() { - to += 1; + if let ExprKind::Lit(lit) = &expr.kind + // The number of bytes from the start of the token to the start of literal's text. + && let start_offset = BytePos::from_u32(match lit.kind { + LitKind::Str => 1, + LitKind::ByteStr | LitKind::CStr => 2, + _ => return, + }) + && !in_external_macro(cx.sess(), expr.span) + { + let s = lit.symbol.as_str(); + let mut iter = s.as_bytes().iter(); + while let Some(&c) = iter.next() { + if c == b'\\' + // Always move the iterator to read the escape char. + && let Some(b'0') = iter.next() + { + // C-style octal escapes read from one to three characters. + // The first character (`0`) has already been read. + let (tail, len, c_hi, c_lo) = match *iter.as_slice() { + [c_hi @ b'0'..=b'7', c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 4, c_hi, c_lo), + [c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 3, b'0', c_lo), + _ => continue, + }; + iter = tail.iter(); + let offset = start_offset + BytePos::from_usize(s.len() - tail.len()); + let data = expr.span.data(); + let span = SpanData { + lo: data.lo + offset - BytePos::from_u32(len), + hi: data.lo + offset, + ..data + } + .span(); + + // Last check to make sure the source text matches what we read from the string. + // Macros are involved somehow if this doesn't match. + if span.check_source_text(cx, |src| match *src.as_bytes() { + [b'\\', b'0', lo] => lo == c_lo, + [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, + _ => false, + }) { + span_lint_and_then(cx, OCTAL_ESCAPES, span, "octal-looking escape in a literal", |diag| { + diag.help_once("octal escapes are not supported, `\\0` is always null") + .span_suggestion( + span, + "if an octal escape is intended, use a hex escape instead", + format!("\\x{:02x}", (((c_hi - b'0') << 3) | (c_lo - b'0'))), + Applicability::MaybeIncorrect, + ) + .span_suggestion( + span, + "if a null escape is intended, disambiguate using", + format!("\\x00{}{}", c_hi as char, c_lo as char), + Applicability::MaybeIncorrect, + ); + }); + } else { + break; } - found.push((from, to + 1)); } } } } - - if found.is_empty() { - return; - } - - span_lint_and_then( - cx, - OCTAL_ESCAPES, - span, - format!( - "octal-looking escape in {} literal", - if is_string { "string" } else { "byte string" } - ), - |diag| { - diag.help(format!( - "octal escapes are not supported, `\\0` is always a null {}", - if is_string { "character" } else { "byte" } - )); - - // Generate suggestions if the string is not too long (~ 5 lines) - if contents.len() < 400 { - // construct two suggestion strings, one with \x escapes with octal meaning - // as in C, and one with \x00 for null bytes. - let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); - let mut suggest_2 = suggest_1.clone(); - let mut index = 0; - for (from, to) in found { - suggest_1.push_str(&contents[index..from]); - suggest_2.push_str(&contents[index..from]); - - // construct a replacement escape - // the maximum value is \077, or \x3f, so u8 is sufficient here - if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{n:02x}").unwrap(); - } - - // append the null byte as \x00 and the following digits literally - suggest_2.push_str("\\x00"); - suggest_2.push_str(&contents[from + 2..to]); - - index = to; - } - suggest_1.push_str(&contents[index..]); - suggest_2.push_str(&contents[index..]); - - suggest_1.push('"'); - suggest_2.push('"'); - // suggestion 1: equivalent hex escape - diag.span_suggestion( - span, - "if an octal escape was intended, use the hexadecimal representation instead", - suggest_1, - Applicability::MaybeIncorrect, - ); - // suggestion 2: unambiguous null byte - diag.span_suggestion( - span, - format!( - "if the null {} is intended, disambiguate using", - if is_string { "character" } else { "byte" } - ), - suggest_2, - Applicability::MaybeIncorrect, - ); - } - }, - ); } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 186e548d3730..4fdaa9f00a19 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -285,9 +285,10 @@ fn check_possible_range_contains( if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && let Some(snip) = &snippet_opt(cx, new_span) - // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - && snip.matches('(').count() == snip.matches(')').count() + && new_span.check_source_text(cx, |src| { + // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong + src.matches('(').count() == src.matches(')').count() + }) { check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); } @@ -363,17 +364,19 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { |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(); - if let Some(is_wrapped) = &snippet_opt(cx, span) { - if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { + 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); - } else { + }, + Some(false) => { diag.span_suggestion( span, "use", format!("{start}..={end}"), Applicability::MachineApplicable, // snippet ); - } + }, + None => {}, } }, ); diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 64b5b8f9f27b..7ba58942a175 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; @@ -12,7 +13,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -69,7 +70,18 @@ declare_clippy_lint! { "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } -declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); +pub struct StringPatterns { + msrv: Msrv, +} + +impl StringPatterns { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); const PATTERN_METHODS: [(&str, usize); 22] = [ ("contains", 0), @@ -122,7 +134,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio } } -fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) { +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: &Msrv) { if let ExprKind::Closure(closure) = method_arg.kind && let body = cx.tcx.hir().body(closure.body) && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) @@ -178,6 +190,9 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< { return; } + if set_char_spans.len() > 1 && !msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) { + return; + } span_lint_and_then( cx, MANUAL_PATTERN_CHAR_COMPARISON, @@ -221,7 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { { check_single_char_pattern_lint(cx, arg); - check_manual_pattern_char_comparison(cx, arg); + check_manual_pattern_char_comparison(cx, arg, &self.msrv); } } + + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index f376d3496461..72392f8e1f74 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use itertools::Itertools; +use core::mem::replace; use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -56,55 +56,71 @@ impl UpperCaseAcronyms { impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]); -fn correct_ident(ident: &str) -> String { - let ident = ident.chars().rev().collect::(); - let fragments = ident - .split_inclusive(|x: char| !x.is_ascii_lowercase()) - .rev() - .map(|x| x.chars().rev().collect::()); - - let mut ident = fragments.clone().next().unwrap(); - for (ref prev, ref curr) in fragments.tuple_windows() { - if <[&String; 2]>::from((prev, curr)) - .iter() - .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase()) - { - ident.push_str(&curr.to_ascii_lowercase()); +fn contains_acronym(s: &str) -> bool { + let mut count = 0; + for c in s.chars() { + if c.is_ascii_uppercase() { + count += 1; + if count == 3 { + return true; + } } else { - ident.push_str(curr); + count = 0; } } - ident + count == 2 } fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) { - let span = ident.span; - let ident = ident.as_str(); - let corrected = correct_ident(ident); - // warn if we have pure-uppercase idents - // assume that two-letter words are some kind of valid abbreviation like FP for false positive - // (and don't warn) - if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2) - // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive - // upper-case-acronyms-aggressive config option enabled - || (be_aggressive && ident != corrected) + let s = ident.as_str(); + + // By default, only warn for upper case identifiers with at least 3 characters. + let replacement = if s.len() > 2 && s.bytes().all(|c| c.is_ascii_uppercase()) { + let mut r = String::with_capacity(s.len()); + let mut s = s.chars(); + r.push(s.next().unwrap()); + r.extend(s.map(|c| c.to_ascii_lowercase())); + r + } else if be_aggressive + // Only lint if the ident starts with an upper case character. + && let unprefixed = s.trim_start_matches('_') + && unprefixed.starts_with(|c: char| c.is_ascii_uppercase()) + && contains_acronym(unprefixed) { - span_lint_hir_and_then( - cx, - UPPER_CASE_ACRONYMS, - hir_id, - span, - format!("name `{ident}` contains a capitalized acronym"), - |diag| { - diag.span_suggestion( - span, - "consider making the acronym lowercase, except the initial letter", - corrected, - Applicability::MaybeIncorrect, - ); - }, - ); - } + let mut r = String::with_capacity(s.len()); + let mut s = s.chars(); + let mut prev_upper = false; + while let Some(c) = s.next() { + r.push( + if replace(&mut prev_upper, c.is_ascii_uppercase()) + && s.clone().next().map_or(true, |c| c.is_ascii_uppercase()) + { + c.to_ascii_lowercase() + } else { + c + }, + ); + } + r + } else { + return; + }; + + span_lint_hir_and_then( + cx, + UPPER_CASE_ACRONYMS, + hir_id, + ident.span, + format!("name `{ident}` contains a capitalized acronym"), + |diag| { + diag.span_suggestion( + ident.span, + "consider making the acronym lowercase, except the initial letter", + replacement, + Applicability::MaybeIncorrect, + ); + }, + ); } impl LateLintPass<'_> for UpperCaseAcronyms { diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index c62ae8d718db..0beb0bb8ed4c 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -69,6 +69,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Float(FloatTy::F64), SimplifiedType::Slice, SimplifiedType::Str, + SimplifiedType::Bool, ] .iter() .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter()) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 785d5ed5dbeb..13256c5557da 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -724,9 +724,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg), ImplTrait(_, rg)) => { - over(lg, rg, eq_generic_bound) - }, + (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), _ => false, diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 553e89999750..7f2234b310b4 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -18,8 +18,8 @@ use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, Safety, TraitItem, - TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, + ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, + TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -121,6 +121,26 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { } } +fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { + let (head, tail) = match path.segments { + [head, .., tail] => (head, tail), + [p] => (p, p), + [] => return (Pat::Str(""), Pat::Str("")), + }; + ( + if head.ident.name == kw::PathRoot { + Pat::Str("::") + } else { + Pat::Sym(head.ident.name) + }, + if tail.args.is_some() { + Pat::Str(">") + } else { + Pat::Sym(tail.ident.name) + }, + ) +} + /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { @@ -355,19 +375,21 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { } } +fn ident_search_pat(ident: Ident) -> (Pat, Pat) { + (Pat::Sym(ident.name), Pat::Sym(ident.name)) +} + pub trait WithSearchPat<'cx> { type Context: LintContext; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); fn span(&self) -> Span; } macro_rules! impl_with_search_pat { - ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { - impl<'cx> WithSearchPat<'cx> for $ty<'cx> { - type Context = $cx<'cx>; - #[allow(unused_variables)] - fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { - $(let $tcx = cx.tcx;)? - $fn($($tcx,)? self) + (($cx_ident:ident: $cx_ty:ident<$cx_lt:lifetime>, $self:tt: $ty:ty) => $fn:ident($($args:tt)*)) => { + impl<$cx_lt> WithSearchPat<$cx_lt> for $ty { + type Context = $cx_ty<$cx_lt>; + fn search_pat(&$self, $cx_ident: &Self::Context) -> (Pat, Pat) { + $fn($($args)*) } fn span(&self) -> Span { self.span @@ -375,13 +397,17 @@ macro_rules! impl_with_search_pat { } }; } -impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx)); -impl_with_search_pat!(LateContext: Item with item_search_pat); -impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); -impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); -impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); -impl_with_search_pat!(LateContext: Variant with variant_search_pat); -impl_with_search_pat!(LateContext: Ty with ty_search_pat); +impl_with_search_pat!((cx: LateContext<'tcx>, self: Expr<'tcx>) => expr_search_pat(cx.tcx, self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Item<'_>) => item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: TraitItem<'_>) => trait_item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: ImplItem<'_>) => impl_item_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: FieldDef<'_>) => field_def_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Variant<'_>) => variant_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Attribute) => attr_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { type Context = LateContext<'cx>; @@ -395,32 +421,6 @@ impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { } } -// `Attribute` does not have the `hir` associated lifetime, so we cannot use the macro -impl<'cx> WithSearchPat<'cx> for &'cx Attribute { - type Context = LateContext<'cx>; - - fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { - attr_search_pat(self) - } - - fn span(&self) -> Span { - self.span - } -} - -// `Ident` does not have the `hir` associated lifetime, so we cannot use the macro -impl<'cx> WithSearchPat<'cx> for Ident { - type Context = LateContext<'cx>; - - fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { - (Pat::Sym(self.name), Pat::Sym(self.name)) - } - - fn span(&self) -> Span { - self.span - } -} - /// Checks if the item likely came from a proc-macro. /// /// This should be called after `in_external_macro` and the initial pattern matching of the ast as diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 681c86f76d07..de6ccfe476fb 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,6 +1,7 @@ #![allow(clippy::float_cmp)] -use crate::source::{get_source_text, walk_span_to_context}; +use crate::macros::HirNode; +use crate::source::{walk_span_to_context, SpanRangeExt}; use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_apfloat::ieee::{Half, Quad}; @@ -17,7 +18,7 @@ use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; use rustc_target::abi::Size; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; @@ -326,6 +327,8 @@ pub enum ConstantSource { Local, /// The value is dependent on a defined constant. Constant, + /// The value is dependent on a constant defined in `core` crate. + CoreConstant, } impl ConstantSource { pub fn is_local(&self) -> bool { @@ -439,9 +442,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { + let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() { + self.lcx.tcx.crate_name(def_id.krate) == sym::core + } else { + false + }; self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; - this.source = ConstantSource::Constant; + // If source is already Constant we wouldn't want to override it with CoreConstant + this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) { + ConstantSource::CoreConstant + } else { + ConstantSource::Constant + }; Some(result) }) }, @@ -683,7 +696,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) + && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 801a98521590..277ba8427e05 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -218,51 +218,56 @@ pub struct Range<'a> { impl<'a> Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. + #[allow(clippy::similar_names)] pub fn hir(expr: &'a Expr<'_>) -> Option> { - /// Finds the field named `name` in the field. Always return `Some` for - /// convenience. - fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c Expr<'c>> { - let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr; - Some(expr) - } - match expr.kind { - ExprKind::Call(path, args) + ExprKind::Call(path, [arg1, arg2]) if matches!( path.kind, ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..)) ) => { Some(Range { - start: Some(&args[0]), - end: Some(&args[1]), + start: Some(arg1), + end: Some(arg2), limits: ast::RangeLimits::Closed, }) }, - ExprKind::Struct(path, fields, None) => match &path { - QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range { + ExprKind::Struct(path, fields, None) => match (path, fields) { + (QPath::LangItem(hir::LangItem::RangeFull, ..), []) => Some(Range { start: None, end: None, limits: ast::RangeLimits::HalfOpen, }), - QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range { - start: Some(get_field("start", fields)?), - end: None, - limits: ast::RangeLimits::HalfOpen, - }), - QPath::LangItem(hir::LangItem::Range, ..) => Some(Range { - start: Some(get_field("start", fields)?), - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::HalfOpen, - }), - QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range { + (QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => { + Some(Range { + start: Some(field.expr), + end: None, + limits: ast::RangeLimits::HalfOpen, + }) + }, + (QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => { + let (start, end) = match (field1.ident.name, field2.ident.name) { + (sym::start, sym::end) => (field1.expr, field2.expr), + (sym::end, sym::start) => (field2.expr, field1.expr), + _ => return None, + }; + Some(Range { + start: Some(start), + end: Some(end), + limits: ast::RangeLimits::HalfOpen, + }) + }, + (QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => { + Some(Range { + start: None, + end: Some(field.expr), + limits: ast::RangeLimits::Closed, + }) + }, + (QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range { start: None, - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::Closed, - }), - QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range { - start: None, - end: Some(get_field("end", fields)?), + end: Some(field.expr), limits: ast::RangeLimits::HalfOpen, }), _ => None, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 50dd8430ac06..8706cec5d388 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -1173,9 +1173,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = get_source_text(cx, left) + if let Some(lsrc) = left.get_source_text(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = right.get_source_text(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ee43d95272a0..935a25d79319 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2666,13 +2666,80 @@ pub enum DefinedTy<'tcx> { /// The context an expressions value is used in. pub struct ExprUseCtxt<'tcx> { /// The parent node which consumes the value. - pub node: ExprUseNode<'tcx>, + pub node: Node<'tcx>, + /// The child id of the node the value came from. + pub child_id: HirId, /// Any adjustments applied to the type. pub adjustments: &'tcx [Adjustment<'tcx>], - /// Whether or not the type must unify with another code path. + /// Whether the type must unify with another code path. pub is_ty_unified: bool, - /// Whether or not the value will be moved before it's used. + /// Whether the value will be moved before it's used. pub moved_before_use: bool, + /// Whether the use site has the same `SyntaxContext` as the value. + pub same_ctxt: bool, +} +impl<'tcx> ExprUseCtxt<'tcx> { + pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> { + match self.node { + Node::LetStmt(l) => ExprUseNode::LetStmt(l), + Node::ExprField(field) => ExprUseNode::Field(field), + + Node::Item(&Item { + kind: ItemKind::Static(..) | ItemKind::Const(..), + owner_id, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Const(..), + owner_id, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Const(..), + owner_id, + .. + }) => ExprUseNode::ConstStatic(owner_id), + + Node::Item(&Item { + kind: ItemKind::Fn(..), + owner_id, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(..), + owner_id, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(..), + owner_id, + .. + }) => ExprUseNode::Return(owner_id), + + Node::Expr(use_expr) => match use_expr.kind { + ExprKind::Ret(_) => ExprUseNode::Return(OwnerId { + def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + }), + + ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }), + ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) { + Some(i) => ExprUseNode::FnArg(func, i), + None => ExprUseNode::Callee, + }, + ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg( + use_expr.hir_id, + name.args, + args.iter() + .position(|arg| arg.hir_id == self.child_id) + .map_or(0, |i| i + 1), + ), + ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name), + ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl), + _ => ExprUseNode::Other, + }, + _ => ExprUseNode::Other, + } + } } /// The node which consumes a value. @@ -2693,7 +2760,8 @@ pub enum ExprUseNode<'tcx> { Callee, /// Access of a field. FieldAccess(Ident), - Expr, + /// Borrow expression. + AddrOf(ast::BorrowKind, Mutability), Other, } impl<'tcx> ExprUseNode<'tcx> { @@ -2770,26 +2838,25 @@ impl<'tcx> ExprUseNode<'tcx> { let sig = cx.tcx.fn_sig(id).skip_binder(); Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) }, - Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None, + Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None, } } } /// Gets the context an expression's value is used in. -pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option> { +pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> { let mut adjustments = [].as_slice(); let mut is_ty_unified = false; let mut moved_before_use = false; + let mut same_ctxt = true; let ctxt = e.span.ctxt(); - walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| { + let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow { if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir_node(child_id) { adjustments = cx.typeck_results().expr_adjustments(e); } - if cx.tcx.hir().span(parent_id).ctxt() != ctxt { - return ControlFlow::Break(()); - } + same_ctxt &= cx.tcx.hir().span(parent_id).ctxt() == ctxt; if let Node::Expr(e) = parent { match e.kind { ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => { @@ -2805,71 +2872,26 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio } } ControlFlow::Continue(()) - })? - .continue_value() - .map(|(use_node, child_id)| { - let node = match use_node { - Node::LetStmt(l) => ExprUseNode::LetStmt(l), - Node::ExprField(field) => ExprUseNode::Field(field), - - Node::Item(&Item { - kind: ItemKind::Static(..) | ItemKind::Const(..), - owner_id, - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Const(..), - owner_id, - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Const(..), - owner_id, - .. - }) => ExprUseNode::ConstStatic(owner_id), - - Node::Item(&Item { - kind: ItemKind::Fn(..), - owner_id, - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Fn(..), - owner_id, - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(..), - owner_id, - .. - }) => ExprUseNode::Return(owner_id), - - Node::Expr(use_expr) => match use_expr.kind { - ExprKind::Ret(_) => ExprUseNode::Return(OwnerId { - def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - }), - ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }), - ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == child_id) { - Some(i) => ExprUseNode::FnArg(func, i), - None => ExprUseNode::Callee, - }, - ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg( - use_expr.hir_id, - name.args, - args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1), - ), - ExprKind::Field(child, name) if child.hir_id == e.hir_id => ExprUseNode::FieldAccess(name), - _ => ExprUseNode::Expr, - }, - _ => ExprUseNode::Other, - }; - ExprUseCtxt { + }); + match node { + Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt { node, + child_id, adjustments, is_ty_unified, moved_before_use, - } - }) + same_ctxt, + }, + Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow"), + None => ExprUseCtxt { + node: Node::Crate(cx.tcx.hir().root_module()), + child_id: HirId::INVALID, + adjustments: &[], + is_ty_unified: true, + moved_before_use: true, + same_ctxt: false, + }, + } } /// Tokenizes the input while keeping the text associated with each token. diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 7b4fd8a210ed..07e6705cd3d9 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -69,7 +69,7 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { let lhs = place.local; match rvalue { - mir::Rvalue::Ref(_, _, borrowed) => { + mir::Rvalue::Ref(_, _, borrowed) | mir::Rvalue::CopyForDeref(borrowed) => { self.possible_borrower.add(borrowed.local, lhs); }, other => { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9bf068ee3cde..3f66813801dc 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -110,5 +110,4 @@ pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; -#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index e2e5cde947d8..496c8f5b5537 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -9,12 +9,16 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{ + hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + DUMMY_SP, +}; use std::borrow::Cow; +use std::fmt; use std::ops::Range; -/// A type which can be converted to the range portion of a `Span`. -pub trait SpanRange { +/// Conversion of a value into the range portion of a `Span`. +pub trait SpanRange: Sized { fn into_range(self) -> Range; } impl SpanRange for Span { @@ -34,6 +38,182 @@ impl SpanRange for Range { } } +/// Conversion of a value into a `Span` +pub trait IntoSpan: Sized { + fn into_span(self) -> Span; + fn with_ctxt(self, ctxt: SyntaxContext) -> Span; +} +impl IntoSpan for Span { + fn into_span(self) -> Span { + self + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.with_ctxt(ctxt) + } +} +impl IntoSpan for SpanData { + fn into_span(self) -> Span { + self.span() + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.lo, self.hi, ctxt, self.parent) + } +} +impl IntoSpan for Range { + fn into_span(self) -> Span { + Span::with_root_ctxt(self.start, self.end) + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.start, self.end, ctxt, None) + } +} + +pub trait SpanRangeExt: SpanRange { + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span + /// extends through multiple files, or is malformed. + fn get_source_text(self, cx: &impl LintContext) -> Option { + get_source_text(cx.sess().source_map(), self.into_range()) + } + + /// Calls the given function with the source text referenced and returns the value. Returns + /// `None` if the source text cannot be retrieved. + fn with_source_text(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + with_source_text(cx.sess().source_map(), self.into_range(), f) + } + + /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the + /// source text cannot be retrieved. + fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + self.with_source_text(cx, pred).unwrap_or(false) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and returns the value. Returns `None` if the source text cannot be retrieved. + fn with_source_text_and_range( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range) -> T, + ) -> Option { + with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and creates a new span with the returned range. Returns `None` if the source text cannot be + /// retrieved, or no result is returned. + /// + /// The new range must reside within the same source file. + fn map_range( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range) -> Option>, + ) -> Option> { + map_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Extends the range to include all preceding whitespace characters. + fn with_leading_whitespace(self, cx: &impl LintContext) -> Range { + with_leading_whitespace(cx.sess().source_map(), self.into_range()) + } + + /// Trims the leading whitespace from the range. + fn trim_start(self, cx: &impl LintContext) -> Range { + trim_start(cx.sess().source_map(), self.into_range()) + } + + /// Writes the referenced source text to the given writer. Will return `Err` if the source text + /// could not be retrieved. + fn write_source_text_to(self, cx: &impl LintContext, dst: &mut impl fmt::Write) -> fmt::Result { + write_source_text_to(cx.sess().source_map(), self.into_range(), dst) + } + + /// Extracts the referenced source text as an owned string. + fn source_text_to_string(self, cx: &impl LintContext) -> Option { + self.with_source_text(cx, ToOwned::to_owned) + } +} +impl SpanRangeExt for T {} + +fn get_source_text(sm: &SourceMap, sp: Range) -> Option { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { sf: start.sf, range }) +} + +fn with_source_text(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + if let Some(src) = get_source_text(sm, sp) + && let Some(src) = src.as_str() + { + Some(f(src)) + } else { + None + } +} + +fn with_source_text_and_range( + sm: &SourceMap, + sp: Range, + f: impl for<'a> FnOnce(&'a str, Range) -> T, +) -> Option { + if let Some(src) = get_source_text(sm, sp) + && let Some(text) = &src.sf.src + { + Some(f(text, src.range)) + } else { + None + } +} + +#[expect(clippy::cast_possible_truncation)] +fn map_range( + sm: &SourceMap, + sp: Range, + f: impl for<'a> FnOnce(&'a str, Range) -> Option>, +) -> Option> { + if let Some(src) = get_source_text(sm, sp.clone()) + && let Some(text) = &src.sf.src + && let Some(range) = f(text, src.range.clone()) + { + debug_assert!( + range.start <= text.len() && range.end <= text.len(), + "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", + src.sf.name.display(FileNameDisplayPreference::Local), + text.len(), + ); + debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); + let dstart = (range.start as u32).wrapping_sub(src.range.start as u32); + let dend = (range.end as u32).wrapping_sub(src.range.start as u32); + Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend))) + } else { + None + } +} + +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) + }) + .unwrap_or(sp) +} + +fn trim_start(sm: &SourceMap, sp: Range) -> Range { + map_range(sm, sp.clone(), |src, range| { + let src = src.get(range.clone())?; + Some(range.start + (src.len() - src.trim_start().len())..range.end) + }) + .unwrap_or(sp) +} + +fn write_source_text_to(sm: &SourceMap, sp: Range, dst: &mut impl fmt::Write) -> fmt::Result { + match with_source_text(sm, sp, |src| dst.write_str(src)) { + Some(x) => x, + None => Err(fmt::Error), + } +} + pub struct SourceFileRange { pub sf: Lrc, pub range: Range, @@ -46,21 +226,6 @@ impl SourceFileRange { } } -/// Gets the source file, and range in the file, of the given span. Returns `None` if the span -/// extends through multiple files, or is malformed. -pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option { - fn f(sm: &SourceMap, sp: Range) -> Option { - let start = sm.lookup_byte_offset(sp.start); - let end = sm.lookup_byte_offset(sp.end); - if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { - return None; - } - let range = start.pos.to_usize()..end.pos.to_usize(); - Some(SourceFileRange { sf: start.sf, range }) - } - f(cx.sess().source_map(), sp.into_range()) -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block( cx: &T, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 3790a852f7ed..e5d205641968 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1349,3 +1349,17 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n None } } + +/// Get's 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 + .non_enum_variant() + .fields + .iter() + .find(|f| f.name == name) + .map(|f| f.ty(tcx, args)), + ty::Tuple(args) => name.as_str().parse::().ok().and_then(|i| args.get(i).copied()), + _ => None, + } +} diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml index 8c5a409e25b1..ae9e77b8eed0 100644 --- a/lintcheck/Cargo.toml +++ b/lintcheck/Cargo.toml @@ -11,28 +11,19 @@ publish = false default-run = "lintcheck" [dependencies] -anyhow = "1.0.69" cargo_metadata = "0.15.3" clap = { version = "4.4", features = ["derive", "env"] } -crates_io_api = "0.8.1" crossbeam-channel = "0.5.6" +diff = "0.1.13" flate2 = "1.0" -indicatif = "0.17.3" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.85" +strip-ansi-escapes = "0.2.0" tar = "0.4" toml = "0.7.3" -ureq = "2.2" +ureq = { version = "2.2", features = ["json"] } walkdir = "2.3" [features] deny-warnings = [] - -[[bin]] -name = "lintcheck" -path = "src/main.rs" - -[[bin]] -name = "popular-crates" -path = "src/popular-crates.rs" diff --git a/lintcheck/README.md b/lintcheck/README.md index 61b581ba0fae..2d6039caeef0 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -26,11 +26,11 @@ the repo root. The results will then be saved to `lintcheck-logs/custom_logs.toml`. The `custom.toml` file may be built using recently most -downloaded crates by using the `popular-crates` binary from the `lintcheck` -directory. For example, to retrieve the 100 recently most downloaded crates: +downloaded crates by using `cargo lintcheck popular`. For example, to retrieve +the 200 recently most downloaded crates: ``` -cargo run --release --bin popular-crates -- -n 100 custom.toml +cargo lintcheck popular -n 200 custom.toml ``` diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index 3f712f453fa0..e6cd7c9fdc2b 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -1,8 +1,9 @@ -use clap::Parser; +use clap::{Parser, Subcommand, ValueEnum}; use std::num::NonZero; use std::path::PathBuf; -#[derive(Clone, Debug, Parser)] +#[derive(Parser, Clone, Debug)] +#[command(args_conflicts_with_subcommands = true)] pub(crate) struct LintcheckConfig { /// Number of threads to use (default: all unless --fix or --recursive) #[clap( @@ -35,12 +36,45 @@ pub(crate) struct LintcheckConfig { /// Apply a filter to only collect specified lints, this also overrides `allow` attributes #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)] pub lint_filter: Vec, - /// Change the reports table to use markdown links - #[clap(long)] - pub markdown: bool, + /// Set the output format of the log file + #[clap(long, short, default_value = "text")] + pub format: OutputFormat, /// Run clippy on the dependencies of crates specified in crates-toml #[clap(long, conflicts_with("max_jobs"))] pub recursive: bool, + #[command(subcommand)] + pub subcommand: Option, +} + +#[derive(Subcommand, Clone, Debug)] +pub(crate) enum Commands { + /// Display a markdown diff between two lintcheck log files in JSON format + Diff { old: PathBuf, new: PathBuf }, + /// Create a lintcheck crates TOML file containing the top N popular crates + Popular { + /// Output TOML file name + output: PathBuf, + /// Number of crate names to download + #[clap(short, long, default_value_t = 100)] + number: usize, + }, +} + +#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum OutputFormat { + Text, + Markdown, + Json, +} + +impl OutputFormat { + fn file_extension(self) -> &'static str { + match self { + OutputFormat::Text => "txt", + OutputFormat::Markdown => "md", + OutputFormat::Json => "json", + } + } } impl LintcheckConfig { @@ -53,7 +87,7 @@ impl LintcheckConfig { config.lintcheck_results_path = PathBuf::from(format!( "lintcheck-logs/{}_logs.{}", filename.display(), - if config.markdown { "md" } else { "txt" } + config.format.file_extension(), )); // look at the --threads arg, if 0 is passed, use the threads count diff --git a/lintcheck/src/json.rs b/lintcheck/src/json.rs new file mode 100644 index 000000000000..43d0413c7cee --- /dev/null +++ b/lintcheck/src/json.rs @@ -0,0 +1,122 @@ +use std::collections::HashMap; +use std::fmt::Write; +use std::fs; +use std::hash::Hash; +use std::path::Path; + +use crate::ClippyWarning; + +/// Creates the log file output for [`crate::config::OutputFormat::Json`] +pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String { + serde_json::to_string(&clippy_warnings).unwrap() +} + +fn load_warnings(path: &Path) -> Vec { + let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display())); + + serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display())) +} + +/// Group warnings by their primary span location + lint name +fn create_map(warnings: &[ClippyWarning]) -> HashMap> { + let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len()); + + for warning in warnings { + let span = warning.span(); + let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end); + + map.entry(key).or_default().push(warning); + } + + map +} + +fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { + if warnings.is_empty() { + return; + } + + println!("### {title}"); + println!("```"); + for warning in warnings { + print!("{}", warning.diag); + } + println!("```"); +} + +fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) { + fn render(warnings: &[&ClippyWarning]) -> String { + let mut rendered = String::new(); + for warning in warnings { + write!(&mut rendered, "{}", warning.diag).unwrap(); + } + rendered + } + + if changed.is_empty() { + return; + } + + println!("### Changed"); + println!("```diff"); + for &(old, new) in changed { + let old_rendered = render(old); + let new_rendered = render(new); + + for change in diff::lines(&old_rendered, &new_rendered) { + use diff::Result::{Both, Left, Right}; + + match change { + Both(unchanged, _) => { + println!(" {unchanged}"); + }, + Left(removed) => { + println!("-{removed}"); + }, + Right(added) => { + println!("+{added}"); + }, + } + } + } + println!("```"); +} + +pub(crate) fn diff(old_path: &Path, new_path: &Path) { + let old_warnings = load_warnings(old_path); + let new_warnings = load_warnings(new_path); + + let old_map = create_map(&old_warnings); + let new_map = create_map(&new_warnings); + + let mut added = Vec::new(); + let mut removed = Vec::new(); + let mut changed = Vec::new(); + + for (key, new) in &new_map { + if let Some(old) = old_map.get(key) { + if old != new { + changed.push((old.as_slice(), new.as_slice())); + } + } else { + added.extend(new); + } + } + + for (key, old) in &old_map { + if !new_map.contains_key(key) { + removed.extend(old); + } + } + + print!( + "{} added, {} removed, {} changed\n\n", + added.len(), + removed.len(), + changed.len() + ); + + print_warnings("Added", &added); + print_warnings("Removed", &removed); + print_changed_diff(&changed); +} diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index deb06094d83b..ec72e0eb5dcb 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -12,26 +12,29 @@ unused_lifetimes, unused_qualifications )] -#![allow(clippy::collapsible_else_if)] +#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)] mod config; mod driver; +mod json; +mod popular_crates; mod recursive; -use crate::config::LintcheckConfig; +use crate::config::{Commands, LintcheckConfig, OutputFormat}; use crate::recursive::LintcheckServer; use std::collections::{HashMap, HashSet}; use std::env::consts::EXE_SUFFIX; -use std::fmt::{self, Write as _}; +use std::fmt::{self, Display, Write as _}; +use std::hash::Hash; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus}; +use std::process::{Command, ExitStatus, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::{env, fs, thread}; -use cargo_metadata::diagnostic::Diagnostic; +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -41,21 +44,21 @@ const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; /// List of sources to check, loaded from a .toml file -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Deserialize)] struct SourceList { crates: HashMap, #[serde(default)] recursive: RecursiveOptions, } -#[derive(Debug, Serialize, Deserialize, Default)] +#[derive(Debug, Deserialize, Default)] struct RecursiveOptions { ignore: HashSet, } /// A crate source stored inside the .toml /// will be translated into on one of the `CrateSource` variants -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Deserialize)] struct TomlCrate { name: String, versions: Option>, @@ -67,7 +70,7 @@ struct TomlCrate { /// Represents an archive we download from crates.io, or a git repo, or a local repo/folder /// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` -#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] enum CrateSource { CratesIo { name: String, @@ -111,6 +114,17 @@ struct RustcIce { pub crate_name: String, pub ice_content: String, } + +impl Display for RustcIce { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}:\n{}\n========================================\n", + self.crate_name, self.ice_content + ) + } +} + impl RustcIce { pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { if status.code().unwrap_or(0) == 101 @@ -127,60 +141,58 @@ impl RustcIce { } /// A single warning that clippy issued while checking a `Crate` -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] struct ClippyWarning { - file: String, - line: usize, - column: usize, + crate_name: String, + crate_version: String, lint_type: String, - message: String, + diag: Diagnostic, } #[allow(unused)] impl ClippyWarning { - fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { - let lint_type = diag.code?.code; + fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { + let lint_type = diag.code.clone()?.code; if !(lint_type.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") { return None; } - let span = diag.spans.into_iter().find(|span| span.is_primary)?; - - let file = if let Ok(stripped) = Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) { - format!("$CARGO_HOME/{}", stripped.display()) - } else { - format!( - "target/lintcheck/sources/{crate_name}-{crate_version}/{}", - span.file_name - ) - }; + // --recursive bypasses cargo so we have to strip the rendered output ourselves + let rendered = diag.rendered.as_mut().unwrap(); + *rendered = strip_ansi_escapes::strip_str(&rendered); Some(Self { - file, - line: span.line_start, - column: span.column_start, + crate_name: crate_name.to_owned(), + crate_version: crate_version.to_owned(), lint_type, - message: diag.message, + diag, }) } - fn to_output(&self, markdown: bool) -> String { - let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column); - if markdown { - let mut file = self.file.clone(); - if !file.starts_with('$') { - file.insert_str(0, "../"); - } + fn span(&self) -> &DiagnosticSpan { + self.diag.spans.iter().find(|span| span.is_primary).unwrap() + } - let mut output = String::from("| "); - let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line); - let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message); - output.push('\n'); - output - } else { - format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.message) + fn to_output(&self, format: OutputFormat) -> String { + let span = self.span(); + let mut file = span.file_name.clone(); + let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); + match format { + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message), + OutputFormat::Markdown => { + if file.starts_with("target") { + file.insert_str(0, "../"); + } + + let mut output = String::from("| "); + write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap(); + output.push('\n'); + output + }, + OutputFormat::Json => unreachable!("JSON output is handled via serde"), } } } @@ -333,10 +345,9 @@ impl CrateSource { impl Crate { /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy /// issued - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, clippy::too_many_lines)] fn run_clippy_lints( &self, - cargo_clippy_path: &Path, clippy_driver_path: &Path, target_dir_index: &AtomicUsize, total_crates_to_lint: usize, @@ -362,17 +373,27 @@ impl Crate { ); } - let cargo_clippy_path = fs::canonicalize(cargo_clippy_path).unwrap(); - let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); - let mut cargo_clippy_args = if config.fix { - vec!["--quiet", "--fix", "--"] - } else { - vec!["--quiet", "--message-format=json", "--"] - }; + let cargo_home = env!("CARGO_HOME"); + + // `src/lib.rs` -> `target/lintcheck/sources/crate-1.2.3/src/lib.rs` + let remap_relative = format!("={}", self.path.display()); + // Fallback for other sources, `~/.cargo/...` -> `$CARGO_HOME/...` + let remap_cargo_home = format!("{cargo_home}=$CARGO_HOME"); + // `~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crate-2.3.4/src/lib.rs` + // -> `crate-2.3.4/src/lib.rs` + let remap_crates_io = format!("{cargo_home}/registry/src/index.crates.io-6f17d22bba15001f/="); + + let mut clippy_args = vec![ + "--remap-path-prefix", + &remap_relative, + "--remap-path-prefix", + &remap_cargo_home, + "--remap-path-prefix", + &remap_crates_io, + ]; - let mut clippy_args = Vec::<&str>::new(); if let Some(options) = &self.options { for opt in options { clippy_args.push(opt); @@ -388,23 +409,23 @@ impl Crate { clippy_args.extend(lint_filter.iter().map(String::as_str)); } - if let Some(server) = server { - let target = shared_target_dir.join("recursive"); + let mut cmd = Command::new("cargo"); + cmd.arg(if config.fix { "fix" } else { "check" }) + .arg("--quiet") + .current_dir(&self.path) + .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__")); + if let Some(server) = server { // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to // `clippy-driver`. We do the same thing here with a couple changes: // // `RUSTC_WRAPPER` is used instead of `RUSTC_WORKSPACE_WRAPPER` so that we can lint all crate // dependencies rather than only workspace members // - // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates + // The wrapper is set to `lintcheck` itself so we can force enable linting and ignore certain crates // (see `crate::driver`) - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) - .arg("check") - .arg("--quiet") - .current_dir(&self.path) - .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__")) - .env("CARGO_TARGET_DIR", target) + let status = cmd + .env("CARGO_TARGET_DIR", shared_target_dir.join("recursive")) .env("RUSTC_WRAPPER", env::current_exe().unwrap()) // Pass the absolute path so `crate::driver` can find `clippy-driver`, as it's executed in various // different working directories @@ -416,23 +437,19 @@ impl Crate { assert_eq!(status.code(), Some(0)); return Vec::new(); + }; + + if !config.fix { + cmd.arg("--message-format=json"); } - cargo_clippy_args.extend(clippy_args); - - let all_output = Command::new(&cargo_clippy_path) + let all_output = cmd // use the looping index to create individual target dirs .env("CARGO_TARGET_DIR", shared_target_dir.join(format!("_{thread_index:?}"))) - .args(&cargo_clippy_args) - .current_dir(&self.path) + // Roughly equivalent to `cargo clippy`/`cargo clippy --fix` + .env("RUSTC_WORKSPACE_WRAPPER", clippy_driver_path) .output() - .unwrap_or_else(|error| { - panic!( - "Encountered error:\n{error:?}\ncargo_clippy_path: {}\ncrate path:{}\n", - &cargo_clippy_path.display(), - &self.path.display() - ); - }); + .unwrap(); let stdout = String::from_utf8_lossy(&all_output.stdout); let stderr = String::from_utf8_lossy(&all_output.stderr); let status = &all_output.status; @@ -479,15 +496,17 @@ impl Crate { } /// Builds clippy inside the repo to make sure we have a clippy executable we can use. -fn build_clippy() { - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) - .arg("build") - .status() - .expect("Failed to build clippy!"); - if !status.success() { +fn build_clippy() -> String { + let output = Command::new("cargo") + .args(["run", "--bin=clippy-driver", "--", "--version"]) + .stderr(Stdio::inherit()) + .output() + .unwrap(); + if !output.status.success() { eprintln!("Error: Failed to compile Clippy!"); std::process::exit(1); } + String::from_utf8_lossy(&output.stdout).into_owned() } /// Read a `lintcheck_crates.toml` file @@ -554,10 +573,10 @@ fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { } /// Generate a short list of occurring lints-types and their count -fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { +fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { // count lint type occurrences let mut counter: HashMap<&String, usize> = HashMap::new(); - clippy_warnings + warnings .iter() .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); @@ -580,7 +599,6 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, (stats_string, counter) } -#[allow(clippy::too_many_lines)] fn main() { // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` if let Ok(addr) = env::var("LINTCHECK_SERVER") { @@ -595,31 +613,29 @@ fn main() { let config = LintcheckConfig::new(); - println!("Compiling clippy..."); - build_clippy(); - println!("Done compiling"); + match config.subcommand { + Some(Commands::Diff { old, new }) => json::diff(&old, &new), + Some(Commands::Popular { output, number }) => popular_crates::fetch(output, number).unwrap(), + None => lintcheck(config), + } +} - let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap(); +#[allow(clippy::too_many_lines)] +fn lintcheck(config: LintcheckConfig) { + let clippy_ver = build_clippy(); let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap(); // assert that clippy is found assert!( - cargo_clippy_path.is_file(), - "target/debug/cargo-clippy binary not found! {}", - cargo_clippy_path.display() + clippy_driver_path.is_file(), + "target/debug/clippy-driver binary not found! {}", + clippy_driver_path.display() ); - let clippy_ver = Command::new(&cargo_clippy_path) - .arg("--version") - .output() - .map(|o| String::from_utf8_lossy(&o.stdout).into_owned()) - .expect("could not get clippy version!"); - // download and extract the crates, then run clippy on them and collect clippy's warnings // flatten into one big list of warnings let (crates, recursive_options) = read_crates(&config.sources_toml_path); - let old_stats = read_stats_from_file(&config.lintcheck_results_path); let counter = AtomicUsize::new(1); let lint_filter: Vec = config @@ -678,7 +694,6 @@ fn main() { .par_iter() .flat_map(|krate| { krate.run_clippy_lints( - &cargo_clippy_path, &clippy_driver_path, &counter, crates.len(), @@ -711,39 +726,51 @@ fn main() { } } - // generate some stats - let (stats_formatted, new_stats) = gather_stats(&warnings); + let text = match config.format { + OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config), + OutputFormat::Json => { + if !raw_ices.is_empty() { + for ice in raw_ices { + println!("{ice}"); + } + panic!("Some crates ICEd"); + } - let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect(); + json::output(&warnings) + }, + }; + + println!("Writing logs to {}", config.lintcheck_results_path.display()); + fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); + fs::write(&config.lintcheck_results_path, text).unwrap(); +} + +/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] +fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String { + // generate some stats + let (stats_formatted, new_stats) = gather_stats(warnings); + let old_stats = read_stats_from_file(&config.lintcheck_results_path); + + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); all_msgs.sort(); all_msgs.push("\n\n### Stats:\n\n".into()); all_msgs.push(stats_formatted); - // save the text into lintcheck-logs/logs.txt let mut text = clippy_ver; // clippy version number on top text.push_str("\n### Reports\n\n"); - if config.markdown { + if config.format == OutputFormat::Markdown { text.push_str("| file | lint | message |\n"); text.push_str("| --- | --- | --- |\n"); } write!(text, "{}", all_msgs.join("")).unwrap(); text.push_str("\n\n### ICEs:\n"); - for ice in &raw_ices { - let _: fmt::Result = write!( - text, - "{}:\n{}\n========================================\n\n", - ice.crate_name, ice.ice_content - ); + for ice in ices { + writeln!(text, "{ice}").unwrap(); } - println!("Writing logs to {}", config.lintcheck_results_path.display()); - if !raw_ices.is_empty() { - println!("WARNING: at least one ICE reported, check log file"); - } - fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); - fs::write(&config.lintcheck_results_path, text).unwrap(); - print_stats(old_stats, new_stats, &config.lint_filter); + + text } /// read the previous stats from the lintcheck-log file @@ -865,7 +892,7 @@ fn lintcheck_test() { "--crates-toml", "lintcheck/test_sources.toml", ]; - let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) + let status = Command::new("cargo") .args(args) .current_dir("..") // repo root .status(); diff --git a/lintcheck/src/popular-crates.rs b/lintcheck/src/popular-crates.rs deleted file mode 100644 index fdab984ad86c..000000000000 --- a/lintcheck/src/popular-crates.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![deny(clippy::pedantic)] - -use clap::Parser; -use crates_io_api::{CratesQueryBuilder, Sort, SyncClient}; -use indicatif::ProgressBar; -use std::collections::HashSet; -use std::fs::File; -use std::io::{BufWriter, Write}; -use std::path::PathBuf; -use std::time::Duration; - -#[derive(Parser)] -struct Opts { - /// Output TOML file name - output: PathBuf, - /// Number of crate names to download - #[clap(short, long, default_value_t = 100)] - number: usize, - /// Do not output progress - #[clap(short, long)] - quiet: bool, -} - -fn main() -> anyhow::Result<()> { - let opts = Opts::parse(); - let mut output = BufWriter::new(File::create(opts.output)?); - output.write_all(b"[crates]\n")?; - let client = SyncClient::new( - "clippy/lintcheck (github.com/rust-lang/rust-clippy/)", - Duration::from_secs(1), - )?; - let mut seen_crates = HashSet::new(); - let pb = if opts.quiet { - None - } else { - Some(ProgressBar::new(opts.number as u64)) - }; - let mut query = CratesQueryBuilder::new() - .sort(Sort::RecentDownloads) - .page_size(100) - .build(); - while seen_crates.len() < opts.number { - let retrieved = client.crates(query.clone())?.crates; - if retrieved.is_empty() { - eprintln!("No more than {} crates available from API", seen_crates.len()); - break; - } - for c in retrieved { - if seen_crates.insert(c.name.clone()) { - output.write_all( - format!( - "{} = {{ name = '{}', versions = ['{}'] }}\n", - c.name, c.name, c.max_version - ) - .as_bytes(), - )?; - if let Some(pb) = &pb { - pb.inc(1); - } - } - } - query.set_page(query.page() + 1); - } - Ok(()) -} diff --git a/lintcheck/src/popular_crates.rs b/lintcheck/src/popular_crates.rs new file mode 100644 index 000000000000..880a8bd81f08 --- /dev/null +++ b/lintcheck/src/popular_crates.rs @@ -0,0 +1,52 @@ +use serde::Deserialize; +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::PathBuf; + +#[derive(Deserialize, Debug)] +struct Page { + crates: Vec, + meta: Meta, +} + +#[derive(Deserialize, Debug)] +struct Crate { + name: String, + max_version: String, +} + +#[derive(Deserialize, Debug)] +struct Meta { + next_page: String, +} + +pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box> { + let agent = ureq::builder() + .user_agent("clippy/lintcheck (github.com/rust-lang/rust-clippy/)") + .build(); + + let mut crates = Vec::with_capacity(number); + let mut query = "?sort=recent-downloads&per_page=100".to_string(); + while crates.len() < number { + let page: Page = agent + .get(&format!("https://crates.io/api/v1/crates{query}")) + .call()? + .into_json()?; + + query = page.meta.next_page; + crates.extend(page.crates); + crates.truncate(number); + + let width = number.ilog10() as usize + 1; + println!("Fetched {:>width$}/{number} crates", crates.len()); + } + + let mut out = "[crates]\n".to_string(); + for Crate { name, max_version } in crates { + writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap(); + } + fs::write(output, out)?; + + Ok(()) +} diff --git a/rust-toolchain b/rust-toolchain index 842c2f3de0d1..72b50d59f7e9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-06-13" +channel = "nightly-2024-06-27" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/integration.rs b/tests/integration.rs index 7f4500826ff6..19c5f3a41339 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -55,6 +55,7 @@ fn integration_test() { "clippy", "--all-targets", "--all-features", + "--message-format=short", "--", "--cap-lints", "warn", diff --git a/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr b/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr index 912ea9bb4d11..b626551e35b9 100644 --- a/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr +++ b/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr @@ -1,10 +1,10 @@ error: file is loaded as a module multiple times: `src/b.rs` - --> src/main.rs:5:1 + --> src/main.rs:3:1 | -5 | mod b; +3 | mod b; | ^^^^^^ first loaded here -6 | / #[path = "b.rs"] -7 | | mod b2; +4 | / #[path = "b.rs"] +5 | | mod b2; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items @@ -12,34 +12,34 @@ error: file is loaded as a module multiple times: `src/b.rs` = help: to override `-D warnings` add `#[allow(clippy::duplicate_mod)]` error: file is loaded as a module multiple times: `src/c.rs` - --> src/main.rs:9:1 + --> src/main.rs:7:1 | -9 | mod c; +7 | mod c; | ^^^^^^ first loaded here -10 | / #[path = "c.rs"] -11 | | mod c2; +8 | / #[path = "c.rs"] +9 | | mod c2; | |_______^ loaded again here -12 | / #[path = "c.rs"] -13 | | mod c3; +10 | / #[path = "c.rs"] +11 | | mod c3; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `src/d.rs` - --> src/main.rs:18:1 + --> src/main.rs:16:1 | -18 | mod d; +16 | mod d; | ^^^^^^ first loaded here -19 | / #[path = "d.rs"] -20 | | mod d2; +17 | / #[path = "d.rs"] +18 | | mod d2; | |_______^ loaded again here | = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `src/from_other_module.rs` - --> src/main.rs:15:1 + --> src/main.rs:13:1 | -15 | mod from_other_module; +13 | mod from_other_module; | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here | ::: src/other_module/mod.rs:1:1 diff --git a/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/tests/ui-cargo/duplicate_mod/fail/src/main.rs index a99fe2e12bb2..9cbe4b83b25e 100644 --- a/tests/ui-cargo/duplicate_mod/fail/src/main.rs +++ b/tests/ui-cargo/duplicate_mod/fail/src/main.rs @@ -1,4 +1,3 @@ - mod a; mod b; diff --git a/tests/ui/assigning_clones.fixed b/tests/ui/assigning_clones.fixed index 70ab43b49b3a..60f6a385fc50 100644 --- a/tests/ui/assigning_clones.fixed +++ b/tests/ui/assigning_clones.fixed @@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom { self } } + +mod borrowck_conflicts { + //! Cases where clone_into and friends cannot be used because the src/dest have conflicting + //! borrows. + use std::path::PathBuf; + + fn issue12444(mut name: String) { + let parts = name.split(", ").collect::>(); + let first = *parts.first().unwrap(); + name = first.to_owned(); + } + + fn issue12444_simple() { + let mut s = String::new(); + let s2 = &s; + s = s2.to_owned(); + } + + fn issue12444_nodrop_projections() { + struct NoDrop; + + impl Clone for NoDrop { + fn clone(&self) -> Self { + todo!() + } + fn clone_from(&mut self, other: &Self) { + todo!() + } + } + + let mut s = NoDrop; + let s2 = &s; + s = s2.clone(); + + let mut s = (NoDrop, NoDrop); + let s2 = &s.0; + s.0 = s2.clone(); + + // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it + // considers `s` fully borrowed + let mut s = (NoDrop, NoDrop); + let s2 = &s.1; + s.0 = s2.clone(); + } + + fn issue12460(mut name: String) { + if let Some(stripped_name) = name.strip_prefix("baz-") { + name = stripped_name.to_owned(); + } + } + + fn issue12749() { + let mut path = PathBuf::from("/a/b/c"); + path = path.components().as_path().to_owned(); + } +} diff --git a/tests/ui/assigning_clones.rs b/tests/ui/assigning_clones.rs index 9699fed100c8..6eb85be511a8 100644 --- a/tests/ui/assigning_clones.rs +++ b/tests/ui/assigning_clones.rs @@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom { self } } + +mod borrowck_conflicts { + //! Cases where clone_into and friends cannot be used because the src/dest have conflicting + //! borrows. + use std::path::PathBuf; + + fn issue12444(mut name: String) { + let parts = name.split(", ").collect::>(); + let first = *parts.first().unwrap(); + name = first.to_owned(); + } + + fn issue12444_simple() { + let mut s = String::new(); + let s2 = &s; + s = s2.to_owned(); + } + + fn issue12444_nodrop_projections() { + struct NoDrop; + + impl Clone for NoDrop { + fn clone(&self) -> Self { + todo!() + } + fn clone_from(&mut self, other: &Self) { + todo!() + } + } + + let mut s = NoDrop; + let s2 = &s; + s = s2.clone(); + + let mut s = (NoDrop, NoDrop); + let s2 = &s.0; + s.0 = s2.clone(); + + // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it + // considers `s` fully borrowed + let mut s = (NoDrop, NoDrop); + let s2 = &s.1; + s.0 = s2.clone(); + } + + fn issue12460(mut name: String) { + if let Some(stripped_name) = name.strip_prefix("baz-") { + name = stripped_name.to_owned(); + } + } + + fn issue12749() { + let mut path = PathBuf::from("/a/b/c"); + path = path.components().as_path().to_owned(); + } +} diff --git a/tests/ui/auxiliary/external_consts.rs b/tests/ui/auxiliary/external_consts.rs new file mode 100644 index 000000000000..1885ba341f51 --- /dev/null +++ b/tests/ui/auxiliary/external_consts.rs @@ -0,0 +1 @@ +pub const MAGIC_NUMBER: i32 = 1; diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index c39f65a43e39..146b04ab8131 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -12,6 +12,7 @@ #![allow( clippy::cast_abs_to_unsigned, clippy::no_effect, + clippy::unnecessary_min_or_max, clippy::unnecessary_operation, clippy::unnecessary_literal_unwrap, clippy::identity_op diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 452482fc88e2..7824bdfac25e 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:25:5 + --> tests/ui/cast.rs:26:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:30:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:31:5 + --> tests/ui/cast.rs:32:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:34:5 + --> tests/ui/cast.rs:35:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:37:5 + --> tests/ui/cast.rs:38:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:39:5 + --> tests/ui/cast.rs:40:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:43:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:44:5 + --> tests/ui/cast.rs:45:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:44:5 + --> tests/ui/cast.rs:45:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:49:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:51:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:52:5 + --> tests/ui/cast.rs:53:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:55:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:60:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:64:22 + --> tests/ui/cast.rs:65:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:66:9 + --> tests/ui/cast.rs:67:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:69:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:70:9 + --> tests/ui/cast.rs:71:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:70:9 + --> tests/ui/cast.rs:71:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:75:5 + --> tests/ui/cast.rs:76:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:78:5 + --> tests/ui/cast.rs:79:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:80:5 + --> tests/ui/cast.rs:81:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:83:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:84:5 + --> tests/ui/cast.rs:85:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:91:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:91:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:95:5 + --> tests/ui/cast.rs:96:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:95:5 + --> tests/ui/cast.rs:96:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:99:5 + --> tests/ui/cast.rs:100:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:104:5 + --> tests/ui/cast.rs:105:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:111:5 + --> tests/ui/cast.rs:112:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:111:5 + --> tests/ui/cast.rs:112:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:116:5 + --> tests/ui/cast.rs:117:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:119:5 + --> tests/ui/cast.rs:120:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:130:5 + --> tests/ui/cast.rs:131:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:135:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:136:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:142:5 + --> tests/ui/cast.rs:143:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:157:5 + --> tests/ui/cast.rs:158:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:208:5 + --> tests/ui/cast.rs:209:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:222:5 + --> tests/ui/cast.rs:223:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:245:21 + --> tests/ui/cast.rs:246:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:247:21 + --> tests/ui/cast.rs:248:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:289:21 + --> tests/ui/cast.rs:290:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:291:21 + --> tests/ui/cast.rs:292:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:308:21 + --> tests/ui/cast.rs:309:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:327:21 + --> tests/ui/cast.rs:328:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:374:21 + --> tests/ui/cast.rs:375:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:385:13 + --> tests/ui/cast.rs:386:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:389:13 + --> tests/ui/cast.rs:390:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:401:9 + --> tests/ui/cast.rs:402:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:32 + --> tests/ui/cast.rs:407:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:408:5 + --> tests/ui/cast.rs:409:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:409:5 + --> tests/ui/cast.rs:410:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:414:5 + --> tests/ui/cast.rs:415:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:417:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:419:5 + --> tests/ui/cast.rs:420:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:423:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:425:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:429:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:430:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:432:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:433:5 + --> tests/ui/cast.rs:434:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:433:6 + --> tests/ui/cast.rs:434:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:436:5 + --> tests/ui/cast.rs:437:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:438:5 + --> tests/ui/cast.rs:439:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:442:5 + --> tests/ui/cast.rs:443:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:444:5 + --> tests/ui/cast.rs:445:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:448:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:449:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:451:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:452:9 + --> tests/ui/cast.rs:453:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:454:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:456:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:457:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:459:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:460:9 + --> tests/ui/cast.rs:461:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:462:9 + --> tests/ui/cast.rs:463:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:464:9 + --> tests/ui/cast.rs:465:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:472:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:475:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:484:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:484:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:498:5 + --> tests/ui/cast.rs:499:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:500:5 + --> tests/ui/cast.rs:501:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cast_size.32bit.stderr b/tests/ui/cast_size.32bit.stderr index eb6c59deabba..8ff3464676c3 100644 --- a/tests/ui/cast_size.32bit.stderr +++ b/tests/ui/cast_size.32bit.stderr @@ -12,35 +12,35 @@ help: ... or use `try_from` and handle the error accordingly LL | i8::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:18:5 +error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) + --> tests/ui/cast_size.rs:21:5 | -LL | x0 as f64; +LL | x0 as f32; | ^^^^^^^^^ | = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:19:5 - | -LL | x1 as f64; - | ^^^^^^^^^ - -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:20:5 - | -LL | x0 as f32; - | ^^^^^^^^^ - error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:21:5 + --> tests/ui/cast_size.rs:22:5 | LL | x1 as f32; | ^^^^^^^^^ +error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:23:5 + | +LL | x0 as f64; + | ^^^^^^^^^ + +error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:24:5 + | +LL | x1 as f64; + | ^^^^^^^^^ + error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:22:5 + --> tests/ui/cast_size.rs:28:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | i32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:23:5 + --> tests/ui/cast_size.rs:29:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | u32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:24:5 + --> tests/ui/cast_size.rs:30:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | u32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | 1usize as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:26:5 + --> tests/ui/cast_size.rs:32:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | isize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:27:5 + --> tests/ui/cast_size.rs:33:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | usize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -133,13 +133,13 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:29:5 + --> tests/ui/cast_size.rs:35:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ @@ -151,25 +151,25 @@ LL | usize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:30:5 + --> tests/ui/cast_size.rs:36:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:35:5 + --> tests/ui/cast_size.rs:43:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:44:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal out of range for `usize` - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:44:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs index c0e5fc3e4467..ea3a4face93f 100644 --- a/tests/ui/copy_iterator.rs +++ b/tests/ui/copy_iterator.rs @@ -1,4 +1,5 @@ #![warn(clippy::copy_iterator)] +#![allow(clippy::manual_inspect)] #[derive(Copy, Clone)] struct Countdown(u8); diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr index 533bddaadb5e..990b1ce628de 100644 --- a/tests/ui/copy_iterator.stderr +++ b/tests/ui/copy_iterator.stderr @@ -1,5 +1,5 @@ error: you are implementing `Iterator` on a `Copy` type - --> tests/ui/copy_iterator.rs:6:1 + --> tests/ui/copy_iterator.rs:7:1 | LL | / impl Iterator for Countdown { LL | | diff --git a/tests/ui/crashes/ice-12284.rs b/tests/ui/crashes/ice-12284.rs new file mode 100644 index 000000000000..8d1dbface8eb --- /dev/null +++ b/tests/ui/crashes/ice-12284.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + +#[repr(C)] +struct Foo { + _: struct { + }, +} + +fn main() {} diff --git a/tests/ui/field_scoped_visibility_modifiers.rs b/tests/ui/field_scoped_visibility_modifiers.rs new file mode 100644 index 000000000000..5789dbf9b1d7 --- /dev/null +++ b/tests/ui/field_scoped_visibility_modifiers.rs @@ -0,0 +1,21 @@ +#![warn(clippy::field_scoped_visibility_modifiers)] + +pub mod pub_module { + pub(in crate::pub_module) mod pub_in_path_module {} + pub(super) mod pub_super_module {} + struct MyStruct { + private_field: bool, + pub pub_field: bool, + pub(crate) pub_crate_field: bool, + pub(in crate::pub_module) pub_in_path_field: bool, + pub(super) pub_super_field: bool, + #[allow(clippy::needless_pub_self)] + pub(self) pub_self_field: bool, + } +} +pub(crate) mod pub_crate_module {} + +#[allow(clippy::needless_pub_self)] +pub(self) mod pub_self_module {} + +fn main() {} diff --git a/tests/ui/field_scoped_visibility_modifiers.stderr b/tests/ui/field_scoped_visibility_modifiers.stderr new file mode 100644 index 000000000000..beea6c92107c --- /dev/null +++ b/tests/ui/field_scoped_visibility_modifiers.stderr @@ -0,0 +1,28 @@ +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:9:9 + | +LL | pub(crate) pub_crate_field: bool, + | ^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + = note: `-D clippy::field-scoped-visibility-modifiers` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::field_scoped_visibility_modifiers)]` + +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:10:9 + | +LL | pub(in crate::pub_module) pub_in_path_field: bool, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + +error: scoped visibility modifier on a field + --> tests/ui/field_scoped_visibility_modifiers.rs:11:9 + | +LL | pub(super) pub_super_field: bool, + | ^^^^^^^^^^ + | + = help: consider making the field private and adding a scoped visibility method for it + +error: aborting due to 3 previous errors + diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index ba73e64f1862..56fe29b4e677 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -1,6 +1,11 @@ +//@aux-build: proc_macros.rs + #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] +extern crate proc_macros; +use proc_macros::with_span; + fn test_end_of_fn() -> bool { if true { // no error! @@ -136,3 +141,11 @@ fn check_expect() -> bool { #[expect(clippy::implicit_return)] true } + +with_span!( + span + + fn dont_lint_proc_macro(x: usize) -> usize{ + x + } +); diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 522fc6a0a447..f066ce20cfd1 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -1,6 +1,11 @@ +//@aux-build: proc_macros.rs + #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] +extern crate proc_macros; +use proc_macros::with_span; + fn test_end_of_fn() -> bool { if true { // no error! @@ -136,3 +141,11 @@ fn check_expect() -> bool { #[expect(clippy::implicit_return)] true } + +with_span!( + span + + fn dont_lint_proc_macro(x: usize) -> usize{ + x + } +); diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr index b2f7bc694395..f06d4e983c57 100644 --- a/tests/ui/implicit_return.stderr +++ b/tests/ui/implicit_return.stderr @@ -1,5 +1,5 @@ error: missing `return` statement - --> tests/ui/implicit_return.rs:10:5 + --> tests/ui/implicit_return.rs:15:5 | LL | true | ^^^^ help: add `return` as shown: `return true` @@ -8,85 +8,85 @@ LL | true = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]` error: missing `return` statement - --> tests/ui/implicit_return.rs:14:15 + --> tests/ui/implicit_return.rs:19:15 | LL | if true { true } else { false } | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:14:29 + --> tests/ui/implicit_return.rs:19:29 | LL | if true { true } else { false } | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:20:17 + --> tests/ui/implicit_return.rs:25:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:21:20 + --> tests/ui/implicit_return.rs:26:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:34:9 + --> tests/ui/implicit_return.rs:39:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:41:13 + --> tests/ui/implicit_return.rs:46:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:49:13 + --> tests/ui/implicit_return.rs:54:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:67:18 + --> tests/ui/implicit_return.rs:72:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:68:16 + --> tests/ui/implicit_return.rs:73:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:76:5 + --> tests/ui/implicit_return.rs:81:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")` error: missing `return` statement - --> tests/ui/implicit_return.rs:85:5 + --> tests/ui/implicit_return.rs:90:5 | LL | m!(true, false) | ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)` error: missing `return` statement - --> tests/ui/implicit_return.rs:91:13 + --> tests/ui/implicit_return.rs:96:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> tests/ui/implicit_return.rs:96:17 + --> tests/ui/implicit_return.rs:101:17 | LL | break 'outer false; | ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false` error: missing `return` statement - --> tests/ui/implicit_return.rs:111:5 + --> tests/ui/implicit_return.rs:116:5 | LL | / loop { LL | | m!(true); @@ -101,7 +101,7 @@ LL + } | error: missing `return` statement - --> tests/ui/implicit_return.rs:125:5 + --> tests/ui/implicit_return.rs:130:5 | LL | true | ^^^^ help: add `return` as shown: `return true` diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed new file mode 100644 index 000000000000..0e1b8fe3edb5 --- /dev/null +++ b/tests/ui/manual_inspect.fixed @@ -0,0 +1,174 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).inspect(|&x| { + println!("{}", x); + }); + + let _ = Some(0).inspect(|&x| { + println!("{x}"); + }); + + let _ = Some(0).inspect(|&x| { + println!("{}", x * 5 + 1); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + panic!(); + } + }); + + let _ = Some(0).inspect(|&x| { + if &x == &0 { + let _y = x; + panic!(); + } + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).inspect(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).inspect(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + return; + } + println!("test"); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell); + + let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { + x.0.set(1); + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).inspect(|&x| { + println!("{}", x); + }); + + let _: Result<(), _> = Err(0).inspect_err(|&x| { + println!("{}", x); + }); + + let _ = [0] + .into_iter() + .inspect(|&x| { + println!("{}", x); + }) + .count(); + + { + struct S(T); + impl S { + fn map(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + + fn map_err(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/tests/ui/manual_inspect.rs b/tests/ui/manual_inspect.rs new file mode 100644 index 000000000000..94cdfe391400 --- /dev/null +++ b/tests/ui/manual_inspect.rs @@ -0,0 +1,186 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).map(|x| { + println!("{}", x); + x + }); + + let _ = Some(0).map(|x| { + println!("{x}"); + x + }); + + let _ = Some(0).map(|x| { + println!("{}", x * 5 + 1); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + if &x == &0 { + let _y = x; + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + x + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = &x; + }; + return x; + } + println!("test"); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + x.0.set(1); + x + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).map(|x| { + println!("{}", x); + x + }); + + let _: Result<(), _> = Err(0).map_err(|x| { + println!("{}", x); + x + }); + + let _ = [0] + .into_iter() + .map(|x| { + println!("{}", x); + x + }) + .count(); + + { + struct S(T); + impl S { + fn map(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + + fn map_err(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr new file mode 100644 index 000000000000..8548c0cd2942 --- /dev/null +++ b/tests/ui/manual_inspect.stderr @@ -0,0 +1,182 @@ +error: + --> tests/ui/manual_inspect.rs:5:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | + = note: `-D clippy::manual-inspect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_inspect)]` +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:10:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{x}"); + | + +error: + --> tests/ui/manual_inspect.rs:15:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x * 5 + 1); + | + +error: + --> tests/ui/manual_inspect.rs:20:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:27:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if &x == &0 { +LL | let _y = x; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:78:41 + | +LL | let _ = Some((String::new(), 0u32)).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some((String::new(), 0u32)).inspect(|x| { +LL | if x.1 == 0 { +LL | let _x = x.1; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:104:33 + | +LL | let _ = Some(String::new()).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(String::new()).inspect(|x| { +LL | if x.is_empty() { +LL | let _ = || { +LL ~ let _x = x; +LL | }; +LL ~ return; +LL | } +LL ~ println!("test"); + | + +error: + --> tests/ui/manual_inspect.rs:115:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { +... +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:130:46 + | +LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { +LL ~ x.0.set(1); + | + +error: + --> tests/ui/manual_inspect.rs:146:34 + | +LL | let _: Result<_, ()> = Ok(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:151:35 + | +LL | let _: Result<(), _> = Err(0).map_err(|x| { + | ^^^^^^^ + | +help: try + | +LL ~ let _: Result<(), _> = Err(0).inspect_err(|&x| { +LL ~ println!("{}", x); + | + +error: this call to `map()` won't have an effect on the call to `count()` + --> tests/ui/manual_inspect.rs:156:13 + | +LL | let _ = [0] + | _____________^ +LL | | .into_iter() +LL | | .map(|x| { +LL | | println!("{}", x); +LL | | x +LL | | }) +LL | | .count(); + | |________________^ + | + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` + = note: `-D clippy::suspicious-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` + +error: + --> tests/ui/manual_inspect.rs:158:10 + | +LL | .map(|x| { + | ^^^ + | +help: try + | +LL ~ .inspect(|&x| { +LL ~ println!("{}", x); + | + +error: aborting due to 13 previous errors + diff --git a/tests/ui/manual_pattern_char_comparison.fixed b/tests/ui/manual_pattern_char_comparison.fixed index 588226b87e87..03e621d95ba1 100644 --- a/tests/ui/manual_pattern_char_comparison.fixed +++ b/tests/ui/manual_pattern_char_comparison.fixed @@ -47,3 +47,15 @@ fn main() { } "".find(|c| m!(c)); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(['.', ',', '!', '?']); +} diff --git a/tests/ui/manual_pattern_char_comparison.rs b/tests/ui/manual_pattern_char_comparison.rs index 5078f3ee27f3..43e883cd325a 100644 --- a/tests/ui/manual_pattern_char_comparison.rs +++ b/tests/ui/manual_pattern_char_comparison.rs @@ -47,3 +47,15 @@ fn main() { } "".find(|c| m!(c)); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); +} diff --git a/tests/ui/manual_pattern_char_comparison.stderr b/tests/ui/manual_pattern_char_comparison.stderr index b6b51794a11f..f185d7c8f676 100644 --- a/tests/ui/manual_pattern_char_comparison.stderr +++ b/tests/ui/manual_pattern_char_comparison.stderr @@ -55,5 +55,11 @@ error: this manual char comparison can be written more succinctly LL | sentence.find(|c| c == '🎈'); | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` -error: aborting due to 9 previous errors +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:60:31 + | +LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` + +error: aborting due to 10 previous errors diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index dffd44b6a7c1..74afa00e12f2 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -68,6 +68,32 @@ fn option_unwrap_or() { Some(s) => s, None => &format!("{} {}!", "hello", "world"), }; + + Some(1).unwrap_or(42); + + //don't lint + if let Some(x) = Some(1) { + x + 1 + } else { + 42 + }; + if let Some(x) = Some(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Some(x) = Some(j) { + x + } else { + continue; + }; + if let Some(x) = Some(j) { + x + } else { + break; + }; + } } fn result_unwrap_or() { @@ -138,6 +164,32 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => "Bob", }; + + Ok::(1).unwrap_or(42); + + //don't lint + if let Ok(x) = Ok::(1) { + x + 1 + } else { + 42 + }; + if let Ok(x) = Ok::(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Ok(x) = Ok::(j) { + x + } else { + continue; + }; + if let Ok(x) = Ok::(j) { + x + } else { + break; + }; + } } // don't lint in const fn diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 67427132c1a8..2d01b8ceaaa7 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -83,6 +83,36 @@ fn option_unwrap_or() { Some(s) => s, None => &format!("{} {}!", "hello", "world"), }; + + if let Some(x) = Some(1) { + x + } else { + 42 + }; + + //don't lint + if let Some(x) = Some(1) { + x + 1 + } else { + 42 + }; + if let Some(x) = Some(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Some(x) = Some(j) { + x + } else { + continue; + }; + if let Some(x) = Some(j) { + x + } else { + break; + }; + } } fn result_unwrap_or() { @@ -177,6 +207,36 @@ fn result_unwrap_or() { Ok(s) => s, Err(s) => "Bob", }; + + if let Ok(x) = Ok::(1) { + x + } else { + 42 + }; + + //don't lint + if let Ok(x) = Ok::(1) { + x + 1 + } else { + 42 + }; + if let Ok(x) = Ok::(1) { + x + } else { + return; + }; + for j in 0..4 { + if let Ok(x) = Ok::(j) { + x + } else { + continue; + }; + if let Ok(x) = Ok::(j) { + x + } else { + break; + }; + } } // don't lint in const fn diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index 33a099680ce0..c93a8952a080 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -58,8 +58,18 @@ LL | | None => "Alice", LL | | }; | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` +error: this pattern reimplements `Option::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:87:5 + | +LL | / if let Some(x) = Some(1) { +LL | | x +LL | | } else { +LL | | 42 +LL | | }; + | |_____^ help: replace with: `Some(1).unwrap_or(42)` + error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:90:5 + --> tests/ui/manual_unwrap_or.rs:120:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -68,7 +78,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:97:5 + --> tests/ui/manual_unwrap_or.rs:127:5 | LL | / match a { LL | | Ok(i) => i, @@ -77,7 +87,7 @@ LL | | }; | |_____^ help: replace with: `a.unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:103:5 + --> tests/ui/manual_unwrap_or.rs:133:5 | LL | / match Ok(1) as Result { LL | | Ok(i) => i, @@ -86,7 +96,7 @@ LL | | }; | |_____^ help: replace with: `(Ok(1) as Result).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:116:5 + --> tests/ui/manual_unwrap_or.rs:146:5 | LL | / match s.method() { LL | | Some(i) => i, @@ -95,7 +105,7 @@ LL | | }; | |_____^ help: replace with: `s.method().unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:122:5 + --> tests/ui/manual_unwrap_or.rs:152:5 | LL | / match Ok::(1) { LL | | Err(_) => 42, @@ -104,7 +114,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:128:5 + --> tests/ui/manual_unwrap_or.rs:158:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -113,7 +123,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(1 + 42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:135:5 + --> tests/ui/manual_unwrap_or.rs:165:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -134,7 +144,7 @@ LL ~ }); | error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:145:5 + --> tests/ui/manual_unwrap_or.rs:175:5 | LL | / match Ok::<&str, &str>("Bob") { LL | | Ok(i) => i, @@ -142,8 +152,18 @@ 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:211:5 + | +LL | / if let Ok(x) = Ok::(1) { +LL | | x +LL | | } else { +LL | | 42 +LL | | }; + | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` + error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:205:17 + --> tests/ui/manual_unwrap_or.rs:265:17 | LL | let _ = match some_macro!() { | _________________^ @@ -152,5 +172,5 @@ LL | | None => 0, LL | | }; | |_________^ help: replace with: `some_macro!().unwrap_or(0)` -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index 663de1a5f067..832376fa5af1 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)] +#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] fn main() { let x: Option> = None; @@ -78,3 +78,24 @@ fn issue_12569() { 0 }; } + +// Should not warn! +fn issue_12928() { + let x = Some((1, 2)); + let y = if let Some((a, _)) = x { a } else { 0 }; + let y = if let Some((a, ..)) = x { a } else { 0 }; + let x = Some([1, 2]); + let y = if let Some([a, _]) = x { a } else { 0 }; + let y = if let Some([a, ..]) = x { a } else { 0 }; + + struct X { + a: u8, + b: u8, + } + let x = Some(X { a: 0, b: 0 }); + let y = if let Some(X { a, .. }) = x { a } else { 0 }; + struct Y(u8, u8); + let x = Some(Y(0, 0)); + let y = if let Some(Y(a, _)) = x { a } else { 0 }; + let y = if let Some(Y(a, ..)) = x { a } else { 0 }; +} diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index 75ffe09be9d4..649f65c89fb0 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)] +#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)] fn main() { let x: Option> = None; @@ -111,3 +111,24 @@ fn issue_12569() { 0 }; } + +// Should not warn! +fn issue_12928() { + let x = Some((1, 2)); + let y = if let Some((a, _)) = x { a } else { 0 }; + let y = if let Some((a, ..)) = x { a } else { 0 }; + let x = Some([1, 2]); + let y = if let Some([a, _]) = x { a } else { 0 }; + let y = if let Some([a, ..]) = x { a } else { 0 }; + + struct X { + a: u8, + b: u8, + } + let x = Some(X { a: 0, b: 0 }); + let y = if let Some(X { a, .. }) = x { a } else { 0 }; + struct Y(u8, u8); + let x = Some(Y(0, 0)); + let y = if let Some(Y(a, _)) = x { a } else { 0 }; + let y = if let Some(Y(a, ..)) = x { a } else { 0 }; +} diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 76b26f5e4386..117e0bc68ccc 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,6 +1,11 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] +#![allow( + clippy::boxed_local, + clippy::uninlined_format_args, + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or +)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index d6f2475ba79c..f8a5269024da 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,6 +1,11 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] +#![allow( + clippy::boxed_local, + clippy::uninlined_format_args, + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or +)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.stderr b/tests/ui/match_result_ok.stderr index 0d42d59dc013..b5b91cbe5534 100644 --- a/tests/ui/match_result_ok.stderr +++ b/tests/ui/match_result_ok.stderr @@ -1,5 +1,5 @@ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:8:5 + --> tests/ui/match_result_ok.rs:13:5 | LL | if let Some(y) = x.parse().ok() { y } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | if let Ok(y) = x.parse() { y } else { 0 } | ~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:18:9 + --> tests/ui/match_result_ok.rs:23:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | if let Ok(y) = x . parse() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:44:5 + --> tests/ui/match_result_ok.rs:49:5 | LL | while let Some(a) = wat.next().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed new file mode 100644 index 000000000000..921dcf0b1626 --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -0,0 +1,173 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![feature(const_mut_refs)] +#![feature(const_trait_impl)] + +use std::mem::transmute; + +struct Game { + guess: i32, +} + +impl Game { + // Could be const + pub const fn new() -> Self { + //~^ ERROR: this could be a `const fn` + //~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings` + Self { guess: 42 } + } + + const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { + //~^ ERROR: this could be a `const fn` + b + } +} + +// Could be const +const fn one() -> i32 { + //~^ ERROR: this could be a `const fn` + 1 +} + +// Could also be const +const fn two() -> i32 { + //~^ ERROR: this could be a `const fn` + let abc = 2; + abc +} + +// Could be const (since Rust 1.39) +const fn string() -> String { + //~^ ERROR: this could be a `const fn` + String::new() +} + +// Could be const +const unsafe fn four() -> i32 { + //~^ ERROR: this could be a `const fn` + 4 +} + +// Could also be const +const fn generic(t: T) -> T { + //~^ ERROR: this could be a `const fn` + t +} + +fn sub(x: u32) -> usize { + unsafe { transmute(&x) } +} + +const fn generic_arr(t: [T; 1]) -> T { + //~^ ERROR: this could be a `const fn` + t[0] +} + +mod with_drop { + pub struct A; + pub struct B; + impl Drop for A { + fn drop(&mut self) {} + } + + impl B { + // This can be const, because `a` is passed by reference + pub const fn b(self, a: &A) -> B { + //~^ ERROR: this could be a `const fn` + B + } + } +} + +#[clippy::msrv = "1.47.0"] +mod const_fn_stabilized_before_msrv { + // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47. + const fn const_fn_stabilized_before_msrv(byte: u8) { + //~^ ERROR: this could be a `const fn` + byte.is_ascii_digit(); + } +} + +#[clippy::msrv = "1.45"] +fn msrv_1_45() -> i32 { + 45 +} + +#[clippy::msrv = "1.46"] +const fn msrv_1_46() -> i32 { + //~^ ERROR: this could be a `const fn` + 46 +} + +// Should not be const +fn main() {} + +struct D; + +impl const Drop for D { + fn drop(&mut self) { + todo!(); + } +} + +// Lint this, since it can be dropped in const contexts +// FIXME(effects) +fn d(this: D) {} + +mod msrv { + struct Foo(*const u8, &'static u8); + + impl Foo { + #[clippy::msrv = "1.58"] + const fn deref_ptr_can_be_const(self) -> usize { + //~^ ERROR: this could be a `const fn` + unsafe { *self.0 as usize } + } + + const fn deref_copied_val(self) -> usize { + //~^ ERROR: this could be a `const fn` + *self.1 as usize + } + } + + union Bar { + val: u8, + } + + #[clippy::msrv = "1.56"] + const fn union_access_can_be_const() { + //~^ ERROR: this could be a `const fn` + let bar = Bar { val: 1 }; + let _ = unsafe { bar.val }; + } +} + +mod issue12677 { + pub struct Wrapper { + pub strings: Vec, + } + + impl Wrapper { + #[must_use] + pub const fn new(strings: Vec) -> Self { + Self { strings } + } + + #[must_use] + pub const fn empty() -> Self { + Self { strings: Vec::new() } + } + } + + pub struct Other { + pub text: String, + pub vec: Vec, + } + + impl Other { + pub const fn new(text: String) -> Self { + let vec = Vec::new(); + Self { text, vec } + } + } +} 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 1c61c3e87132..8999af761e31 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -10,6 +10,10 @@ LL | | } | = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | pub const fn new() -> Self { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:20:5 @@ -19,6 +23,11 @@ LL | | LL | | b LL | | } | |_____^ + | +help: make the function `const` + | +LL | const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:27:1 @@ -28,6 +37,11 @@ LL | | LL | | 1 LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn one() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:33:1 @@ -38,6 +52,11 @@ LL | | let abc = 2; LL | | abc LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn two() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:40:1 @@ -47,6 +66,11 @@ LL | | LL | | String::new() LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn string() -> String { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:46:1 @@ -56,6 +80,11 @@ LL | | LL | | 4 LL | | } | |_^ + | +help: make the function `const` + | +LL | const unsafe fn four() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:52:1 @@ -65,6 +94,11 @@ LL | | LL | | t LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn generic(t: T) -> T { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:61:1 @@ -74,6 +108,11 @@ LL | | LL | | t[0] LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn generic_arr(t: [T; 1]) -> T { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:75:9 @@ -83,6 +122,11 @@ LL | | LL | | B LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn b(self, a: &A) -> B { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:85:5 @@ -92,6 +136,11 @@ LL | | LL | | byte.is_ascii_digit(); LL | | } | |_____^ + | +help: make the function `const` + | +LL | const fn const_fn_stabilized_before_msrv(byte: u8) { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:97:1 @@ -101,6 +150,11 @@ LL | | LL | | 46 LL | | } | |_^ + | +help: make the function `const` + | +LL | const fn msrv_1_46() -> i32 { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9 @@ -110,6 +164,11 @@ LL | | LL | | unsafe { *self.0 as usize } LL | | } | |_________^ + | +help: make the function `const` + | +LL | const fn deref_ptr_can_be_const(self) -> usize { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9 @@ -119,6 +178,11 @@ LL | | LL | | *self.1 as usize LL | | } | |_________^ + | +help: make the function `const` + | +LL | const fn deref_copied_val(self) -> usize { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5 @@ -129,6 +193,11 @@ LL | | let bar = Bar { val: 1 }; LL | | let _ = unsafe { bar.val }; LL | | } | |_____^ + | +help: make the function `const` + | +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:152:9 @@ -137,6 +206,11 @@ LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn new(strings: Vec) -> Self { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 @@ -145,6 +219,11 @@ LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn empty() -> Self { + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 @@ -154,6 +233,11 @@ LL | | let vec = Vec::new(); LL | | Self { text, vec } LL | | } | |_________^ + | +help: make the function `const` + | +LL | pub const fn new(text: String) -> Self { + | +++++ error: aborting due to 17 previous errors diff --git a/tests/ui/octal_escapes.rs b/tests/ui/octal_escapes.rs index 3915dfdb8418..f2664e2fa67f 100644 --- a/tests/ui/octal_escapes.rs +++ b/tests/ui/octal_escapes.rs @@ -2,25 +2,20 @@ #![warn(clippy::octal_escapes)] fn main() { - let _bad1 = "\033[0m"; - //~^ ERROR: octal-looking escape in string literal - let _bad2 = b"\033[0m"; - //~^ ERROR: octal-looking escape in byte string literal - let _bad3 = "\\\033[0m"; - //~^ ERROR: octal-looking escape in string literal + let _bad1 = "\033[0m"; //~ octal_escapes + let _bad2 = b"\033[0m"; //~ octal_escapes + let _bad3 = "\\\033[0m"; //~ octal_escapes // maximum 3 digits (\012 is the escape) - let _bad4 = "\01234567"; - //~^ ERROR: octal-looking escape in string literal - let _bad5 = "\0\03"; - //~^ ERROR: octal-looking escape in string literal + let _bad4 = "\01234567"; //~ octal_escapes + let _bad5 = "\0\03"; //~ octal_escapes let _bad6 = "Text-\055\077-MoreText"; - //~^ ERROR: octal-looking escape in string literal + //~^ octal_escapes + //~| octal_escapes let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; - //~^ ERROR: octal-looking escape in string literal - let _bad8 = "锈\01锈"; - //~^ ERROR: octal-looking escape in string literal - let _bad9 = "锈\011锈"; - //~^ ERROR: octal-looking escape in string literal + //~^ octal_escapes + //~| octal_escapes + let _bad8 = "锈\01锈"; //~ octal_escapes + let _bad9 = "锈\011锈"; //~ octal_escapes let _good1 = "\\033[0m"; let _good2 = "\0\\0"; diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr index 7ed9ee3ae2f4..9343ba64a30b 100644 --- a/tests/ui/octal_escapes.stderr +++ b/tests/ui/octal_escapes.stderr @@ -1,148 +1,170 @@ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:5:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:5:18 | LL | let _bad1 = "\033[0m"; - | ^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character + = help: octal escapes are not supported, `\0` is always null = note: `-D clippy::octal-escapes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::octal_escapes)]` -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad1 = "\x1b[0m"; - | ~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad1 = "\x0033[0m"; - | ~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in byte string literal - --> tests/ui/octal_escapes.rs:7:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:6:19 | LL | let _bad2 = b"\033[0m"; - | ^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null byte -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad2 = b"\x1b[0m"; - | ~~~~~~~~~~ -help: if the null byte is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad2 = b"\x0033[0m"; - | ~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:9:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:7:20 | LL | let _bad3 = "\\\033[0m"; - | ^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad3 = "\\\x1b[0m"; - | ~~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad3 = "\\\x0033[0m"; - | ~~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:12:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:9:18 | LL | let _bad4 = "\01234567"; - | ^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad4 = "\x0a34567"; - | ~~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad4 = "\x001234567"; - | ~~~~~~~~~~~~~ + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:14:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:10:20 | LL | let _bad5 = "\0\03"; - | ^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad5 = "\0\x03"; - | ~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad5 = "\0\x003"; - | ~~~~~~~~~ +LL | let _bad5 = "\0\x0003"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:16:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:11:23 | LL | let _bad6 = "Text-\055\077-MoreText"; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | -LL | let _bad6 = "Text-\x2d\x3f-MoreText"; - | ~~~~~~~~~~~~~~~~~~~~~~~~ -help: if the null character is intended, disambiguate using +LL | let _bad6 = "Text-\x2d\077-MoreText"; + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad6 = "Text-\x0055\x0077-MoreText"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _bad6 = "Text-\x0055\077-MoreText"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:18:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:11:27 + | +LL | let _bad6 = "Text-\055\077-MoreText"; + | ^^^^ + | +help: if an octal escape is intended, use a hex escape instead + | +LL | let _bad6 = "Text-\055\x3f-MoreText"; + | ~~~~ +help: if a null escape is intended, disambiguate using + | +LL | let _bad6 = "Text-\055\x0077-MoreText"; + | ~~~~~~ + +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:14:31 | LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | -LL | let _bad7 = "EvenMoreText-\x01\x02-ShortEscapes"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: if the null character is intended, disambiguate using +LL | let _bad7 = "EvenMoreText-\x01\02-ShortEscapes"; + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad7 = "EvenMoreText-\x001\x002-ShortEscapes"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _bad7 = "EvenMoreText-\x0001\02-ShortEscapes"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:20:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:14:34 + | +LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; + | ^^^ + | +help: if an octal escape is intended, use a hex escape instead + | +LL | let _bad7 = "EvenMoreText-\01\x02-ShortEscapes"; + | ~~~~ +help: if a null escape is intended, disambiguate using + | +LL | let _bad7 = "EvenMoreText-\01\x0002-ShortEscapes"; + | ~~~~~~ + +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:17:19 | LL | let _bad8 = "锈\01锈"; - | ^^^^^^^^^ + | ^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad8 = "锈\x01锈"; - | ~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | -LL | let _bad8 = "锈\x001锈"; - | ~~~~~~~~~~~ +LL | let _bad8 = "锈\x0001锈"; + | ~~~~~~ -error: octal-looking escape in string literal - --> tests/ui/octal_escapes.rs:22:17 +error: octal-looking escape in a literal + --> tests/ui/octal_escapes.rs:18:19 | LL | let _bad9 = "锈\011锈"; - | ^^^^^^^^^^ + | ^^^^ | - = help: octal escapes are not supported, `\0` is always a null character -help: if an octal escape was intended, use the hexadecimal representation instead +help: if an octal escape is intended, use a hex escape instead | LL | let _bad9 = "锈\x09锈"; - | ~~~~~~~~~~ -help: if the null character is intended, disambiguate using + | ~~~~ +help: if a null escape is intended, disambiguate using | LL | let _bad9 = "锈\x0011锈"; - | ~~~~~~~~~~~~ + | ~~~~~~ -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index eeab801b7da8..0ac89bf0d8ea 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -4,7 +4,8 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, - clippy::manual_unwrap_or_default + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 3e5b96d7c316..b4f1b2cd1f7f 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -4,7 +4,8 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, - clippy::manual_unwrap_or_default + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index f5359a0c34f9..37ef791edb00 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:11:5 + --> tests/ui/option_if_let_else.rs:12:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -12,19 +12,19 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:29:13 + --> tests/ui/option_if_let_else.rs:30:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:30:13 + --> tests/ui/option_if_let_else.rs:31:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:31:13 + --> tests/ui/option_if_let_else.rs:32:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -44,13 +44,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:37:13 + --> tests/ui/option_if_let_else.rs:38:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:38:13 + --> tests/ui/option_if_let_else.rs:39:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -70,7 +70,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:44:13 + --> tests/ui/option_if_let_else.rs:45:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -90,7 +90,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:53:5 + --> tests/ui/option_if_let_else.rs:54:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -109,7 +109,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:66:13 + --> tests/ui/option_if_let_else.rs:67:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:75:13 + --> tests/ui/option_if_let_else.rs:76:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -144,7 +144,7 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:108:13 + --> tests/ui/option_if_let_else.rs:109:13 | LL | / if let Some(idx) = s.find('.') { LL | | vec![s[..idx].to_string(), s[idx..].to_string()] @@ -154,7 +154,7 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:119:5 + --> tests/ui/option_if_let_else.rs:120:5 | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); @@ -177,13 +177,13 @@ LL + }) | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:143:13 + --> tests/ui/option_if_let_else.rs:144:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:153:13 + --> tests/ui/option_if_let_else.rs:154:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -205,13 +205,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:181:13 + --> tests/ui/option_if_let_else.rs:182:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:185:13 + --> tests/ui/option_if_let_else.rs:186:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -231,7 +231,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:224:13 + --> tests/ui/option_if_let_else.rs:225:13 | LL | let _ = match s { | _____________^ @@ -241,7 +241,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:228:13 + --> tests/ui/option_if_let_else.rs:229:13 | LL | let _ = match Some(10) { | _____________^ @@ -251,7 +251,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:234:13 + --> tests/ui/option_if_let_else.rs:235:13 | LL | let _ = match res { | _____________^ @@ -261,7 +261,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:238:13 + --> tests/ui/option_if_let_else.rs:239:13 | LL | let _ = match res { | _____________^ @@ -271,13 +271,13 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:242:13 + --> tests/ui/option_if_let_else.rs:243:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:259:17 + --> tests/ui/option_if_let_else.rs:260:17 | LL | let _ = match initial { | _________________^ @@ -287,7 +287,7 @@ LL | | }; | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:266:17 + --> tests/ui/option_if_let_else.rs:267:17 | LL | let _ = match initial { | _________________^ @@ -297,7 +297,7 @@ LL | | }; | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:289:24 + --> tests/ui/option_if_let_else.rs:290:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ @@ -308,7 +308,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:295:19 + --> tests/ui/option_if_let_else.rs:296:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/tests/ui/unnecessary_min_or_max.fixed b/tests/ui/unnecessary_min_or_max.fixed new file mode 100644 index 000000000000..392f6dd1fee4 --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.fixed @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32); + let _ = 9; + let _ = 6; + let _ = 9_u32; + let _ = 6; + let _ = 7_u8; + + let x: u32 = 42; + // unsigned with zero + let _ = 0; + let _ = x; + let _ = 0_u32; + let _ = x; + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN; + let _ = x; + let _ = i32::MIN; + let _ = x; + + let _ = i32::MIN - 0; + let _ = x; + + let _ = i32::MIN - 0; + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/tests/ui/unnecessary_min_or_max.rs b/tests/ui/unnecessary_min_or_max.rs new file mode 100644 index 000000000000..b03755e6d23d --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.rs @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32).min(9); + let _ = (-6_i32).max(9); + let _ = 9_u32.min(6); + let _ = 9_u32.max(6); + let _ = 6.min(7_u8); + let _ = 6.max(7_u8); + + let x: u32 = 42; + // unsigned with zero + let _ = 0.min(x); + let _ = 0.max(x); + let _ = x.min(0_u32); + let _ = x.max(0_u32); + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN.min(x); + let _ = i32::MIN.max(x); + let _ = x.min(i32::MIN); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/tests/ui/unnecessary_min_or_max.stderr b/tests/ui/unnecessary_min_or_max.stderr new file mode 100644 index 000000000000..f5cd31fbaf24 --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.stderr @@ -0,0 +1,107 @@ +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:13:13 + | +LL | let _ = (-6_i32).min(9); + | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` + | + = note: `-D clippy::unnecessary-min-or-max` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min_or_max)]` + +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:14:13 + | +LL | let _ = (-6_i32).max(9); + | ^^^^^^^^^^^^^^^ help: try: `9` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:15:13 + | +LL | let _ = 9_u32.min(6); + | ^^^^^^^^^^^^ help: try: `6` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:16:13 + | +LL | let _ = 9_u32.max(6); + | ^^^^^^^^^^^^ help: try: `9_u32` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:17:13 + | +LL | let _ = 6.min(7_u8); + | ^^^^^^^^^^^ help: try: `6` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:18:13 + | +LL | let _ = 6.max(7_u8); + | ^^^^^^^^^^^ help: try: `7_u8` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:22:13 + | +LL | let _ = 0.min(x); + | ^^^^^^^^ help: try: `0` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:23:13 + | +LL | let _ = 0.max(x); + | ^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:24:13 + | +LL | let _ = x.min(0_u32); + | ^^^^^^^^^^^^ help: try: `0_u32` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:25:13 + | +LL | let _ = x.max(0_u32); + | ^^^^^^^^^^^^ help: try: `x` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:29:13 + | +LL | let _ = i32::MIN.min(x); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:30:13 + | +LL | let _ = i32::MIN.max(x); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:31:13 + | +LL | let _ = x.min(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:32:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:34:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:35:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:37:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: aborting due to 17 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 4d66b728b76d..0f0e62670ffe 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -22,7 +22,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB users_on_vacation = [ "matthiaskrgr", "giraffate", - "Centri3", ] [assign.owners] @@ -32,10 +31,10 @@ users_on_vacation = [ "*" = [ "@Manishearth", "@llogiq", - "@xFrednet", "@Alexendoo", "@dswij", "@Jarcho", "@blyxyas", "@y21", + "@Centri3", ] diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index c88c298d5d78..8de36fc40051 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -103,6 +103,7 @@ Otherwise, have a great day =^.^= @media (min-width: 405px) { #upper-filters { display: flex; + flex-wrap: wrap; } } @@ -404,7 +405,7 @@ Otherwise, have a great day =^.^=
-
+
- +
+ + +
-
+
-
+

diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 7cca298df8e4..921bb0376f6c 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -156,6 +156,18 @@ Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) ); + const APPLICABILITIES_FILTER_DEFAULT = { + Unspecified: true, + Unresolved: true, + MachineApplicable: true, + MaybeIncorrect: true, + HasPlaceholders: true + }; + + $scope.applicabilities = { + ...APPLICABILITIES_FILTER_DEFAULT + } + // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them // to corresponding $scope variables. function loadFromURLParameters() { @@ -182,6 +194,7 @@ handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); + handleParameter('applicabilities', $scope.applicabilities, APPLICABILITIES_FILTER_DEFAULT); // Handle 'versions' parameter separately because it needs additional processing if (urlParameters.versions) { @@ -249,6 +262,7 @@ updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); updateVersionURLParameter($scope.versionFilters); + updateURLParameter($scope.applicabilities, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT); } // Add $watches to automatically update URL parameters when the data changes @@ -270,6 +284,12 @@ } }, true); + $scope.$watch('applicabilities', function (newVal, oldVal) { + if (newVal !== oldVal) { + updateURLParameter(newVal, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT) + } + }, true); + // Watch for changes in the URL path and update the search and lint display $scope.$watch(function () { return $location.path(); }, function (newPath) { const searchParameter = newPath.substring(1); @@ -327,6 +347,15 @@ } }; + $scope.toggleApplicabilities = function (value) { + const applicabilities = $scope.applicabilities; + for (const key in applicabilities) { + if (applicabilities.hasOwnProperty(key)) { + applicabilities[key] = value; + } + } + } + $scope.resetGroupsToDefault = function () { $scope.groups = { ...GROUPS_FILTER_DEFAULT @@ -430,6 +459,10 @@ return true; } + $scope.byApplicabilities = function (lint) { + return $scope.applicabilities[lint.applicability.applicability]; + }; + // Show details for one lint $scope.openLint = function (lint) { $scope.open[lint.id] = true; From 39a215531cc975d4dd50486f9d71187bdfad1086 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Jun 2024 14:56:57 -0400 Subject: [PATCH 037/361] Tighten spans for async blocks --- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index ab1b3043f0c3..1c1de805db0c 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -549,7 +549,7 @@ fn ident_difference_expr_with_base_location( | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) | (Await(_, _), Await(_, _)) - | (Gen(_, _, _), Gen(_, _, _)) + | (Gen(_, _, _, _), Gen(_, _, _, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) | (Match(_, _, _), Match(_, _, _)) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 785d5ed5dbeb..4b8d1c5ee9f3 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -226,7 +226,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { && eq_fn_decl(lf, rf) && eq_expr(le, re) }, - (Gen(lc, lb, lk), Gen(rc, rb, rk)) => lc == rc && eq_block(lb, rb) && lk == rk, + (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), From 6de87829da801c10db378e28dd1797434383e651 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 27 Jun 2024 16:35:43 -0700 Subject: [PATCH 038/361] doc_lazy_continuation: blank comment line for gap This change addresses cases where doc comments are separated by blank lines, comments, or non-doc-comment attributes, like this: ```rust /// - first line // not part of doc comment /// second line ``` Before this commit, Clippy gave a pedantically-correct warning about how you needed to indent the second line. This is unlikely to be what the user intends, and has been described as a "false positive" (since Clippy is warning you about a highly unintuitive behavior that Rustdoc actually has, we definitely want it to output *something*, but the suggestion to indent was poor). https://github.com/rust-lang/rust-clippy/issues/12917 --- clippy_lints/src/doc/lazy_continuation.rs | 29 +++++++++++- clippy_lints/src/doc/mod.rs | 1 + tests/ui/doc/doc_lazy_blank_line.fixed | 47 +++++++++++++++++++ tests/ui/doc/doc_lazy_blank_line.rs | 43 +++++++++++++++++ tests/ui/doc/doc_lazy_blank_line.stderr | 56 +++++++++++++++++++++++ tests/ui/doc/doc_lazy_blockquote.fixed | 12 ++--- tests/ui/doc/doc_lazy_blockquote.rs | 12 ++--- tests/ui/doc/doc_lazy_blockquote.stderr | 12 ++--- tests/ui/doc/doc_lazy_list.fixed | 31 +++++++------ tests/ui/doc/doc_lazy_list.rs | 22 ++++----- tests/ui/doc/doc_lazy_list.stderr | 49 ++++++++++---------- 11 files changed, 246 insertions(+), 68 deletions(-) create mode 100644 tests/ui/doc/doc_lazy_blank_line.fixed create mode 100644 tests/ui/doc/doc_lazy_blank_line.rs create mode 100644 tests/ui/doc/doc_lazy_blank_line.stderr diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index 38bc58a55019..bd1cc46e1850 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -22,6 +22,7 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], + line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -46,11 +47,35 @@ pub(super) fn check( .sum(); if ccount < blockquote_level || lcount < list_indentation { let msg = if ccount < blockquote_level { - "doc quote missing `>` marker" + "doc quote line without `>` marker" } else { - "doc list item missing indentation" + "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { + let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); + if snippet.chars().filter(|&c| c == '\n').count() > 1 + && let Some(doc_comment_start) = snippet.rfind('\n') + && let doc_comment = snippet[doc_comment_start..].trim() + && (doc_comment == "///" || doc_comment == "//!") + { + // suggest filling in a blank line + diag.span_suggestion_with_style( + line_break_span.shrink_to_lo(), + "if this should be its own paragraph, add a blank doc comment line", + format!("\n{doc_comment}"), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + if ccount > 0 || blockquote_level > 0 { + diag.help("if this not intended to be a quote at all, escape it with `\\>`"); + } else { + let indent = list_indentation - lcount; + diag.help(format!( + "if this is intended to be part of the list, indent {indent} spaces" + )); + } + return; + } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 3d875e7ac2d3..5faa00b7c971 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -762,6 +762,7 @@ fn check_doc<'a, Events: Iterator, Range blockquote code path +/// + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +/// +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.rs b/tests/ui/doc/doc_lazy_blank_line.rs new file mode 100644 index 000000000000..e1ab8fc83892 --- /dev/null +++ b/tests/ui/doc/doc_lazy_blank_line.rs @@ -0,0 +1,43 @@ +// https://github.com/rust-lang/rust-clippy/issues/12917 +#![warn(clippy::doc_lazy_continuation)] + +/// This is a constant. +/// +/// The meaning of which should not be explained. +pub const A: i32 = 42; + +/// This is another constant, no longer used. +/// +/// This block of documentation has a long +/// explanation and derivation to explain +/// why it is what it is, and how it's used. +/// +/// It is left here for historical reasons, and +/// for reference. +/// +/// Reasons it's great: +/// - First reason +/// - Second reason +//pub const B: i32 = 1337; + +/// This is yet another constant. +/// +/// This has a similar fate as `B`. +/// +/// Reasons it's useful: +/// 1. First reason +/// 2. Second reason +//pub const C: i32 = 8008; + +/// This is still in use. +pub const D: i32 = 20; + +/// > blockquote code path + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.stderr b/tests/ui/doc/doc_lazy_blank_line.stderr new file mode 100644 index 000000000000..854906a74741 --- /dev/null +++ b/tests/ui/doc/doc_lazy_blank_line.stderr @@ -0,0 +1,56 @@ +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 + | +LL | /// This is yet another constant. + | ^ + | + = help: if this is intended to be part of the list, indent 3 spaces + = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// - Second reason +LL + /// + | + +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 + | +LL | /// This is still in use. + | ^ + | + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// 2. Second reason +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/doc/doc_lazy_blockquote.fixed b/tests/ui/doc/doc_lazy_blockquote.fixed index 9877991f183a..9d6e8637608f 100644 --- a/tests/ui/doc/doc_lazy_blockquote.fixed +++ b/tests/ui/doc/doc_lazy_blockquote.fixed @@ -2,7 +2,7 @@ /// > blockquote with /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// > lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/tests/ui/doc/doc_lazy_blockquote.rs b/tests/ui/doc/doc_lazy_blockquote.rs index 587b2fdd533c..0323a1b44e7c 100644 --- a/tests/ui/doc/doc_lazy_blockquote.rs +++ b/tests/ui/doc/doc_lazy_blockquote.rs @@ -2,7 +2,7 @@ /// > blockquote with /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/tests/ui/doc/doc_lazy_blockquote.stderr b/tests/ui/doc/doc_lazy_blockquote.stderr index 975184a01c3f..d3390efdff37 100644 --- a/tests/ui/doc/doc_lazy_blockquote.stderr +++ b/tests/ui/doc/doc_lazy_blockquote.stderr @@ -1,4 +1,4 @@ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: add markers to start of line LL | /// > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:20:5 | LL | /// > lazy continuation @@ -24,7 +24,7 @@ help: add markers to start of line LL | /// > > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:27:5 | LL | /// lazy continuation @@ -36,7 +36,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:32:5 | LL | /// lazy continuation @@ -48,7 +48,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:37:5 | LL | /// lazy continuation @@ -60,7 +60,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:45:5 | LL | /// lazy continuation (this results in strange indentation, but still works) diff --git a/tests/ui/doc/doc_lazy_list.fixed b/tests/ui/doc/doc_lazy_list.fixed index 409e6b0bc227..ea59ae4c01c9 100644 --- a/tests/ui/doc/doc_lazy_list.fixed +++ b/tests/ui/doc/doc_lazy_list.fixed @@ -2,38 +2,41 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation -/// and so should this -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// and so should this +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +57,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +76,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/tests/ui/doc/doc_lazy_list.rs b/tests/ui/doc/doc_lazy_list.rs index 30ab448a1130..3cc18e35780a 100644 --- a/tests/ui/doc/doc_lazy_list.rs +++ b/tests/ui/doc/doc_lazy_list.rs @@ -2,38 +2,38 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// and so should this -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +54,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +73,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/tests/ui/doc/doc_lazy_list.stderr b/tests/ui/doc/doc_lazy_list.stderr index ddfdc49340c4..52aa74df8948 100644 --- a/tests/ui/doc/doc_lazy_list.stderr +++ b/tests/ui/doc/doc_lazy_list.stderr @@ -1,4 +1,4 @@ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: indent this line LL | /// lazy continuation | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:9:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -24,19 +24,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:11:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 3 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 | LL | /// lazy continuation @@ -48,7 +49,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:21:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -60,19 +61,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:23:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 | LL | /// lazy continuation @@ -84,7 +86,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:33:5 | LL | /// this will warn on the lazy continuation @@ -96,19 +98,20 @@ help: indent this line LL | /// this will warn on the lazy continuation | ++++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:35:5 | LL | /// and so should this | ^^^^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 2 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// this will warn on the lazy continuation +LL + /// | -LL | /// and so should this - | ++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 | LL | /// 'protocol_descriptors': [ @@ -120,7 +123,7 @@ help: indent this line LL | /// 'protocol_descriptors': [ | + -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:75:5 | LL | /// ] From 01a6dfa29fce5fe0375318b6504526cbd41d277e Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 28 Jun 2024 10:29:18 +0200 Subject: [PATCH 039/361] Add error message to manual_inspect lint --- clippy_lints/src/methods/manual_inspect.rs | 26 +++++++++++++--------- tests/ui/manual_inspect.stderr | 24 ++++++++++---------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index e3ce64c246a5..cac2e11f5916 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { edits.extend(addr_of_edits); } - edits.push(( - name_span, - String::from(match name { - "map" => "inspect", - "map_err" => "inspect_err", - _ => return, - }), - )); + let edit = match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }; + edits.push((name_span, edit.to_string())); edits.push(( final_expr .span @@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { Applicability::MachineApplicable }; - span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { - diag.multipart_suggestion("try", edits, app); - }); + span_lint_and_then( + cx, + MANUAL_INSPECT, + name_span, + format!("using `{name}` over `{edit}`"), + |diag| { + diag.multipart_suggestion("try", edits, app); + }, + ); } } } diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr index 8548c0cd2942..0559b3bd6611 100644 --- a/tests/ui/manual_inspect.stderr +++ b/tests/ui/manual_inspect.stderr @@ -1,4 +1,4 @@ -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:5:21 | LL | let _ = Some(0).map(|x| { @@ -12,7 +12,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:10:21 | LL | let _ = Some(0).map(|x| { @@ -24,7 +24,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{x}"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:15:21 | LL | let _ = Some(0).map(|x| { @@ -36,7 +36,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x * 5 + 1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:20:21 | LL | let _ = Some(0).map(|x| { @@ -50,7 +50,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:27:21 | LL | let _ = Some(0).map(|x| { @@ -65,7 +65,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:78:41 | LL | let _ = Some((String::new(), 0u32)).map(|x| { @@ -80,7 +80,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:104:33 | LL | let _ = Some(String::new()).map(|x| { @@ -98,7 +98,7 @@ LL | } LL ~ println!("test"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:115:21 | LL | let _ = Some(0).map(|x| { @@ -113,7 +113,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:130:46 | LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { @@ -125,7 +125,7 @@ LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { LL ~ x.0.set(1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:146:34 | LL | let _: Result<_, ()> = Ok(0).map(|x| { @@ -137,7 +137,7 @@ LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map_err` over `inspect_err` --> tests/ui/manual_inspect.rs:151:35 | LL | let _: Result<(), _> = Err(0).map_err(|x| { @@ -166,7 +166,7 @@ LL | | .count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:158:10 | LL | .map(|x| { From 74bc964e60eee642297face703940c6c8c198cf5 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 25 Jun 2024 10:44:00 +0000 Subject: [PATCH 040/361] finishing touches, move fixed ICEs to ui tests --- .../ui/missing_const_for_fn/could_be_const.rs | 3 +++ .../could_be_const.stderr | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) 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 58e639cc7fd1..5e4e2c58e5a4 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -104,15 +104,18 @@ fn main() {} struct D; +/* FIXME(effects) impl const Drop for D { fn drop(&mut self) { todo!(); } } +*/ // Lint this, since it can be dropped in const contexts // FIXME(effects) fn d(this: D) {} +//~^ ERROR: this could be a `const fn` mod msrv { struct Foo(*const u8, &'static u8); 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 8999af761e31..8ba42c0e5b67 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -157,7 +157,13 @@ LL | const fn msrv_1_46() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:117:1 + | +LL | fn d(this: D) {} + | ^^^^^^^^^^^^^^^^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 | LL | / fn deref_ptr_can_be_const(self) -> usize { LL | | @@ -171,7 +177,7 @@ LL | const fn deref_ptr_can_be_const(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:130:9 | LL | / fn deref_copied_val(self) -> usize { LL | | @@ -185,7 +191,7 @@ LL | const fn deref_copied_val(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:141:5 | LL | / fn union_access_can_be_const() { LL | | @@ -200,7 +206,7 @@ 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:152:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -213,7 +219,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -226,7 +232,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -239,5 +245,5 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors From 2fcef6e9f7bb3e94bf889fa3846afbfb25c991b8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 26 Jun 2024 16:36:42 +0000 Subject: [PATCH 041/361] address review comments --- tests/ui/missing_const_for_fn/could_be_const.fixed | 5 ++++- tests/ui/missing_const_for_fn/could_be_const.stderr | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) 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 921dcf0b1626..f8fc935f3679 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -104,15 +104,18 @@ fn main() {} struct D; +/* FIXME(effects) impl const Drop for D { fn drop(&mut self) { todo!(); } } +*/ // Lint this, since it can be dropped in const contexts // FIXME(effects) -fn d(this: D) {} +const fn d(this: D) {} +//~^ ERROR: this could be a `const fn` mod msrv { struct Foo(*const u8, &'static u8); 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 8ba42c0e5b67..8302b074127e 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -161,6 +161,11 @@ error: this could be a `const fn` | LL | fn d(this: D) {} | ^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn d(this: D) {} + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 From eb33c1ac74d0e209b320bbc58c4a9c8085154797 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 28 Jun 2024 22:48:46 +0100 Subject: [PATCH 042/361] Image-related valid idents --- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index cfd34c7d2a7d..4fc109c7851f 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -454,7 +454,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index dbab3b106a80..9cc119c68cb1 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -31,6 +31,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", + "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", From b08b8b8a75a37db53bdc7756914a8a37c36a79c3 Mon Sep 17 00:00:00 2001 From: Roman Franchuk Date: Sun, 23 Jun 2024 12:30:20 +0200 Subject: [PATCH 043/361] Implement a lint to replace bit manual rotations with rotate_left/rotate_right --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_rotate.rs | 117 +++++++++++++++++++++++++++++ tests/ui/manual_rotate.fixed | 31 ++++++++ tests/ui/manual_rotate.rs | 31 ++++++++ tests/ui/manual_rotate.stderr | 71 +++++++++++++++++ 7 files changed, 254 insertions(+) create mode 100644 clippy_lints/src/manual_rotate.rs create mode 100644 tests/ui/manual_rotate.fixed create mode 100644 tests/ui/manual_rotate.rs create mode 100644 tests/ui/manual_rotate.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 70ef2c793640..0974631ac5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5539,6 +5539,7 @@ Released 2018-09-13 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain +[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 638de5e818c8..53f346c04e78 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, + crate::manual_rotate::MANUAL_ROTATE_INFO, crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ed0ff51fbf65..fa4c7084f4dd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -211,6 +211,7 @@ mod manual_non_exhaustive; mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; +mod manual_rotate; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; @@ -1023,6 +1024,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate)); store.register_late_pass(move |_| { Box::new(operators::Operators::new( verbose_bit_mask_threshold, diff --git a/clippy_lints/src/manual_rotate.rs b/clippy_lints/src/manual_rotate.rs new file mode 100644 index 000000000000..a517a4d50752 --- /dev/null +++ b/clippy_lints/src/manual_rotate.rs @@ -0,0 +1,117 @@ +use std::fmt::Display; + +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// It detects manual bit rotations that could be rewritten using standard + /// functions `rotate_left` or `rotate_right`. + /// + /// ### Why is this bad? + /// + /// Calling the function better conveys the intent. + /// + /// ### Known issues + /// + /// Currently, the lint only catches shifts by constant amount. + /// + /// ### Example + /// ```no_run + /// let x = 12345678_u32; + /// let _ = (x >> 8) | (x << 24); + /// ``` + /// Use instead: + /// ```no_run + /// let x = 12345678_u32; + /// let _ = x.rotate_right(8); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_ROTATE, + style, + "using bit shifts to rotate integers" +} + +declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ShiftDirection { + Left, + Right, +} + +impl Display for ShiftDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Left => "rotate_left", + Self::Right => "rotate_right", + }) + } +} + +fn parse_shift<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> { + if let ExprKind::Binary(op, l, r) = expr.kind { + let dir = match op.node { + BinOpKind::Shl => ShiftDirection::Left, + BinOpKind::Shr => ShiftDirection::Right, + _ => return None, + }; + let const_expr = constant(cx, cx.typeck_results(), r)?; + if let Constant::Int(shift) = const_expr { + return Some((dir, shift, l)); + } + } + None +} + +impl LateLintPass<'_> for ManualRotate { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Binary(op, l, r) = expr.kind + && let BinOpKind::Add | BinOpKind::BitOr = op.node + && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l) + && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r) + { + if l_shift_dir == r_shift_dir { + return; + } + if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) { + return; + } + let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() { + ty::Int(itype) => itype.bit_width(), + ty::Uint(itype) => itype.bit_width(), + _ => return, + }) else { + return; + }; + if l_amount + r_amount == u128::from(bit_width) { + let (shift_function, amount) = if l_amount < r_amount { + (l_shift_dir, l_amount) + } else { + (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(); + span_lint_and_sugg( + cx, + MANUAL_ROTATE, + expr.span, + "there is no need to manually implement bit rotation", + "this expression can be rewritten as", + format!("{expr_sugg}.{shift_function}({amount})"), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/tests/ui/manual_rotate.fixed b/tests/ui/manual_rotate.fixed new file mode 100644 index 000000000000..5d33838a3187 --- /dev/null +++ b/tests/ui/manual_rotate.fixed @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = x_u8.rotate_right(3); + let y_u16 = x_u16.rotate_right(7); + let y_u32 = x_u32.rotate_right(8); + let y_u64 = x_u64.rotate_right(9); + let y_i8 = x_i8.rotate_right(3); + let y_i16 = x_i16.rotate_right(7); + let y_i32 = x_i32.rotate_right(8); + let y_i64 = x_i64.rotate_right(9); + // Plus also works instead of | + let y_u32_plus = x_u32.rotate_right(8); + // Complex expression + let y_u32_complex = (x_u32 | 3256).rotate_right(8); + let y_u64_as = (x_u32 as u64).rotate_right(8); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/tests/ui/manual_rotate.rs b/tests/ui/manual_rotate.rs new file mode 100644 index 000000000000..5377491fb1a3 --- /dev/null +++ b/tests/ui/manual_rotate.rs @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + // Plus also works instead of | + let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + // Complex expression + let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/tests/ui/manual_rotate.stderr b/tests/ui/manual_rotate.stderr new file mode 100644 index 000000000000..52da0861f700 --- /dev/null +++ b/tests/ui/manual_rotate.stderr @@ -0,0 +1,71 @@ +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:8:16 + | +LL | let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)` + | + = note: `-D clippy::manual-rotate` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:9:17 + | +LL | let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:10:17 + | +LL | let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:11:17 + | +LL | let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:12:16 + | +LL | let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:13:17 + | +LL | let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:14:17 + | +LL | let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:15:17 + | +LL | let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:17:22 + | +LL | let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:19:25 + | +LL | let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:20:20 + | +LL | let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)` + +error: aborting due to 11 previous errors + From 5adaed06a0326a567ce0571ba1cdbf503f99bf86 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 11:28:14 +0000 Subject: [PATCH 044/361] Merge commit '49cd5dd454d0115cfbe9e39102a8b3ba4616aa40' into sync_cg_clif-2024-06-30 --- .github/workflows/abi-cafe.yml | 4 - .github/workflows/main.yml | 17 ++-- Cargo.lock | 58 ++++++------- Cargo.toml | 14 ++-- Readme.md | 3 +- build_system/build_sysroot.rs | 35 -------- build_system/tests.rs | 36 +------- example/mini_core_hello_world.rs | 20 ++--- example/std_example.rs | 38 +++++++++ patches/stdlib-lock.toml | 33 +++++--- rust-toolchain | 2 +- scripts/test_rustc_tests.sh | 30 ++++--- src/abi/mod.rs | 137 +++++++++++++++++++++++-------- src/allocator.rs | 12 +-- src/base.rs | 5 +- src/common.rs | 4 +- src/driver/aot.rs | 31 +++---- src/driver/jit.rs | 52 ++++-------- src/inline_asm.rs | 16 +--- src/intrinsics/llvm_x86.rs | 41 ++++++++- src/lib.rs | 20 ++--- src/main_shim.rs | 10 +-- src/unwind_module.rs | 115 ++++++++++++++++++++++++++ 23 files changed, 441 insertions(+), 292 deletions(-) create mode 100644 src/unwind_module.rs diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index b7063f35a3e8..1ed6f8fc359d 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -55,10 +55,6 @@ jobs: if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' run: rustup set default-host x86_64-apple-darwin - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f5a6513f63b..a2ae3d63fb90 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,6 +66,9 @@ jobs: env: TARGET_TRIPLE: aarch64-unknown-linux-gnu apt_deps: gcc-aarch64-linux-gnu qemu-user + - os: macos-latest + env: + TARGET_TRIPLE: aarch64-apple-darwin - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu @@ -108,10 +111,6 @@ jobs: sudo apt-get update sudo apt-get install -y ${{ matrix.apt_deps }} - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare @@ -214,6 +213,9 @@ jobs: - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin + - os: macos-latest + env: + TARGET_TRIPLE: aarch64-apple-darwin # cross-compile from Linux to Windows using mingw - os: ubuntu-latest env: @@ -248,10 +250,6 @@ jobs: sudo apt-get update sudo apt-get install -y gcc-mingw-w64-x86-64 - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare @@ -282,7 +280,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/master' }} - needs: [rustfmt, test, bench, dist] + # FIXME add the bench job back to the dependency list once rust-lang/rust#125493 gets merged + needs: [rustfmt, test, dist] permissions: contents: write # for creating the dev tag and release diff --git a/Cargo.lock b/Cargo.lock index 33fe52ddbdd6..15c9e9d66fac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b27922a6879b5b5361d0a084cb0b1941bf109a98540addcb932da13b68bed4" +checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304c455b28bf56372729acb356afbb55d622f2b0f2f7837aa5e57c138acaac4d" +checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa" dependencies = [ "bumpalo", "cranelift-bforest", @@ -70,45 +70,46 @@ dependencies = [ "hashbrown 0.14.3", "log", "regalloc2", + "rustc-hash", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1653c56b99591d07f67c5ca7f9f25888948af3f4b97186bff838d687d666f613" +checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b6a9cf6b6eb820ee3f973a0db313c05dc12d370f37b4fe9630286e1672573f" +checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da" [[package]] name = "cranelift-control" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d06e6bf30075fb6bed9e034ec046475093392eea1aff90eb5c44c4a033d19a" +checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29be04f931b73cdb9694874a295027471817f26f26d2f0ebe5454153176b6e3a" +checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b" [[package]] name = "cranelift-frontend" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07fd7393041d7faa2f37426f5dc7fc04003b70988810e8c063beefeff1cd8f9" +checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5" dependencies = [ "cranelift-codegen", "log", @@ -118,15 +119,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f341d7938caa6dff8149dac05bb2b53fc680323826b83b4cf175ab9f5139a3c9" +checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e" [[package]] name = "cranelift-jit" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42733555e06433f1461570e09dbd756dafc228b4dac75c597cdbdc518de07522" +checksum = "f5c5cfb8bbd3339cd25cca30e7516ff8fe5cb1feeddde6980cc4d5ef34df97bb" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +145,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84950af02bb85f3da764d53a953b43bb29a732e793d4fe24637a61591be9a024" +checksum = "7c9b0d4269b36fd858e6d8f20cd4938941186fb831488c361888cb2d6b33a9a6" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +156,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82af6066e6448d26eeabb7aa26a43f7ff79f8217b06bade4ee6ef230aecc8880" +checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581" dependencies = [ "cranelift-codegen", "libc", @@ -166,9 +167,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00af56107039ed150391df6f753298c7b08f2b6a2e0727d216b5fa599d684d8b" +checksum = "19e33439ec20db058bc7cc3410f9748ab1ad90a35cef713d625c736f43e3820d" dependencies = [ "anyhow", "cranelift-codegen", @@ -278,9 +279,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "object" -version = "0.33.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "crc32fast", "hashbrown 0.14.3", @@ -410,10 +411,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "20.0.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9f93a3289057b26dc75eb84d6e60d7694f7d169c7c09597495de6e016a13ff" +checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91" dependencies = [ + "anyhow", "cfg-if", "libc", "windows-sys", diff --git a/Cargo.toml b/Cargo.toml index 2015cdbcc2a7..2969a6cf6eca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.107.0", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.107.0" } -cranelift-module = { version = "0.107.0" } -cranelift-native = { version = "0.107.0" } -cranelift-jit = { version = "0.107.0", optional = true } -cranelift-object = { version = "0.107.0" } +cranelift-codegen = { version = "0.109.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.109.0" } +cranelift-module = { version = "0.109.0" } +cranelift-native = { version = "0.109.0" } +cranelift-jit = { version = "0.109.0", optional = true } +cranelift-object = { version = "0.109.0" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} -object = { version = "0.33", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.8.0", optional = true } diff --git a/Readme.md b/Readme.md index 00ea15cb38cc..eb21e027dd0e 100644 --- a/Readme.md +++ b/Readme.md @@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |FreeBSD|✅[^no-rustup]|❓|❓|❓| |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| -|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|macOS|✅|✅[^no-rustup]|N/A|N/A| |Windows|✅[^no-rustup]|❌|N/A|N/A| ✅: Fully supported and tested @@ -80,7 +80,6 @@ For more docs on how to build and test see [build_system/usage.txt](build_system Not all targets are available as rustup component for nightly. See notes in the platform support matrix. [^xcoff]: XCOFF object file format is not supported. -[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). [^no-rustup]: Not available as rustup component for nightly. You can build it yourself. ## Usage diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 196ff8fda754..dfbe0f51e7be 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -267,10 +267,6 @@ fn build_clif_sysroot_for_triple( prefix.to_str().unwrap() )); } - rustflags.push("-Zunstable-options".to_owned()); - for (name, values) in EXTRA_CHECK_CFGS { - rustflags.push(check_cfg_arg(name, *values)); - } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); if channel == "release" { @@ -330,34 +326,3 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { Some(target_libs) } - -// Copied from https://github.com/rust-lang/rust/blob/4fd98a4b1b100f5329c6efae18031791f64372d2/src/bootstrap/src/utils/helpers.rs#L569-L585 -/// Create a `--check-cfg` argument invocation for a given name -/// and it's values. -fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { - // Creating a string of the values by concatenating each value: - // ',values("tvos","watchos")' or '' (nothing) when there are no values. - let next = match values { - Some(values) => { - let mut tmp = values.iter().flat_map(|val| [",", "\"", val, "\""]).collect::(); - - tmp.insert_str(1, "values("); - tmp.push(')'); - tmp - } - None => "".to_string(), - }; - format!("--check-cfg=cfg({name}{next})") -} - -const EXTRA_CHECK_CFGS: &[(&str, Option<&[&str]>)] = &[ - ("bootstrap", None), - ("stdarch_intel_sde", None), - ("no_fp_fmt_parse", None), - ("no_global_oom_handling", None), - ("no_rc", None), - ("no_sync", None), - ("netbsd10", None), - ("backtrace_in_libstd", None), - ("target_arch", Some(&["xtensa"])), -]; diff --git a/build_system/tests.rs b/build_system/tests.rs index 278f334796a9..790d9cbd9fc5 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -329,7 +329,6 @@ pub(crate) fn run_tests( struct TestRunner<'a> { is_native: bool, jit_supported: bool, - use_unstable_features: bool, skip_tests: &'a [&'a str], dirs: Dirs, target_compiler: Compiler, @@ -361,15 +360,7 @@ impl<'a> TestRunner<'a> { && target_compiler.triple.contains("x86_64") && !target_compiler.triple.contains("windows"); - Self { - is_native, - jit_supported, - use_unstable_features, - skip_tests, - dirs, - target_compiler, - stdlib_source, - } + Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source } } fn run_testsuite(&self, tests: &[TestCase]) { @@ -393,31 +384,13 @@ impl<'a> TestRunner<'a> { match *cmd { TestCaseCmd::Custom { func } => func(self), TestCaseCmd::BuildLib { source, crate_types } => { - if self.use_unstable_features { - self.run_rustc([source, "--crate-type", crate_types]); - } else { - self.run_rustc([ - source, - "--crate-type", - crate_types, - "--cfg", - "no_unstable_features", - ]); - } + self.run_rustc([source, "--crate-type", crate_types]); } TestCaseCmd::BuildBin { source } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } + self.run_rustc([source]); } TestCaseCmd::BuildBinAndRun { source, args } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } + self.run_rustc([source]); self.run_out_command( source.split('/').last().unwrap().split('.').next().unwrap(), args, @@ -472,7 +445,6 @@ impl<'a> TestRunner<'a> { cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); cmd.arg("-Zunstable-options"); - cmd.arg("--check-cfg=cfg(no_unstable_features)"); cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); cmd diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index aab20f672487..7d361a9ab2bb 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -333,12 +333,7 @@ fn main() { #[cfg(all(not(jit), not(all(windows, target_env = "gnu"))))] test_tls(); - #[cfg(all( - not(jit), - not(no_unstable_features), - target_arch = "x86_64", - any(target_os = "linux", target_os = "macos") - ))] + #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))] unsafe { global_asm_test(); naked_test(); @@ -367,17 +362,12 @@ fn stack_val_align() { assert_eq!(&a as *const Foo as usize % 8192, 0); } -#[cfg(all( - not(jit), - not(no_unstable_features), - target_arch = "x86_64", - any(target_os = "linux", target_os = "macos") -))] +#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))] extern "C" { fn global_asm_test(); } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "linux"))] +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))] global_asm! { " .global global_asm_test @@ -387,7 +377,7 @@ global_asm! { " } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "macos"))] +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "macos"))] global_asm! { " .global _global_asm_test @@ -397,7 +387,7 @@ global_asm! { " } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64"))] +#[cfg(all(not(jit), target_arch = "x86_64"))] #[naked] extern "C" fn naked_test() { unsafe { diff --git a/example/std_example.rs b/example/std_example.rs index 7347b2e77899..6cedd84adfe5 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -251,6 +251,9 @@ unsafe fn test_simd() { test_mm_add_epi8(); test_mm_add_pd(); test_mm_cvtepi8_epi16(); + #[cfg(not(jit))] + test_mm_cvtps_epi32(); + test_mm_cvttps_epi32(); test_mm_cvtsi128_si64(); test_mm_extract_epi8(); @@ -476,6 +479,41 @@ unsafe fn test_mm256_permutevar8x32_epi32() { assert_eq_m256i(r, e); } +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[cfg(not(jit))] +unsafe fn test_mm_cvtps_epi32() { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvtps_epi32(float_vec); + + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [2, -2, i32::MIN, i32::MIN]; + + assert_eq!(ints, expected_ints); +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +unsafe fn test_mm_cvttps_epi32() { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvttps_epi32(float_vec); + + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [1, -2, i32::MIN, i32::MIN]; + + assert_eq!(ints, expected_ints); +} + fn test_checked_mul() { let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index c8c7b45bc9a6..9ea53e8f848d 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -4,12 +4,12 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.29.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -133,6 +133,17 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -147,9 +158,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -189,9 +200,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "compiler_builtins", "memchr", @@ -286,9 +297,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -396,8 +407,6 @@ dependencies = [ "core", "getopts", "libc", - "panic_abort", - "panic_unwind", "std", ] @@ -430,7 +439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.28.1", "rustc-std-workspace-core", ] diff --git a/rust-toolchain b/rust-toolchain index a2ba79cbe903..cfa91744a0e8 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-13" +channel = "nightly-2024-06-30" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 689cda21643c..c1b7e4b0e076 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -36,9 +36,8 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic # exotic linkages -rm tests/ui/issues/issue-33992.rs # unsupported linkages -rm tests/incremental/hashes/function_interfaces.rs # same -rm tests/incremental/hashes/statics.rs # same +rm tests/incremental/hashes/function_interfaces.rs +rm tests/incremental/hashes/statics.rs # variadic arguments rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs @@ -60,13 +59,20 @@ rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported # requires LTO rm -r tests/run-make/cdylib -rm -r tests/run-make/issue-14500 -rm -r tests/run-make/issue-64153 rm -r tests/run-make/codegen-options-parsing rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 rm -r tests/run-make/issue-109934-lto-debuginfo rm -r tests/run-make/no-builtins-lto +rm -r tests/run-make/reachable-extern-fn-available-lto + +# coverage instrumentation +rm tests/ui/consts/precise-drop-with-coverage.rs +rm tests/ui/issues/issue-85461.rs +rm -r tests/ui/instrument-coverage/ + +# missing f16/f128 support +rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs # optimization tests # ================== @@ -74,6 +80,7 @@ rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same rm tests/ui/issues/issue-40883.rs # same rm -r tests/run-make/fmt-write-bloat/ # tests an optimization +rm tests/ui/statics/const_generics.rs # same # backend specific tests # ====================== @@ -85,6 +92,7 @@ rm -r tests/run-make/sepcomp-cci-copies # same rm -r tests/run-make/volatile-intrinsics # same rm -r tests/run-make/llvm-ident # same rm -r tests/run-make/no-builtins-attribute # same +rm -r tests/run-make/pgo-gen-no-imp-symbols # same rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific @@ -93,13 +101,14 @@ rm -r tests/run-make/print-to-output # requires --print relocation-models # requires asm, llvm-ir and/or llvm-bc emit support # ============================================= rm -r tests/run-make/emit-named-files -rm -r tests/run-make/issue-30063 rm -r tests/run-make/multiple-emits rm -r tests/run-make/output-type-permutations rm -r tests/run-make/emit-to-stdout rm -r tests/run-make/compressed-debuginfo rm -r tests/run-make/symbols-include-type-name - +rm -r tests/run-make/notify-all-emit-artifacts +rm -r tests/run-make/reset-codegen-1 +rm -r tests/run-make/inline-always-many-cgu # giving different but possibly correct results # ============================================= @@ -118,6 +127,7 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain # ============ rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort +rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation warning for -Cinline-threshold # bugs in the test suite # ====================== @@ -148,12 +158,12 @@ index 9607ff02f96..b7d97caf9a2 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -34,8 +34,6 @@ pub fn bare() -> Self { - /// Construct a \`rustdoc\` invocation with \`-L \$(TARGET_RPATH_DIR)\` set. + #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); -- let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); +- let target_rpath_dir = env_var_os("TARGET_RPATH_DIR"); - cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); - Self { cmd, stdin: None } + Self { cmd } } EOF diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 695dbaf2804b..0d7eee7afb41 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -5,8 +5,9 @@ mod pass_mode; mod returning; use std::borrow::Cow; +use std::mem; -use cranelift_codegen::ir::SigRef; +use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; @@ -17,7 +18,7 @@ use rustc_middle::ty::TypeVisitableExt; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::abi::call::{Conv, FnAbi}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::spec::abi::Abi; use self::pass_mode::*; @@ -487,6 +488,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let args = args; assert_eq!(fn_abi.args.len(), args.len()); + #[derive(Copy, Clone)] enum CallTarget { Direct(FuncRef), Indirect(SigRef, Value), @@ -532,7 +534,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( }; self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| { - let call_args = return_ptr + let mut call_args = return_ptr .into_iter() .chain(first_arg_override.into_iter()) .chain( @@ -545,40 +547,17 @@ pub(crate) fn codegen_terminator_call<'tcx>( ) .collect::>(); - let call_inst = match func_ref { + // FIXME: Find a cleaner way to support varargs. + if fn_abi.c_variadic { + adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); + } + + match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) } - }; - - // FIXME find a cleaner way to support varargs - if fn_sig.c_variadic() { - if !matches!(fn_sig.abi(), Abi::C { .. }) { - fx.tcx.dcx().span_fatal( - source_info.span, - format!("Variadic call for non-C abi {:?}", fn_sig.abi()), - ); - } - let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap(); - let abi_params = call_args - .into_iter() - .map(|arg| { - let ty = fx.bcx.func.dfg.value_type(arg); - if !ty.is_int() { - // FIXME set %al to upperbound on float args once floats are supported - fx.tcx.dcx().span_fatal( - source_info.span, - format!("Non int ty {:?} for variadic call", ty), - ); - } - AbiParam::new(ty) - }) - .collect::>(); - fx.bcx.func.dfg.signatures[sig_ref].params = abi_params; } - - call_inst }); if let Some(dest) = target { @@ -587,6 +566,100 @@ pub(crate) fn codegen_terminator_call<'tcx>( } else { fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } + + fn adjust_call_for_c_variadic<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + source_info: mir::SourceInfo, + target: CallTarget, + call_args: &mut Vec, + ) { + if fn_abi.conv != Conv::C { + fx.tcx.dcx().span_fatal( + source_info.span, + format!("Variadic call for non-C abi {:?}", fn_abi.conv), + ); + } + let sig_ref = match target { + CallTarget::Direct(func_ref) => fx.bcx.func.dfg.ext_funcs[func_ref].signature, + CallTarget::Indirect(sig_ref, _) => sig_ref, + }; + // `mem::take()` the `params` so that `fx.bcx` can be used below. + let mut abi_params = mem::take(&mut fx.bcx.func.dfg.signatures[sig_ref].params); + + // Recalculate the parameters in the signature to ensure the signature contains the variadic arguments. + let has_return_arg = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); + // Drop everything except the return argument (if there is one). + abi_params.truncate(if has_return_arg { 1 } else { 0 }); + // Add the fixed arguments. + abi_params.extend( + fn_abi.args[..fn_abi.fixed_count as usize] + .iter() + .flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()), + ); + let fixed_arg_count = abi_params.len(); + // Add the variadic arguments. + abi_params.extend( + fn_abi.args[fn_abi.fixed_count as usize..] + .iter() + .flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()), + ); + + if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" { + // Add any padding arguments needed for Apple AArch64. + // There's no need to pad the argument list unless variadic arguments are actually being + // passed. + if abi_params.len() > fixed_arg_count { + // 128-bit integers take 2 registers, and everything else takes 1. + // FIXME: Add support for non-integer types + // This relies on the checks below to ensure all arguments are integer types and + // that the ABI is "C". + // The return argument isn't counted as it goes in its own dedicated register. + let integer_registers_used: usize = abi_params + [if has_return_arg { 1 } else { 0 }..fixed_arg_count] + .iter() + .map(|arg| if arg.value_type.bits() == 128 { 2 } else { 1 }) + .sum(); + // The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out + // the registers if needed to ensure the variadic arguments are passed on the stack. + if integer_registers_used < 8 { + abi_params.splice( + fixed_arg_count..fixed_arg_count, + (integer_registers_used..8).map(|_| AbiParam::new(types::I64)), + ); + call_args.splice( + fixed_arg_count..fixed_arg_count, + (integer_registers_used..8).map(|_| fx.bcx.ins().iconst(types::I64, 0)), + ); + } + } + + // `StructArgument` is not currently used by the `aarch64` ABI, and is therefore not + // handled when calculating how many padding arguments to use. Assert that this remains + // the case. + assert!(abi_params.iter().all(|param| matches!( + param.purpose, + // The only purposes used are `Normal` and `StructReturn`. + ArgumentPurpose::Normal | ArgumentPurpose::StructReturn + ))); + } + + // Check all parameters are integers. + for param in abi_params.iter() { + if !param.value_type.is_int() { + // FIXME: Set %al to upperbound on float args once floats are supported. + fx.tcx.dcx().span_fatal( + source_info.span, + format!("Non int ty {:?} for variadic call", param.value_type), + ); + } + } + + assert_eq!(abi_params.len(), call_args.len()); + + // Put the `AbiParam`s back in the signature. + fx.bcx.func.dfg.signatures[sig_ref].params = abi_params; + } } pub(crate) fn codegen_drop<'tcx>( diff --git a/src/allocator.rs b/src/allocator.rs index e8af3e8c2555..b4a3825e9965 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -11,15 +11,10 @@ use rustc_session::config::OomStrategy; use crate::prelude::*; /// Returns whether an allocator shim was created -pub(crate) fn codegen( - tcx: TyCtxt<'_>, - module: &mut impl Module, - unwind_context: &mut UnwindContext, -) -> bool { +pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; codegen_inner( module, - unwind_context, kind, tcx.alloc_error_handler_kind(()).unwrap(), tcx.sess.opts.unstable_opts.oom, @@ -28,8 +23,7 @@ pub(crate) fn codegen( } fn codegen_inner( - module: &mut impl Module, - unwind_context: &mut UnwindContext, + module: &mut dyn Module, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, oom_strategy: OomStrategy, @@ -67,7 +61,6 @@ fn codegen_inner( }; crate::common::create_wrapper_function( module, - unwind_context, sig, &global_fn_name(method.name), &default_fn_name(method.name), @@ -82,7 +75,6 @@ fn codegen_inner( }; crate::common::create_wrapper_function( module, - unwind_context, sig, "__rust_alloc_error_handler", &alloc_error_handler_name(alloc_error_handler_kind), diff --git a/src/base.rs b/src/base.rs index b117dc496c2b..c5b4277015a9 100644 --- a/src/base.rs +++ b/src/base.rs @@ -249,9 +249,7 @@ pub(crate) fn compile_fn( } // Define debuginfo for function - let isa = module.isa(); let debug_context = &mut cx.debug_context; - let unwind_context = &mut cx.unwind_context; cx.profiler.generic_activity("generate debug info").run(|| { if let Some(debug_context) = debug_context { codegened_func.func_debug_cx.unwrap().finalize( @@ -260,7 +258,6 @@ pub(crate) fn compile_fn( context, ); } - unwind_context.add_function(codegened_func.func_id, &context, isa); }); } @@ -909,7 +906,7 @@ fn codegen_stmt<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::AscribeUserType(..) => {} - StatementKind::Coverage { .. } => fx.tcx.dcx().fatal("-Zcoverage is unimplemented"), + StatementKind::Coverage { .. } => unreachable!(), StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic { // We ignore `assume` intrinsics, they are only useful for optimizations NonDivergingIntrinsic::Assume(_) => {} diff --git a/src/common.rs b/src/common.rs index 21d0cd2d30f2..093171399369 100644 --- a/src/common.rs +++ b/src/common.rs @@ -247,7 +247,6 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool { pub(crate) fn create_wrapper_function( module: &mut dyn Module, - unwind_context: &mut UnwindContext, sig: Signature, wrapper_name: &str, callee_name: &str, @@ -280,7 +279,6 @@ pub(crate) fn create_wrapper_function( bcx.finalize(); } module.define_function(wrapper_func_id, &mut ctx).unwrap(); - unwind_context.add_function(wrapper_func_id, &ctx, module.isa()); } pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { @@ -395,6 +393,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { // FIXME Don't force the size to a multiple of bytes once Cranelift gets // a way to specify stack slot alignment. size: (size + abi_align - 1) / abi_align * abi_align, + align_shift: 4, }); Pointer::stack_slot(stack_slot) } else { @@ -405,6 +404,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { // FIXME Don't force the size to a multiple of bytes once Cranelift gets // a way to specify stack slot alignment. size: (size + align) / abi_align * abi_align, + align_shift: 4, }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align)); diff --git a/src/driver/aot.rs b/src/driver/aot.rs index dcafac21bc74..763d9a484077 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -26,6 +26,7 @@ use rustc_session::Session; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; use crate::global_asm::GlobalAsmConfig; +use crate::unwind_module::UnwindModule; use crate::{prelude::*, BackendConfig}; struct ModuleCodegenResult { @@ -318,7 +319,11 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule { +fn make_module( + sess: &Session, + backend_config: &BackendConfig, + name: String, +) -> UnwindModule { let isa = crate::build_isa(sess, backend_config); let mut builder = @@ -327,16 +332,15 @@ fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections // can easily double the amount of time necessary to perform linking. builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) + UnwindModule::new(ObjectModule::new(builder), true) } fn emit_cgu( output_filenames: &OutputFilenames, prof: &SelfProfilerRef, name: String, - module: ObjectModule, + module: UnwindModule, debug: Option, - unwind_context: UnwindContext, global_asm_object_file: Option, producer: &str, ) -> Result { @@ -346,8 +350,6 @@ fn emit_cgu( debug.emit(&mut product); } - unwind_context.emit(&mut product); - let module_regular = emit_module( output_filenames, prof, @@ -494,7 +496,6 @@ fn module_codegen( let mut cx = crate::CodegenCx::new( tcx, - backend_config.clone(), module.isa(), tcx.sess.opts.debuginfo != DebugInfo::None, cgu_name, @@ -531,13 +532,7 @@ fn module_codegen( } } } - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut module, - &mut cx.unwind_context, - false, - cgu.is_primary(), - ); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, false, cgu.is_primary()); let cgu_name = cgu.name().as_str().to_owned(); @@ -571,7 +566,6 @@ fn module_codegen( cgu_name, module, cx.debug_context, - cx.unwind_context, global_asm_object_file, &producer, ) @@ -665,13 +659,10 @@ pub(crate) fn run_aot( }); let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string()); - let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); - let created_alloc_shim = - crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); + let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); let allocator_module = if created_alloc_shim { - let mut product = allocator_module.finish(); - allocator_unwind_context.emit(&mut product); + let product = allocator_module.finish(); match emit_module( tcx.output_filenames(()), diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 4b149131b61a..dfee8e714e64 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -14,12 +14,12 @@ use rustc_session::Session; use rustc_span::Symbol; use crate::debuginfo::TypeDebugContext; +use crate::unwind_module::UnwindModule; use crate::{prelude::*, BackendConfig}; use crate::{CodegenCx, CodegenMode}; struct JitState { - backend_config: BackendConfig, - jit_module: JITModule, + jit_module: UnwindModule, } thread_local! { @@ -63,7 +63,7 @@ fn create_jit_module( tcx: TyCtxt<'_>, backend_config: &BackendConfig, hotswap: bool, -) -> (JITModule, CodegenCx) { +) -> (UnwindModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); let isa = crate::build_isa(tcx.sess, backend_config); @@ -72,17 +72,11 @@ fn create_jit_module( crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); - let mut jit_module = JITModule::new(jit_builder); + let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); - let mut cx = crate::CodegenCx::new( - tcx, - backend_config.clone(), - jit_module.isa(), - false, - Symbol::intern("dummy_cgu_name"), - ); + let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, Symbol::intern("dummy_cgu_name")); - crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context); + crate::allocator::codegen(tcx, &mut jit_module); (jit_module, cx) } @@ -128,7 +122,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { ); } CodegenMode::JitLazy => { - codegen_shim(tcx, &mut cx, &mut cached_context, &mut jit_module, inst) + codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) } }, MonoItem::Static(def_id) => { @@ -146,18 +140,11 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { tcx.dcx().fatal("Inline asm is not supported in JIT mode"); } - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut jit_module, - &mut cx.unwind_context, - true, - true, - ); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, true, true); tcx.dcx().abort_if_errors(); - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; + jit_module.finalize_definitions(); println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" @@ -177,12 +164,12 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { call_conv: jit_module.target_config().default_call_conv, }; let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); - let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); + let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); LAZY_JIT_STATE.with(|lazy_jit_state| { let mut lazy_jit_state = lazy_jit_state.borrow_mut(); assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { backend_config, jit_module }); + *lazy_jit_state = Some(JitState { jit_module }); }); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = @@ -268,7 +255,6 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> let mut lazy_jit_state = lazy_jit_state.borrow_mut(); let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); let jit_module = &mut lazy_jit_state.jit_module; - let backend_config = lazy_jit_state.backend_config.clone(); let name = tcx.symbol_name(instance).name; let sig = crate::abi::get_function_sig( @@ -278,7 +264,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> ); let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); - let current_ptr = jit_module.read_got_entry(func_id); + let current_ptr = jit_module.module.read_got_entry(func_id); // If the function's GOT entry has already been updated to point at something other // than the shim trampoline, don't re-jit but just return the new pointer instead. @@ -288,11 +274,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> return current_ptr; } - jit_module.prepare_for_function_redefine(func_id).unwrap(); + jit_module.module.prepare_for_function_redefine(func_id).unwrap(); let mut cx = crate::CodegenCx::new( tcx, - backend_config, jit_module.isa(), false, Symbol::intern("dummy_cgu_name"), @@ -300,9 +285,8 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); assert!(cx.global_asm.is_empty()); - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; - jit_module.get_finalized_function(func_id) + jit_module.finalize_definitions(); + jit_module.module.get_finalized_function(func_id) }) }) } @@ -310,7 +294,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> fn dep_symbol_lookup_fn( sess: &Session, crate_info: CrateInfo, -) -> Box Option<*const u8>> { +) -> Box Option<*const u8> + Send> { use rustc_middle::middle::dependency_format::Linkage; let mut dylib_paths = Vec::new(); @@ -362,9 +346,8 @@ fn dep_symbol_lookup_fn( fn codegen_shim<'tcx>( tcx: TyCtxt<'tcx>, - cx: &mut CodegenCx, cached_context: &mut Context, - module: &mut JITModule, + module: &mut UnwindModule, inst: Instance<'tcx>, ) { let pointer_type = module.target_config().pointer_type(); @@ -413,5 +396,4 @@ fn codegen_shim<'tcx>( trampoline_builder.ins().return_(&ret_vals); module.define_function(func_id, context).unwrap(); - cx.unwind_context.add_function(func_id, context, module.isa()); } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index c6b26dd873bd..c88230c93605 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -113,13 +113,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( ); let sig = get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); - create_wrapper_function( - fx.module, - &mut fx.cx.unwind_context, - sig, - &wrapper_name, - symbol.name, - ); + create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); CInlineAsmOperand::Symbol { symbol: wrapper_name } } else { @@ -283,13 +277,7 @@ pub(crate) fn codegen_naked_asm<'tcx>( ); let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); - create_wrapper_function( - module, - &mut cx.unwind_context, - sig, - &wrapper_name, - symbol.name, - ); + create_wrapper_function(module, sig, &wrapper_name, symbol.name); CInlineAsmOperand::Symbol { symbol: wrapper_name } } else { diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index d454f3c1de7e..399518e58d8c 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -459,11 +459,20 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (a); intrinsic); let a = a.load_scalar(fx); + let value = fx.bcx.ins().x86_cvtt2dq(types::I32X4, a); + let cvalue = CValue::by_val(value, ret.layout()); + ret.write_cvalue(fx, cvalue); + } + "llvm.x86.sse2.cvtps2dq" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_epi32 + intrinsic_args!(fx, args => (a); intrinsic); + let a = a.load_scalar(fx); + // Using inline asm instead of fcvt_to_sint_sat as unrepresentable values are turned // into 0x80000000 for which Cranelift doesn't have a native instruction. codegen_inline_asm_inner( fx, - &[InlineAsmTemplatePiece::String(format!("cvttps2dq xmm0, xmm0"))], + &[InlineAsmTemplatePiece::String(format!("cvtps2dq xmm0, xmm0"))], &[CInlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), _late: true, @@ -1416,6 +1425,36 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.write_cvalue(fx, res); } + "llvm.x86.rdtsc" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_rdtsc&ig_expand=5273 + + let res_place = CPlace::new_stack_slot( + fx, + fx.layout_of(Ty::new_tup(fx.tcx, &[fx.tcx.types.u32, fx.tcx.types.u32])), + ); + let eax_place = res_place.place_field(fx, FieldIdx::new(0)); + let edx_place = res_place.place_field(fx, FieldIdx::new(1)); + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("rdtsc".to_string())], + &[ + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + late: true, + place: Some(eax_place), + }, + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + late: true, + place: Some(edx_place), + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::NOMEM, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + _ => { fx.tcx .dcx() diff --git a/src/lib.rs b/src/lib.rs index 06ca52b39032..192e6c91ea38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,7 @@ mod pretty_clif; mod toolchain; mod trap; mod unsize; +mod unwind_module; mod value_and_place; mod vtable; @@ -130,22 +131,13 @@ struct CodegenCx { global_asm: String, inline_asm_index: Cell, debug_context: Option, - unwind_context: UnwindContext, cgu_name: Symbol, } impl CodegenCx { - fn new( - tcx: TyCtxt<'_>, - backend_config: BackendConfig, - isa: &dyn TargetIsa, - debug_info: bool, - cgu_name: Symbol, - ) -> Self { + fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, debug_info: bool, cgu_name: Symbol) -> Self { assert_eq!(pointer_ty(tcx), isa.pointer_type()); - let unwind_context = - UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { Some(DebugContext::new(tcx, isa, cgu_name.as_str())) } else { @@ -158,7 +150,6 @@ impl CodegenCx { global_asm: String::new(), inline_asm_index: Cell::new(0), debug_context, - unwind_context, cgu_name, } } @@ -175,7 +166,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } fn init(&self, sess: &Session) { - use rustc_session::config::Lto; + use rustc_session::config::{InstrumentCoverage, Lto}; match sess.lto() { Lto::No | Lto::ThinLocal => {} Lto::Thin | Lto::Fat => { @@ -183,6 +174,11 @@ impl CodegenBackend for CraneliftCodegenBackend { } } + if sess.opts.cg.instrument_coverage() != InstrumentCoverage::No { + sess.dcx() + .fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift"); + } + let mut config = self.config.borrow_mut(); if config.is_none() { let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args) diff --git a/src/main_shim.rs b/src/main_shim.rs index f9a729618a51..33d3f9b8a90a 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -11,8 +11,7 @@ use crate::prelude::*; /// users main function. pub(crate) fn maybe_create_entry_wrapper( tcx: TyCtxt<'_>, - module: &mut impl Module, - unwind_context: &mut UnwindContext, + module: &mut dyn Module, is_jit: bool, is_primary_cgu: bool, ) { @@ -36,12 +35,11 @@ pub(crate) fn maybe_create_entry_wrapper( return; } - create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe); + create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe); fn create_entry_fn( tcx: TyCtxt<'_>, - m: &mut impl Module, - unwind_context: &mut UnwindContext, + m: &mut dyn Module, rust_main_def_id: DefId, ignore_lang_start_wrapper: bool, is_main_fn: bool, @@ -170,7 +168,5 @@ pub(crate) fn maybe_create_entry_wrapper( if let Err(err) = m.define_function(cmain_func_id, &mut ctx) { tcx.dcx().fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}")); } - - unwind_context.add_function(cmain_func_id, &ctx, m.isa()); } } diff --git a/src/unwind_module.rs b/src/unwind_module.rs new file mode 100644 index 000000000000..b950aaa29ce0 --- /dev/null +++ b/src/unwind_module.rs @@ -0,0 +1,115 @@ +use cranelift_codegen::control::ControlPlane; +use cranelift_codegen::ir::{Function, Signature}; +use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa}; +use cranelift_codegen::{Context, FinalizedMachReloc}; +use cranelift_module::{ + DataDescription, DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations, + ModuleResult, +}; +use cranelift_object::{ObjectModule, ObjectProduct}; + +use crate::UnwindContext; + +/// A wrapper around a [Module] which adds any defined function to the [UnwindContext]. +pub(crate) struct UnwindModule { + pub(crate) module: T, + unwind_context: UnwindContext, +} + +impl UnwindModule { + pub(crate) fn new(module: T, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(module.isa(), pic_eh_frame); + UnwindModule { module, unwind_context } + } +} + +impl UnwindModule { + pub(crate) fn finish(self) -> ObjectProduct { + let mut product = self.module.finish(); + self.unwind_context.emit(&mut product); + product + } +} + +#[cfg(feature = "jit")] +impl UnwindModule { + pub(crate) fn finalize_definitions(&mut self) { + self.module.finalize_definitions().unwrap(); + let prev_unwind_context = std::mem::replace( + &mut self.unwind_context, + UnwindContext::new(self.module.isa(), false), + ); + unsafe { prev_unwind_context.register_jit(&self.module) }; + } +} + +impl Module for UnwindModule { + fn isa(&self) -> &dyn TargetIsa { + self.module.isa() + } + + fn declarations(&self) -> &ModuleDeclarations { + self.module.declarations() + } + + fn get_name(&self, name: &str) -> Option { + self.module.get_name(name) + } + + fn target_config(&self) -> TargetFrontendConfig { + self.module.target_config() + } + + fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &Signature, + ) -> ModuleResult { + self.module.declare_function(name, linkage, signature) + } + + fn declare_anonymous_function(&mut self, signature: &Signature) -> ModuleResult { + self.module.declare_anonymous_function(signature) + } + + fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult { + self.module.declare_data(name, linkage, writable, tls) + } + + fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult { + self.module.declare_anonymous_data(writable, tls) + } + + fn define_function_with_control_plane( + &mut self, + func: FuncId, + ctx: &mut Context, + ctrl_plane: &mut ControlPlane, + ) -> ModuleResult<()> { + self.module.define_function_with_control_plane(func, ctx, ctrl_plane)?; + self.unwind_context.add_function(func, ctx, self.module.isa()); + Ok(()) + } + + fn define_function_bytes( + &mut self, + _func_id: FuncId, + _func: &Function, + _alignment: u64, + _bytes: &[u8], + _relocs: &[FinalizedMachReloc], + ) -> ModuleResult<()> { + unimplemented!() + } + + fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> { + self.module.define_data(data_id, data) + } +} From 7a1601553dde7d74f7aefc509486d4ae564de662 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 11:54:45 +0000 Subject: [PATCH 045/361] Mark .debug_str as mergeable strings Fixes rust-lang/rustc_codegen_cranelift#1496 --- src/debuginfo/object.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/debuginfo/object.rs b/src/debuginfo/object.rs index 65f4c67b21f1..7c873515a8f2 100644 --- a/src/debuginfo/object.rs +++ b/src/debuginfo/object.rs @@ -39,7 +39,13 @@ impl WriteDebugInfo for ObjectProduct { let section_id = self.object.add_section( segment, name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, + if id == SectionId::DebugStr { + SectionKind::DebugString + } else if id == SectionId::EhFrame { + SectionKind::ReadOnlyData + } else { + SectionKind::Debug + }, ); self.object .section_mut(section_id) From eb1b24a97a5794fe62e83964700ec233b8dd5f32 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 30 Jun 2024 23:56:39 +0200 Subject: [PATCH 046/361] `manual_inspect`: fix `clippy::version` from 1.78.0 to 1.81.0 Although `manual_inspect`'s PR started some months ago, the lint is only available in the current nightly (1.81.0), rather than 1.78.0. Signed-off-by: Miguel Ojeda --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1408f4548200..c5d44e620f28 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4121,7 +4121,7 @@ declare_clippy_lint! { /// ```no_run /// let x = Some(0).inspect(|x| println!("{x}")); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub MANUAL_INSPECT, complexity, "use of `map` returning the original item" From 126fd7c31d1b7fdeeb486f4ad3d68489a8b13922 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Jul 2024 08:18:34 +0000 Subject: [PATCH 047/361] Also mark .debug_line_str as mergeable strings --- src/debuginfo/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debuginfo/object.rs b/src/debuginfo/object.rs index 7c873515a8f2..1c6e471cc870 100644 --- a/src/debuginfo/object.rs +++ b/src/debuginfo/object.rs @@ -39,7 +39,7 @@ impl WriteDebugInfo for ObjectProduct { let section_id = self.object.add_section( segment, name, - if id == SectionId::DebugStr { + if id == SectionId::DebugStr || id == SectionId::DebugLineStr { SectionKind::DebugString } else if id == SectionId::EhFrame { SectionKind::ReadOnlyData From 0dddf6e0e8af27d363a6e69e67cfbe1d1ae294d8 Mon Sep 17 00:00:00 2001 From: asemia Date: Mon, 1 Jul 2024 14:09:15 +0500 Subject: [PATCH 048/361] Fix doc for verbose_bit_mask --- clippy_lints/src/operators/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 48a442705b29..202ee61506c0 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -242,6 +242,13 @@ declare_clippy_lint! { /// # let x = 1; /// if (x | 1 > 3) { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x = 1; + /// if (x >= 2) { } + /// ``` #[clippy::version = "pre 1.29.0"] pub INEFFECTIVE_BIT_MASK, correctness, @@ -265,6 +272,13 @@ declare_clippy_lint! { /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x: i32 = 1; + /// if x.trailing_zeros() > 4 { } + /// ``` #[clippy::version = "pre 1.29.0"] pub VERBOSE_BIT_MASK, pedantic, From 5cbf6d5da8774de9136168b57b55fbc0a6ca9fbf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 11:25:12 -0700 Subject: [PATCH 049/361] clippy: update to pulldown-cmark 0.11 --- clippy_lints/src/doc/mod.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 3d875e7ac2d3..3e210fd153bf 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -6,10 +6,10 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ - Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, + Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; -use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; +use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_hir::intravisit::{self, Visitor}; @@ -659,7 +659,7 @@ fn check_doc<'a, Events: Iterator, Range { + Html(tag) | InlineHtml(tag) => { if tag.starts_with(", Range { + Start(BlockQuote(_)) => { blockquote_level += 1; containers.push(Container::Blockquote); }, - End(BlockQuote) => { + End(TagEnd::BlockQuote) => { blockquote_level -= 1; containers.pop(); }, @@ -699,15 +699,15 @@ fn check_doc<'a, Events: Iterator, Range { + End(TagEnd::CodeBlock) => { in_code = false; is_rust = false; ignore = false; }, - Start(Link(_, url, _)) => in_link = Some(url), - End(Link(..)) => in_link = None, - Start(Heading(_, _, _) | Paragraph | Item) => { - if let Start(Heading(_, _, _)) = event { + Start(Link { dest_url, .. }) => in_link = Some(dest_url), + End(TagEnd::Link) => in_link = None, + Start(Heading { .. } | Paragraph | Item) => { + if let Start(Heading { .. }) = event { in_heading = true; } if let Start(Item) = event { @@ -720,11 +720,11 @@ fn check_doc<'a, Events: Iterator, Range { - if let End(Heading(_, _, _)) = event { + End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => { + if let End(TagEnd::Heading(_)) = event { in_heading = false; } - if let End(Item) = event { + if let End(TagEnd::Item) = event { containers.pop(); } if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { @@ -746,8 +746,8 @@ fn check_doc<'a, Events: Iterator, Range in_footnote_definition = true, - End(FootnoteDefinition(..)) => in_footnote_definition = false, - Start(_tag) | End(_tag) => (), // We don't care about other tags + End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, + Start(_) | End(_) => (), // We don't care about other tags SoftBreak | HardBreak => { if !containers.is_empty() && let Some((next_event, next_range)) = events.peek() @@ -765,7 +765,7 @@ fn check_doc<'a, Events: Iterator, Range (), + TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; ticks_unbalanced |= text.contains('`') && !in_code; From 76a068be6da0878393473e4929e5a2cab8af0d0b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 1 Jul 2024 22:45:56 +0700 Subject: [PATCH 050/361] Skip installing rust-docs with minimal rustup profile --- rust-toolchain | 1 + 1 file changed, 1 insertion(+) diff --git a/rust-toolchain b/rust-toolchain index 72b50d59f7e9..52e8831eeb3a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,4 @@ [toolchain] channel = "nightly-2024-06-27" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] +profile = "minimal" From f35bd40d18c39c58fbc9985d42ea601886a6bc63 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:07:22 +0000 Subject: [PATCH 051/361] Remove unused generic_args arguments from intrinsic codegen functions --- src/abi/mod.rs | 1 - src/intrinsics/llvm.rs | 20 ++------------------ src/intrinsics/llvm_aarch64.rs | 1 - src/intrinsics/llvm_x86.rs | 1 - 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 0d7eee7afb41..cad6aa1a943a 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -390,7 +390,6 @@ pub(crate) fn codegen_terminator_call<'tcx>( crate::intrinsics::codegen_llvm_intrinsic_call( fx, &fx.tcx.symbol_name(instance).name, - fn_args, args, ret_place, target, diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index e50c74b87f60..720a0d8fbf59 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -6,32 +6,16 @@ use crate::prelude::*; pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - generic_args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, span: Span, ) { if intrinsic.starts_with("llvm.aarch64") { - return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call( - fx, - intrinsic, - generic_args, - args, - ret, - target, - ); + return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(fx, intrinsic, args, ret, target); } if intrinsic.starts_with("llvm.x86") { - return llvm_x86::codegen_x86_llvm_intrinsic_call( - fx, - intrinsic, - generic_args, - args, - ret, - target, - span, - ); + return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, args, ret, target, span); } match intrinsic { diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index e66bcbf4e40e..f0fb18608e07 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -6,7 +6,6 @@ use crate::prelude::*; pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - _args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 399518e58d8c..e1896138e487 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -10,7 +10,6 @@ use crate::prelude::*; pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - _args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, From 0f643c449aea5060de03a0b8fe8288cd1c861e0d Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 27 Jun 2024 22:18:04 +0100 Subject: [PATCH 052/361] Ensure tests don't fail on i586 in CI --- tests/assembly/x86-return-float.rs | 5 ++ .../ui/abi/numbers-arithmetic/return-float.rs | 90 ++++++++++--------- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs index 270aea2475f0..c4a2c1ad44ec 100644 --- a/tests/assembly/x86-return-float.rs +++ b/tests/assembly/x86-return-float.rs @@ -1,5 +1,10 @@ //@ assembly-output: emit-asm //@ only-x86 +// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled. +// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable +// SSE2. +// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order. +//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4 // Force frame pointers to make ASM more consistent between targets //@ compile-flags: -O -C force-frame-pointers //@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst diff --git a/tests/ui/abi/numbers-arithmetic/return-float.rs b/tests/ui/abi/numbers-arithmetic/return-float.rs index 3b025b763f13..66a6d66911d3 100644 --- a/tests/ui/abi/numbers-arithmetic/return-float.rs +++ b/tests/ui/abi/numbers-arithmetic/return-float.rs @@ -4,50 +4,54 @@ // Test that floats (in particular signalling NaNs) are losslessly returned from functions. fn main() { - let bits_f32 = std::hint::black_box([ - 4.2_f32.to_bits(), - f32::INFINITY.to_bits(), - f32::NEG_INFINITY.to_bits(), - f32::NAN.to_bits(), - // These two masks cover all the mantissa bits. One of them is a signalling NaN, the other - // is quiet. - // Similar to the masks in `test_float_bits_conv` in library/std/src/f32/tests.rs - f32::NAN.to_bits() ^ 0x002A_AAAA, - f32::NAN.to_bits() ^ 0x0055_5555, - // Same as above but with the sign bit flipped. - f32::NAN.to_bits() ^ 0x802A_AAAA, - f32::NAN.to_bits() ^ 0x8055_5555, - ]); - for bits in bits_f32 { - assert_eq!(identity(f32::from_bits(bits)).to_bits(), bits); - // Test types that are returned as scalar pairs. - assert_eq!(identity((f32::from_bits(bits), 42)).0.to_bits(), bits); - assert_eq!(identity((42, f32::from_bits(bits))).1.to_bits(), bits); - let (a, b) = identity((f32::from_bits(bits), f32::from_bits(bits))); - assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); - } + // FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled on + // x86. + if cfg!(not(all(target_arch = "x86", not(target_feature = "sse2")))) { + let bits_f32 = std::hint::black_box([ + 4.2_f32.to_bits(), + f32::INFINITY.to_bits(), + f32::NEG_INFINITY.to_bits(), + f32::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the + // other is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f32/tests.rs + f32::NAN.to_bits() ^ 0x002A_AAAA, + f32::NAN.to_bits() ^ 0x0055_5555, + // Same as above but with the sign bit flipped. + f32::NAN.to_bits() ^ 0x802A_AAAA, + f32::NAN.to_bits() ^ 0x8055_5555, + ]); + for bits in bits_f32 { + assert_eq!(identity(f32::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f32::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f32::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f32::from_bits(bits), f32::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } - let bits_f64 = std::hint::black_box([ - 4.2_f64.to_bits(), - f64::INFINITY.to_bits(), - f64::NEG_INFINITY.to_bits(), - f64::NAN.to_bits(), - // These two masks cover all the mantissa bits. One of them is a signalling NaN, the other - // is quiet. - // Similar to the masks in `test_float_bits_conv` in library/std/src/f64/tests.rs - f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA, - f64::NAN.to_bits() ^ 0x0005_5555_5555_5555, - // Same as above but with the sign bit flipped. - f64::NAN.to_bits() ^ 0x800A_AAAA_AAAA_AAAA, - f64::NAN.to_bits() ^ 0x8005_5555_5555_5555, - ]); - for bits in bits_f64 { - assert_eq!(identity(f64::from_bits(bits)).to_bits(), bits); - // Test types that are returned as scalar pairs. - assert_eq!(identity((f64::from_bits(bits), 42)).0.to_bits(), bits); - assert_eq!(identity((42, f64::from_bits(bits))).1.to_bits(), bits); - let (a, b) = identity((f64::from_bits(bits), f64::from_bits(bits))); - assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + let bits_f64 = std::hint::black_box([ + 4.2_f64.to_bits(), + f64::INFINITY.to_bits(), + f64::NEG_INFINITY.to_bits(), + f64::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the + // other is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f64/tests.rs + f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x0005_5555_5555_5555, + // Same as above but with the sign bit flipped. + f64::NAN.to_bits() ^ 0x800A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x8005_5555_5555_5555, + ]); + for bits in bits_f64 { + assert_eq!(identity(f64::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f64::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f64::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f64::from_bits(bits), f64::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } } } From 567bea29b14e0365bddbd8b5f0ee9f49c8ea7e72 Mon Sep 17 00:00:00 2001 From: Astra Tsai Date: Mon, 1 Jul 2024 18:57:24 -0700 Subject: [PATCH 053/361] Fix `into_iter_without_iter` false positive when the implementation is not within the first `impl` block --- clippy_utils/src/ty.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e5d205641968..b0c842f98502 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1336,15 +1336,13 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n .inherent_impls(ty_did) .into_iter() .flatten() - .map(|&did| { + .find_map(|&did| { cx.tcx .associated_items(did) .filter_by_name_unhygienic(method_name) .next() .filter(|item| item.kind == AssocKind::Fn) }) - .next() - .flatten() } else { None } From ba05b764bcb776c0c732d058e0a0d1ac99c5facb Mon Sep 17 00:00:00 2001 From: Astra Tsai Date: Mon, 1 Jul 2024 19:00:10 -0700 Subject: [PATCH 054/361] Add regression test for #12964 --- tests/ui/into_iter_without_iter.rs | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs index c8b9076041a3..109259d6975c 100644 --- a/tests/ui/into_iter_without_iter.rs +++ b/tests/ui/into_iter_without_iter.rs @@ -185,3 +185,42 @@ pub mod issue11635 { } } } + +pub mod issue12964 { + pub struct MyIter<'a, T: 'a> { + iter: std::slice::Iter<'a, T>, + } + + impl<'a, T> Iterator for MyIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + } + + pub struct MyContainer { + inner: Vec, + } + + impl MyContainer {} + + impl MyContainer { + #[must_use] + pub fn iter(&self) -> MyIter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + } + + impl<'a, T> IntoIterator for &'a MyContainer { + type Item = &'a T; + + type IntoIter = MyIter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter { + iter: self.inner.as_slice().iter(), + } + } + } +} From 0dd8b27b6b44533357848276e190f684cb36b797 Mon Sep 17 00:00:00 2001 From: Astra Tsai Date: Mon, 1 Jul 2024 19:10:10 -0700 Subject: [PATCH 055/361] Fix formatting --- clippy_utils/src/ty.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index b0c842f98502..ab9f6433e187 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1332,17 +1332,13 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { - cx.tcx - .inherent_impls(ty_did) - .into_iter() - .flatten() - .find_map(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .filter(|item| item.kind == AssocKind::Fn) - }) + cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .filter(|item| item.kind == AssocKind::Fn) + }) } else { None } From f715bfc344502d0983d351c2cbdfea5373bd6c50 Mon Sep 17 00:00:00 2001 From: hattizai Date: Tue, 2 Jul 2024 11:25:31 +0800 Subject: [PATCH 056/361] chore: remove duplicate words --- clippy_lints/src/empty_with_brackets.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index 745599b0e57a..743ec5b9ea7f 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// and it may be desirable to do so consistently for style. /// /// However, removing the brackets also introduces a public constant named after the struct, - /// so this is not just a syntactic simplification but an an API change, and adding them back + /// so this is not just a syntactic simplification but an API change, and adding them back /// is a *breaking* API change. /// /// ### Example @@ -44,7 +44,7 @@ declare_clippy_lint! { /// and it may be desirable to do so consistently for style. /// /// However, removing the brackets also introduces a public constant named after the variant, - /// so this is not just a syntactic simplification but an an API change, and adding them back + /// so this is not just a syntactic simplification but an API change, and adding them back /// is a *breaking* API change. /// /// ### Example diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5cb8e7bfab2a..964d199bfcb6 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -258,7 +258,7 @@ impl<'tcx> NonCopyConst<'tcx> { // e.g. implementing `has_frozen_variant` described above, and not running this function // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with the a frozen variant) (e.g. borrowing + // similar to 2., but with a frozen variant) (e.g. borrowing // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). matches!(err, ErrorHandled::TooGeneric(..)) From 2da0edbdf10799f3245b08a2c7b41f3bf7890f6d Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Mon, 9 Oct 2023 11:48:13 +0200 Subject: [PATCH 057/361] Honor avoid-breaking-exported-api in needless_pass_by_ref_mut Until now, the lint only emitted a warning, when breaking public API. Now it doesn't lint at all when the config value is not set to `false`, bringing it in line with the other lints using this config value. Also ensures that this config value is documented in the lint. --- clippy_config/src/conf.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 10 ++-- .../needless_pass_by_ref_mut/clippy.toml | 1 + .../needless_pass_by_ref_mut.fixed | 10 ++++ .../needless_pass_by_ref_mut.rs | 10 ++++ .../needless_pass_by_ref_mut.stderr | 12 +++++ tests/ui/needless_pass_by_ref_mut.rs | 18 ++++--- tests/ui/needless_pass_by_ref_mut.stderr | 52 ++++++++----------- tests/ui/needless_pass_by_ref_mut2.fixed | 4 +- tests/ui/needless_pass_by_ref_mut2.rs | 4 +- tests/ui/needless_pass_by_ref_mut2.stderr | 15 +++--- 11 files changed, 85 insertions(+), 53 deletions(-) create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/clippy.toml create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 9cc119c68cb1..7f53aad67933 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -263,7 +263,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 57ba0da53319..13774987b8ec 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Check if a `&mut` function argument is actually used mutably. /// /// Be careful if the function is publicly reexported as it would break compatibility with - /// users of this function. + /// users of this function, when the users pass this function as an argument. /// /// ### Why is this bad? /// Less `mut` means less fights with the borrow checker. It can also lead to more @@ -262,8 +262,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { .iter() .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id)) { - let show_semver_warning = - self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id); + let is_exported = cx.effective_visibilities.is_exported(*fn_def_id); + if self.avoid_breaking_exported_api && is_exported { + continue; + } let mut is_cfged = None; for input in unused { @@ -284,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),), Applicability::Unspecified, ); - if show_semver_warning { + if is_exported { diag.warn("changing this function will impact semver compatibility"); } if *is_cfged { diff --git a/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml b/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml new file mode 100644 index 000000000000..cda8d17eed44 --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed new file mode 100644 index 000000000000..40556ca5410f --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs new file mode 100644 index 000000000000..bbc63ceb15a3 --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr new file mode 100644 index 000000000000..c10607bf4bab --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr @@ -0,0 +1,12 @@ +error: this argument is a mutable reference, but not used mutably + --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19 + | +LL | pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | + = warning: changing this function will impact semver compatibility + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index eee62122fdfd..162ec82aeded 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec) { } fn non_mut(n: &str) {} //Should warn -pub async fn call_in_closure1(n: &mut str) { +async fn call_in_closure1(n: &mut str) { (|| non_mut(n))() } fn str_mut(str: &mut String) -> bool { str.pop().is_some() } //Should not warn -pub async fn call_in_closure2(str: &mut String) { +async fn call_in_closure2(str: &mut String) { (|| str_mut(str))(); } // Should not warn. -pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { +async fn closure(n: &mut usize) -> impl '_ + FnMut() { || { *n += 1; } } // Should warn. -pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { +fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { //~^ ERROR: this argument is a mutable reference, but not used mutably || *n + 1 } // Should not warn. -pub async fn closure3(n: &mut usize) { +async fn closure3(n: &mut usize) { (|| *n += 1)(); } // Should warn. -pub async fn closure4(n: &mut usize) { +async fn closure4(n: &mut usize) { //~^ ERROR: this argument is a mutable reference, but not used mutably (|| { let _x = *n + 1; })(); } +// Should not warn: pub +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + *x += *b + s.len() as u32; +} + // Should not warn. async fn _f(v: &mut Vec<()>) { let x = || v.pop(); @@ -365,4 +370,5 @@ fn main() { used_as_path; let _: fn(&mut u32) = passed_as_local; let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 }; + pub_foo(&mut v, &0, &mut u); } diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 51e3ba37dede..f462fa9099ed 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -108,109 +108,103 @@ 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:235:34 + --> tests/ui/needless_pass_by_ref_mut.rs:235:30 | -LL | pub async fn call_in_closure1(n: &mut str) { - | ^^^^^^^^ help: consider changing to: `&str` - | - = warning: changing this function will impact semver compatibility +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:254:20 + --> tests/ui/needless_pass_by_ref_mut.rs:254:16 | -LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +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:265:26 + --> tests/ui/needless_pass_by_ref_mut.rs:265:22 | -LL | pub async fn closure4(n: &mut usize) { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +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:314:12 + --> tests/ui/needless_pass_by_ref_mut.rs:319: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:316:18 + --> tests/ui/needless_pass_by_ref_mut.rs:321: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:316:45 + --> tests/ui/needless_pass_by_ref_mut.rs:321: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:324:46 + --> tests/ui/needless_pass_by_ref_mut.rs:329: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:340:18 + --> tests/ui/needless_pass_by_ref_mut.rs:345: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:341:19 + --> tests/ui/needless_pass_by_ref_mut.rs:346: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:342:18 + --> tests/ui/needless_pass_by_ref_mut.rs:347: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:343:11 + --> tests/ui/needless_pass_by_ref_mut.rs:348: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:345:23 + --> tests/ui/needless_pass_by_ref_mut.rs:350: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:346:20 + --> tests/ui/needless_pass_by_ref_mut.rs:351: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:347:18 + --> tests/ui/needless_pass_by_ref_mut.rs:352: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:348:25 + --> tests/ui/needless_pass_by_ref_mut.rs:353: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:349:20 + --> tests/ui/needless_pass_by_ref_mut.rs:354: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:350:20 + --> tests/ui/needless_pass_by_ref_mut.rs:355: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_mut2.fixed b/tests/ui/needless_pass_by_ref_mut2.fixed index 3c2576213cd7..f26b39ea6a16 100644 --- a/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/tests/ui/needless_pass_by_ref_mut2.fixed @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &i32, y: &mut u32) { +async fn inner_async3(x: &i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &u32) { +async fn inner_async4(u: &mut i32, v: &u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/tests/ui/needless_pass_by_ref_mut2.rs b/tests/ui/needless_pass_by_ref_mut2.rs index 34b0b564deb8..4220215b1fe9 100644 --- a/tests/ui/needless_pass_by_ref_mut2.rs +++ b/tests/ui/needless_pass_by_ref_mut2.rs @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &mut i32, y: &mut u32) { +async fn inner_async3(x: &mut i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &mut i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &mut u32) { +async fn inner_async4(u: &mut i32, v: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/tests/ui/needless_pass_by_ref_mut2.stderr b/tests/ui/needless_pass_by_ref_mut2.stderr index c87536032256..1c0136cf5d59 100644 --- a/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/tests/ui/needless_pass_by_ref_mut2.stderr @@ -1,20 +1,17 @@ error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:8:30 + --> tests/ui/needless_pass_by_ref_mut2.rs:8:26 | -LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` +LL | async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` | - = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = 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_mut2.rs:16:43 + --> tests/ui/needless_pass_by_ref_mut2.rs:16:39 | -LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` - | - = warning: changing this function will impact semver compatibility +LL | async fn inner_async4(u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` error: aborting due to 2 previous errors From 125c778d6d01824fde3fe96f765a4dd9341af036 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 2 Jul 2024 19:30:30 +0200 Subject: [PATCH 058/361] Move exported check to check_fn to exit early --- clippy_lints/src/needless_pass_by_ref_mut.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 13774987b8ec..5ffd41d78e0c 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { return; } + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { @@ -262,11 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { .iter() .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id)) { - let is_exported = cx.effective_visibilities.is_exported(*fn_def_id); - if self.avoid_breaking_exported_api && is_exported { - continue; - } - let mut is_cfged = None; for input in unused { // If the argument is never used mutably, we emit the warning. @@ -286,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),), Applicability::Unspecified, ); - if is_exported { + if cx.effective_visibilities.is_exported(*fn_def_id) { diag.warn("changing this function will impact semver compatibility"); } if *is_cfged { From a6056bce92a8983f2bd3a8c9d03914bd4fb93c5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2024 21:05:22 +0200 Subject: [PATCH 059/361] Miri function identity hack: account for possible inlining --- src/constant.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/constant.rs b/src/constant.rs index 87c5da3b7c3e..9f7b95261d52 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -155,7 +155,7 @@ pub(crate) fn codegen_const_value<'tcx>( fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } } - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); @@ -351,7 +351,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant TodoItem::Alloc(alloc_id) => { let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { + GlobalAlloc::Function { .. } + | GlobalAlloc::Static(_) + | GlobalAlloc::VTable(..) => { unreachable!() } }; @@ -415,7 +417,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let reloc_target_alloc = tcx.global_alloc(alloc_id); let data_id = match reloc_target_alloc { - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { assert_eq!(addend, 0); let func_id = crate::abi::import_function(tcx, module, instance.polymorphize(tcx)); From e4bde05ed6e4028e936ac223e0322ff66020ad9f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 13:06:23 -0400 Subject: [PATCH 060/361] Give Instance::expect_resolve a span --- src/abi/mod.rs | 11 ++++++++--- src/main_shim.rs | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 0d7eee7afb41..81dfde81e938 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -371,9 +371,14 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Handle special calls like intrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { - let instance = - ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args) - .polymorphize(fx.tcx); + let instance = ty::Instance::expect_resolve( + fx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + fn_args, + Some(source_info.span), + ) + .polymorphize(fx.tcx); if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { diff --git a/src/main_shim.rs b/src/main_shim.rs index 33d3f9b8a90a..d1dc147dba8f 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -119,6 +119,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), + None, ) .polymorphize(tcx); @@ -144,6 +145,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), + None, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); From c6b883bb2eefd5377f2d75be95d8f20e271924ca Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 1 Jul 2024 16:32:32 -0400 Subject: [PATCH 061/361] Fix spans --- src/abi/mod.rs | 2 +- src/main_shim.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 81dfde81e938..9dc94ab33ea9 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( ty::ParamEnv::reveal_all(), def_id, fn_args, - Some(source_info.span), + source_info.span, ) .polymorphize(fx.tcx); diff --git a/src/main_shim.rs b/src/main_shim.rs index d1dc147dba8f..fe0a15514190 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::AssocKind; use rustc_middle::ty::GenericArg; use rustc_session::config::{sigpipe, EntryFnType}; use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; use crate::prelude::*; @@ -119,7 +120,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), - None, + DUMMY_SP, ) .polymorphize(tcx); @@ -145,7 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); From 70c8579e210d2fc8dae3bd0ae14c2210326eab5f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 28 Jun 2024 11:00:42 -0700 Subject: [PATCH 062/361] doc_markdown: detect escaped `` ` `` when checking unmatched Add explanatory comment to complex bounds check Format --- clippy_lints/src/doc/mod.rs | 13 ++++++++++++- tests/ui/doc/unbalanced_ticks.rs | 17 +++++++++++++++++ tests/ui/doc/unbalanced_ticks.stderr | 18 +++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 5faa00b7c971..357ed08c7c71 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -769,7 +769,18 @@ fn check_doc<'a, Events: Iterator, Range (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; - ticks_unbalanced |= text.contains('`') && !in_code; + let range_ = range.clone(); + ticks_unbalanced |= text.contains('`') + && !in_code + && doc[range.clone()].bytes().enumerate().any(|(i, c)| { + // scan the markdown source code bytes for backquotes that aren't preceded by backslashes + // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii) + // - relevant backquotes are within doc[range], but backslashes are not, because they're not + // actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes) + // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in + // usize, that would underflow and maybe panic + c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\')) + }); if Some(&text) == in_link.as_ref() || ticks_unbalanced { // Probably a link of the form `` // Which are represented as a link to "http://example.com" with diff --git a/tests/ui/doc/unbalanced_ticks.rs b/tests/ui/doc/unbalanced_ticks.rs index 6f7bab72040c..04446787b6c2 100644 --- a/tests/ui/doc/unbalanced_ticks.rs +++ b/tests/ui/doc/unbalanced_ticks.rs @@ -49,3 +49,20 @@ fn other_markdown() {} /// pub struct Struct; /// ``` fn issue_7421() {} + +/// ` +//~^ ERROR: backticks are unbalanced +fn escape_0() {} + +/// Escaped \` backticks don't count. +fn escape_1() {} + +/// Escaped \` \` backticks don't count. +fn escape_2() {} + +/// Escaped \` ` backticks don't count, but unescaped backticks do. +//~^ ERROR: backticks are unbalanced +fn escape_3() {} + +/// Backslashes ` \` within code blocks don't count. +fn escape_4() {} diff --git a/tests/ui/doc/unbalanced_ticks.stderr b/tests/ui/doc/unbalanced_ticks.stderr index 56ef29136231..50324010e97f 100644 --- a/tests/ui/doc/unbalanced_ticks.stderr +++ b/tests/ui/doc/unbalanced_ticks.stderr @@ -78,5 +78,21 @@ help: try LL | /// - This item needs `backticks_here` | ~~~~~~~~~~~~~~~~ -error: aborting due to 8 previous errors +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:53:5 + | +LL | /// ` + | ^ + | + = help: a backtick may be missing a pair + +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:63:5 + | +LL | /// Escaped \` ` backticks don't count, but unescaped backticks do. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: a backtick may be missing a pair + +error: aborting due to 10 previous errors From cd6023180f131134440fdb2b265c496581d67895 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Jul 2024 15:55:17 -0400 Subject: [PATCH 063/361] Instance::resolve -> Instance::try_resolve, and other nits --- clippy_lints/src/assigning_clones.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 05ea74b0d534..406f38f411ec 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -103,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< let args = cx.typeck_results().node_args(expr.hir_id); // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else { + let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else { return None; }; if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { @@ -119,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< // If we could not resolve the method, don't apply the lint let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args), + ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args), _ => Ok(None), }) else { return None; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5cb8e7bfab2a..b71ebe35eb6a 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> { ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, From ae47b97655d48e7d57f5442b1dfde067b488d4fb Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 3 Jul 2024 09:52:56 +0200 Subject: [PATCH 064/361] needless-pass-by-ref-mut: Update conf documentation --- book/src/lint_configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 4fc109c7851f..ad29339a84ad 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -348,6 +348,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut) * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) From 3b14526cead4105f82c398d8d4c7954efa3bab6b Mon Sep 17 00:00:00 2001 From: Harry Moulton Date: Tue, 4 Jun 2024 11:06:25 +0100 Subject: [PATCH 065/361] Fill out target-spec metadata for all targets Complete the metadata fields for all targets. Cargo will depend on this for checking whether a given target supports building the standard library. --- .../src/spec/targets/aarch64_apple_darwin.rs | 8 ++++---- .../rustc_target/src/spec/targets/aarch64_apple_ios.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_ios_macabi.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_ios_sim.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_tvos.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_tvos_sim.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_watchos.rs | 8 ++++---- .../src/spec/targets/aarch64_apple_watchos_sim.rs | 8 ++++---- .../src/spec/targets/aarch64_be_unknown_linux_gnu.rs | 8 ++++---- .../spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs | 8 ++++---- .../src/spec/targets/aarch64_be_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/aarch64_kmc_solid_asp3.rs | 8 ++++---- .../src/spec/targets/aarch64_linux_android.rs | 8 ++++---- .../targets/aarch64_nintendo_switch_freestanding.rs | 8 ++++---- .../src/spec/targets/aarch64_pc_windows_gnullvm.rs | 8 ++++---- .../src/spec/targets/aarch64_pc_windows_msvc.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_fuchsia.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_hermit.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_illumos.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_linux_gnu.rs | 8 ++++---- .../spec/targets/aarch64_unknown_linux_gnu_ilp32.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_linux_ohos.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_none.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_none_softfloat.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_nto_qnx710.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_openbsd.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_redox.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_teeos.rs | 8 ++++---- .../src/spec/targets/aarch64_unknown_uefi.rs | 8 ++++---- .../src/spec/targets/aarch64_uwp_windows_msvc.rs | 6 +++--- .../src/spec/targets/aarch64_wrs_vxworks.rs | 6 +++--- .../src/spec/targets/arm64_32_apple_watchos.rs | 8 ++++---- .../src/spec/targets/arm64e_apple_darwin.rs | 8 ++++---- .../rustc_target/src/spec/targets/arm64e_apple_ios.rs | 8 ++++---- .../src/spec/targets/arm64ec_pc_windows_msvc.rs | 8 ++++---- .../src/spec/targets/arm_linux_androideabi.rs | 8 ++++---- .../src/spec/targets/arm_unknown_linux_gnueabi.rs | 8 ++++---- .../src/spec/targets/arm_unknown_linux_gnueabihf.rs | 8 ++++---- .../src/spec/targets/arm_unknown_linux_musleabi.rs | 8 ++++---- .../src/spec/targets/arm_unknown_linux_musleabihf.rs | 8 ++++---- .../src/spec/targets/armeb_unknown_linux_gnueabi.rs | 8 ++++---- .../src/spec/targets/armebv7r_none_eabi.rs | 8 ++++---- .../src/spec/targets/armebv7r_none_eabihf.rs | 8 ++++---- .../rustc_target/src/spec/targets/armv4t_none_eabi.rs | 8 ++++---- .../src/spec/targets/armv4t_unknown_linux_gnueabi.rs | 8 ++++---- .../rustc_target/src/spec/targets/armv5te_none_eabi.rs | 8 ++++---- .../src/spec/targets/armv5te_unknown_linux_gnueabi.rs | 8 ++++---- .../src/spec/targets/armv5te_unknown_linux_musleabi.rs | 8 ++++---- .../spec/targets/armv5te_unknown_linux_uclibceabi.rs | 8 ++++---- .../src/spec/targets/armv6_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/armv6_unknown_netbsd_eabihf.rs | 8 ++++---- .../src/spec/targets/armv6k_nintendo_3ds.rs | 8 ++++---- .../src/spec/targets/armv7_linux_androideabi.rs | 8 ++++---- .../src/spec/targets/armv7_sony_vita_newlibeabihf.rs | 10 ++++++---- .../src/spec/targets/armv7_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_gnueabi.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_gnueabihf.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_musleabi.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_musleabihf.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_ohos.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_linux_uclibceabi.rs | 8 ++++---- .../spec/targets/armv7_unknown_linux_uclibceabihf.rs | 8 ++++---- .../src/spec/targets/armv7_unknown_netbsd_eabihf.rs | 8 ++++---- .../src/spec/targets/armv7_wrs_vxworks_eabihf.rs | 8 ++++---- .../src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs | 8 ++++---- .../src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs | 8 ++++---- .../rustc_target/src/spec/targets/armv7a_none_eabi.rs | 8 ++++---- .../src/spec/targets/armv7a_none_eabihf.rs | 8 ++++---- .../src/spec/targets/armv7k_apple_watchos.rs | 8 ++++---- .../rustc_target/src/spec/targets/armv7r_none_eabi.rs | 8 ++++---- .../src/spec/targets/armv7r_none_eabihf.rs | 8 ++++---- .../rustc_target/src/spec/targets/armv7s_apple_ios.rs | 8 ++++---- .../src/spec/targets/armv8r_none_eabihf.rs | 8 ++++---- .../src/spec/targets/bpfeb_unknown_none.rs | 8 ++++---- .../src/spec/targets/bpfel_unknown_none.rs | 8 ++++---- .../src/spec/targets/csky_unknown_linux_gnuabiv2.rs | 7 ++++++- .../src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs | 7 ++++++- .../src/spec/targets/hexagon_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/hexagon_unknown_none_elf.rs | 8 ++++---- .../rustc_target/src/spec/targets/i386_apple_ios.rs | 8 ++++---- .../src/spec/targets/i586_pc_nto_qnx700.rs | 8 ++++---- .../src/spec/targets/i586_unknown_netbsd.rs | 8 ++++---- .../rustc_target/src/spec/targets/i686_apple_darwin.rs | 8 ++++---- .../src/spec/targets/i686_linux_android.rs | 8 ++++---- .../src/spec/targets/i686_pc_windows_gnu.rs | 8 ++++---- .../src/spec/targets/i686_pc_windows_gnullvm.rs | 8 ++++---- .../src/spec/targets/i686_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/i686_unknown_haiku.rs | 8 ++++---- .../src/spec/targets/i686_unknown_hurd_gnu.rs | 8 ++++---- .../src/spec/targets/i686_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/i686_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/i686_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/i686_unknown_openbsd.rs | 8 ++++---- .../rustc_target/src/spec/targets/i686_unknown_uefi.rs | 8 ++++---- .../src/spec/targets/i686_uwp_windows_gnu.rs | 6 +++--- .../src/spec/targets/i686_uwp_windows_msvc.rs | 6 +++--- .../src/spec/targets/i686_win7_windows_msvc.rs | 8 ++++---- .../rustc_target/src/spec/targets/i686_wrs_vxworks.rs | 6 +++--- .../src/spec/targets/loongarch64_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/loongarch64_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/loongarch64_unknown_none.rs | 6 +++--- .../spec/targets/loongarch64_unknown_none_softfloat.rs | 6 +++--- .../src/spec/targets/m68k_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/mips64_openwrt_linux_musl.rs | 8 ++++---- .../src/spec/targets/mips64_unknown_linux_gnuabi64.rs | 8 ++++---- .../src/spec/targets/mips64_unknown_linux_muslabi64.rs | 8 ++++---- .../spec/targets/mips64el_unknown_linux_gnuabi64.rs | 8 ++++---- .../spec/targets/mips64el_unknown_linux_muslabi64.rs | 8 ++++---- .../src/spec/targets/mips_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/mips_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/mips_unknown_linux_uclibc.rs | 8 ++++---- .../rustc_target/src/spec/targets/mipsel_sony_psp.rs | 8 ++++---- .../rustc_target/src/spec/targets/mipsel_sony_psx.rs | 8 ++++---- .../src/spec/targets/mipsel_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/mipsel_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/mipsel_unknown_linux_uclibc.rs | 8 ++++---- .../src/spec/targets/mipsel_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/mipsel_unknown_none.rs | 8 ++++---- .../src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs | 8 ++++---- .../spec/targets/mipsisa32r6el_unknown_linux_gnu.rs | 8 ++++---- .../spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs | 8 ++++---- .../targets/mipsisa64r6el_unknown_linux_gnuabi64.rs | 8 ++++---- .../rustc_target/src/spec/targets/msp430_none_elf.rs | 8 ++++---- .../src/spec/targets/nvptx64_nvidia_cuda.rs | 8 ++++---- .../rustc_target/src/spec/targets/powerpc64_ibm_aix.rs | 8 ++++---- .../src/spec/targets/powerpc64_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/powerpc64_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/powerpc64_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/powerpc64_unknown_openbsd.rs | 8 ++++---- .../src/spec/targets/powerpc64_wrs_vxworks.rs | 6 +++--- .../src/spec/targets/powerpc64le_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/powerpc64le_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/powerpc64le_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_linux_gnuspe.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/powerpc_unknown_openbsd.rs | 6 +++--- .../src/spec/targets/powerpc_wrs_vxworks.rs | 6 +++--- .../src/spec/targets/powerpc_wrs_vxworks_spe.rs | 6 +++--- .../src/spec/targets/riscv32gc_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/riscv32gc_unknown_linux_musl.rs | 10 ++++++---- .../src/spec/targets/riscv32i_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv32im_risc0_zkvm_elf.rs | 8 ++++---- .../src/spec/targets/riscv32im_unknown_none_elf.rs | 6 +++--- .../src/spec/targets/riscv32ima_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv32imac_esp_espidf.rs | 8 ++++---- .../src/spec/targets/riscv32imac_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv32imac_unknown_xous_elf.rs | 8 ++++---- .../src/spec/targets/riscv32imafc_esp_espidf.rs | 8 ++++---- .../src/spec/targets/riscv32imafc_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv32imc_esp_espidf.rs | 8 ++++---- .../src/spec/targets/riscv32imc_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv64_linux_android.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_fuchsia.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_hermit.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/riscv64gc_unknown_openbsd.rs | 8 ++++---- .../src/spec/targets/riscv64imac_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/s390x_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/s390x_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/sparc64_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/sparc64_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/sparc64_unknown_openbsd.rs | 8 ++++---- .../src/spec/targets/sparc_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/sparc_unknown_none_elf.rs | 8 ++++---- .../src/spec/targets/sparcv9_sun_solaris.rs | 8 ++++---- .../src/spec/targets/thumbv4t_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv5te_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv6m_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv7a_pc_windows_msvc.rs | 6 +++--- .../src/spec/targets/thumbv7a_uwp_windows_msvc.rs | 6 +++--- .../src/spec/targets/thumbv7em_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv7em_none_eabihf.rs | 8 ++++---- .../src/spec/targets/thumbv7m_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv7neon_linux_androideabi.rs | 8 ++++---- .../targets/thumbv7neon_unknown_linux_gnueabihf.rs | 10 ++++++---- .../targets/thumbv7neon_unknown_linux_musleabihf.rs | 8 ++++---- .../src/spec/targets/thumbv8m_base_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv8m_main_none_eabi.rs | 8 ++++---- .../src/spec/targets/thumbv8m_main_none_eabihf.rs | 8 ++++---- .../src/spec/targets/wasm32_unknown_emscripten.rs | 8 ++++---- .../src/spec/targets/wasm32_unknown_unknown.rs | 8 ++++---- .../rustc_target/src/spec/targets/wasm32_wasip1.rs | 8 ++++---- .../src/spec/targets/wasm32_wasip1_threads.rs | 6 +++--- .../rustc_target/src/spec/targets/wasm32_wasip2.rs | 8 ++++---- .../src/spec/targets/wasm64_unknown_unknown.rs | 8 ++++---- .../src/spec/targets/x86_64_apple_darwin.rs | 8 ++++---- .../rustc_target/src/spec/targets/x86_64_apple_ios.rs | 8 ++++---- .../src/spec/targets/x86_64_apple_ios_macabi.rs | 8 ++++---- .../rustc_target/src/spec/targets/x86_64_apple_tvos.rs | 8 ++++---- .../src/spec/targets/x86_64_apple_watchos_sim.rs | 8 ++++---- .../src/spec/targets/x86_64_fortanix_unknown_sgx.rs | 8 ++++---- .../src/spec/targets/x86_64_linux_android.rs | 8 ++++---- .../src/spec/targets/x86_64_pc_nto_qnx710.rs | 8 ++++---- .../rustc_target/src/spec/targets/x86_64_pc_solaris.rs | 8 ++++---- .../src/spec/targets/x86_64_pc_windows_gnu.rs | 8 ++++---- .../src/spec/targets/x86_64_pc_windows_gnullvm.rs | 8 ++++---- .../src/spec/targets/x86_64_unikraft_linux_musl.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_dragonfly.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_freebsd.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_fuchsia.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_haiku.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_hermit.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_illumos.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_l4re_uclibc.rs | 6 +++--- .../src/spec/targets/x86_64_unknown_linux_gnu.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_linux_gnux32.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_linux_ohos.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_netbsd.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_none.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_openbsd.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_redox.rs | 8 ++++---- .../src/spec/targets/x86_64_unknown_uefi.rs | 8 ++++---- .../src/spec/targets/x86_64_uwp_windows_gnu.rs | 6 +++--- .../src/spec/targets/x86_64_uwp_windows_msvc.rs | 6 +++--- .../src/spec/targets/x86_64_win7_windows_msvc.rs | 8 ++++---- .../src/spec/targets/x86_64_wrs_vxworks.rs | 6 +++--- .../src/spec/targets/x86_64h_apple_darwin.rs | 8 ++++---- 228 files changed, 903 insertions(+), 887 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 4e2964174f92..f37781c3f638 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 macOS (11.0+, Big Sur+)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 20655689772d..11a39c26e9d2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 iOS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 4c008f7985e6..85c40ec60c41 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: mac_catalyst_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple Catalyst on ARM64".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 4a63abdf5419..703b886cc19e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple iOS Simulator on ARM64".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 3310e6c9e8a4..e97ad11cdf6c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 tvOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index b901c663afae..8bfa9c8e8b7e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 tvOS Simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index a00a97a133f6..6d66299d6d9e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-apple-watchos".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Apple WatchOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index e2f80b7b7a88..9675a950d5d0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: watchos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Apple WatchOS Simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs index 88115b81fa5b..df389fe34bd6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (big-endian)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs index b89c2841dae7..10a8e3e4df81 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-linux-gnu_ilp32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (big-endian, ILP32 ABI)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs index d9164f8b052e..ba646cd6065f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 NetBSD (big-endian)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs index 168f6ad1ac2b..1c2273bb3a1f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 SOLID with TOPPERS/ASP3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs index e9fa482bff10..3f0072c00c14 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs index 7e7e202b1121..1ba4fbb3d256 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Nintendo Switch, Horizon".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index 2cc417ea8309..070460538c7a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index a5e7dda5fb8a..f4e2ee448057 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Windows MSVC".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs index 81c9d5927fa2..b10f1c7592e5 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs index d740f0b7c97a..f84853fbb19c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Fuchsia".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs index a466fa055164..55cb0b8f2ee7 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "aarch64".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs index 6f253c2a2239..7f05358e0161 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "aarch64-unknown-solaris2.11".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 illumos".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs index 0c4bac0e1295..1a45c2c5c05e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (kernel 4.1, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs index e202ce2f57f6..851366b7647b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu_ilp32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (ILP32 ABI)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs index 4a82423bb636..6b4a422a474a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index 3d357bcf3f23..5924e4f57579 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "aarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs index ac26aa822716..0069d5431f8e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 NetBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index 21706aa0b5d8..169468f2e248 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -32,10 +32,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARM64, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index 4f04a7816ce8..222d5651b521 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -26,10 +26,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARM64, softfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs index 8e448a2fa9a7..0e5a0b9b9a54 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 QNX Neutrino 7.1 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, // from: https://llvm.org/docs/LangRef.html#data-layout diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs index b51cddafb1aa..e16991af4e66 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs index 544709cffe67..e59b38a3e411 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-redox".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 RedoxOS".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs index 285c5e79cf05..5ae2d68332c6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 TEEOS".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs index de4a56ae03da..429303170b6b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-windows".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs index 50064e673b3d..df1b75272b1f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs @@ -9,9 +9,9 @@ pub fn target() -> Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs index 026b30e9eb78..41f7532ecdb1 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs @@ -5,9 +5,9 @@ pub fn target() -> Target { llvm_target: "aarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 3ca8c9969c2d..2c76f4736de8 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: watchos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm Apple WatchOS 64-bit with 32-bit pointers".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 90be518638e9..6f28f5d05436 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64e Apple Darwin".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 56470d29eae0..1590ae9679d8 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64e Apple iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs index aedfb8810246..21cb38868fb9 100644 --- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "arm64ec-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm64EC Windows MSVC".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs index 12c6388a97b6..a22bcef47575 100644 --- a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-linux-androideabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs index 8abf7dd53234..8ff272e786db 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index 922f51fd60d0..e3e2f4cd05c2 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs index 3c01c86c7d54..f958b89358b1 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "arm-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs index 5be5bb03979b..98093fdc0032 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs index f95ec8c78dd8..b56f311793ad 100644 --- a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armeb-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm BE8 the default Arm big-endian architecture since Armv6".into()), + tier: Some(3), + host_tools: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index d5ee10dbfc4c..df32b74f6d9a 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-R, Big Endian".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index 2f86506e2d05..063038c80122 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-R, Big Endian, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index 42d165a6ca48..f873fb0d3495 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv4T".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs index d12bc241d067..18f327bc87f7 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv4T Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index 512a175f2c97..1fbe4b89ea17 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv5TE".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs index 6b31d0ee25fa..123686448378 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs index ea14a2ec2521..ccbc1e36ddec 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv5te-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs index e2ab803576a9..d88b88333b56 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-uclibcgnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs index 04f351788283..24e9d1e03949 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-freebsd-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs index ca4d42ebbe87..62e328b9cbda 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-netbsdelf-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 NetBSD w/hard-float".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs index 9a88277b0636..bcdad0a55b31 100644 --- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6k-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs index e798ef473543..8f6a58a1b498 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 0730a423f724..a9b5172385ba 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -14,10 +14,12 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-vita-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)".into(), + ), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index 017b126129c1..3a16bbe95db3 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-freebsd-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs index 2be263d6d9c1..8a4ba271456a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux (kernel 4.15, glibc 2.27)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index 8a80a623b1d2..a217a2daeb39 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs index ad4ebed74e7e..96459a5137fd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs index ba7b62bc5eb4..6c878141fd49 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs index 489aad7845d9..bffc51d9b7bc 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs index fdf46101d257..9dc1221287dd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with uClibc, softfloat".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs index 36bc9548209e..01a1468d3a8c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with uClibc, hardfloat".into()), + tier: Some(3), + host_tools: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index 2dc4d9b835b2..a2391503ff8a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-netbsdelf-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A NetBSD w/hard-float".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs index 89469f01c3a2..7d60ec1b64dd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A for VxWorks".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs index ffdeba50df27..76d4653931b8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm SOLID with TOPPERS/ASP3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index cbcf223daf6d..d2b4d46adac6 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm SOLID with TOPPERS/ASP3, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs index 3373e677c4ac..b544c404f3f2 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs @@ -33,10 +33,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-A".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index 12844a8e5824..aebb7e667bcd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -25,10 +25,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-A, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 5c675c22ef51..e876c567b09a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7k-apple-watchos".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Apple WatchOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs index d5213234339c..b3246dc79281 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-R".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs index 7c39d2d38de8..9ac500d7ffe7 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-R, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index 4dd475e3a82d..11608794932b 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Apple-A6 Apple iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs index 17fdd496302c..ee940c3a76a2 100644 --- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv8r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv8-R, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs index 470674372fdd..8cddb6fe005c 100644 --- a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "bpfeb".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("BPF (big endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs index 3e3202df17e0..d070aa0ec44b 100644 --- a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "bpfel".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("BPF (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs index 120c75f528ad..e8a0b465e156 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs @@ -6,7 +6,12 @@ pub fn target() -> Target { Target { //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h llvm_target: "csky-unknown-linux-gnuabiv2".into(), - metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None }, + metadata: crate::spec::TargetMetadata { + description: Some("C-SKY abiv2 Linux (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true) + }, pointer_width: 32, data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: "csky".into(), diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs index 2856e94ea4a9..99330ddc3189 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs @@ -6,7 +6,12 @@ pub fn target() -> Target { Target { //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h llvm_target: "csky-unknown-linux-gnuabiv2".into(), - metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None }, + metadata: crate::spec::TargetMetadata { + description: Some("C-SKY abiv2 Linux, hardfloat (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true) + }, pointer_width: 32, data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: "csky".into(), diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index 003d35ebeb45..bd5397990296 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Hexagon Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: concat!( diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs index 8750e0ee85f1..cefd0bf6d67b 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Hexagon (v60+, HVX)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: concat!( diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index c03a0974bc1c..b1b2b6cdffa8 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 290ed81ad45d..6c80ab6994dd 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "i586-pc-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs index 73949c7bdc4c..de42549b7f8d 100644 --- a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "i586-unknown-netbsdelf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86, resricted to Pentium".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index aea6a1ac4ece..02f6bec4692f 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { // While ld64 doesn't understand i686, LLVM does. llvm_target: macos_llvm_target(Arch::I686).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit macOS (10.12+, Sierra+)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index 585aad10c57c..fc313e575be6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index 66e09416dde9..4b0f4bf3ecd2 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MinGW (Windows 10+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs index 7a2d28aec9c0..5bb082014298 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs index 5826906e9d8e..cce21fcacb1c 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit FreeBSD".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs index 5f66911b39a1..84ef00f06c81 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-haiku".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Haiku".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index a67105f24ca2..ad8c0f7f582e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-hurd-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit GNU/Hurd".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs index 1d4916cabfdf..5584435a0ad9 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Linux (kernel 3.2, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs index c3b9b71802b1..d1ab1f73b511 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs @@ -24,10 +24,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs index 87eba1fb856f..255148fca9a3 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-netbsdelf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/i386 with SSE2".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs index 0436f39f5b11..d6df801234c6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs index 8665a7ca61a3..b92fc2e759a3 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs @@ -79,10 +79,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs index 77dcd645728f..851bea80fb83 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs @@ -18,9 +18,9 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs index b38302262670..28bd2aae8e71 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs @@ -9,9 +9,9 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index ae1a44e44a85..cd488d0532c2 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -22,10 +22,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Windows 7 support".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs index e4d0b674cc4c..973c75eeca6e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "i686-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 3e88180012e5..6f0bb449c16c 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index c45bc4383500..19b04607f0e0 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 69533e82c3ce..744ffff721fe 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index bc4c5bcde5ed..a382e7a53fbd 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs index abd07ef9bdc7..7cff0efd112c 100644 --- a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "m68k-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Motorola 680x0 Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".into(), 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 9df7b2b670f5..c3235bf994fa 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 @@ -14,10 +14,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 for OpenWrt Linux musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), 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 e9de4a5c2607..cdf4ffb7f9eb 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 @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips64-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), 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 48443717b196..463f7dc47f72 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 @@ -10,10 +10,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), 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 515473fbabc5..ad77a02c0630 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 @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mips64el-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), 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 e6b998746e6a..83f5c7ea37d6 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 @@ -9,10 +9,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs index 3616ea603044..0bdfd6ee6b09 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs index b47bc0d30058..8e27c9936c56 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs index 117d74f2d25e..852e1d9376d0 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-uclibc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs index fafe14935383..9d3f4d9f7950 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psp".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Sony PlatStation Portable (PSP)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs index 9f37b0edc176..c0b99a68b0d0 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psx".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Sony PlayStation 1 (PSX)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs index e65480e355b7..8fe4548a3ad9 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (little endian) Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs index ed98f53a2b29..43914a233080 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (little endian) Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs index dc6807509cb9..6150654c0817 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-uclibc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs index 8e5cd30a54f2..03501aa76a83 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS (LE), requires mips32 cpu support".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs index b5948b4d35c4..81aac3ce0b87 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare MIPS (LE) softfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs index dbb143b73192..2ed520e9f48f 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS Release 6 Big Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs index f5fff6bec1c2..de30c5b35b75 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6el-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS Release 6 Little Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), 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 ed236cca1bb5..4178a991e14f 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 @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MIPS Release 6 Big Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), 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 bbdc5b95ad18..8e50373bd124 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 @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MIPS Release 6 Little Endian".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs index 2b022a4a5584..de476741defd 100644 --- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "msp430-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("16-bit MSP430 microcontrollers".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 16, data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".into(), diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 0b0b31b503b8..15156fbcfc9e 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { data_layout: "e-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(), llvm_target: "nvptx64-nvidia-cuda".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index 481df71c1a65..bda43e7a2b0f 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-ibm-aix".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit AIX (7.2 and newer)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index b1b981823b89..6eb5bba0fcd9 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64 FreeBSD (ELFv1 and ELFv2)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index ac10630d9440..53b84479a491 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 663f06cf0c67..0d0484dd1748 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit PowerPC Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index 5611352c951c..2922c921e17d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/powerpc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 22b45042aa66..dd2ec2742076 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -12,9 +12,9 @@ pub fn target() -> Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 812b5928966f..ea295cf169e0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64LE FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index e3c4b3b585c2..dc70bd238a74 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64LE Linux (kernel 3.10, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index 497a40ade81e..dbfbd69b95b1 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs index 194bb0566f18..2f7acccfae83 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-freebsd13.0".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs index b88b2fbf8094..2ecafbb08bc3 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs index b09c4cd21e04..04b2309fdc88 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC SPE Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs index 67b19e904891..108e468eb66b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs index c592cd3f6fd2..3ee6cd46c853 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD 32-bit powerpc systems".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs index a17f437e0648..f00ee9604137 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs index 91925ce151df..5d107d6e60ec 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs index 7640feb28e3c..aea525a69123 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index 7e607574241a..e425d6a3f3fc 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index a46b1bb6588e..409b6b22f1cf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -6,10 +6,12 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches".into(), + ), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs index 87eebbe87087..631a31edeb5e 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32I ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs index 186f8105df5b..726778aca0d8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs index 962fcd0eb996..5fa3858e8574 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs index 9acf6a3b5a0e..2022873d05cb 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMA ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs index 1e1356910d92..386e3a38f975 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs index 705bc17892aa..7ced37e15357 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMAC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs index 80b6e6077b22..cd50a9e60c32 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Xous (RV32IMAC ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs index 6c660793777d..3661e38e7b1b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs index f4a0cd1c51ef..954660908912 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMAFC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs index cee6fd32dd64..d52dc8f96ca2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs index 5378c132df10..ff9931978466 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 27629199ea55..2dfaf8a2033c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V 64-bit Android".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs index 37c360e6761d..1fd6a4b38dcf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs index a600ee765668..5c3f525966ed 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Fuchsia".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs index 63c06a97223d..f11128cfcb67 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "riscv64".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index 199ffc1c139a..308c995297bb 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 4.20, glibc 2.29)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index f8b5ceee8b4f..3e575fdd528d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 4.20, musl 1.2.3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs index 9dbe01f45987..65781f5af5c7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V NetBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs index 9f128d07a99f..a75f8969a739 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV64IMAFDC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, llvm_target: "riscv64".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs index 29919a16078a..5bdbda773b1b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/riscv64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs index 1ab6aebcea94..ba9a10e66331 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), llvm_target: "riscv64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV64IMAC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, arch: "riscv64".into(), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index be68c5b1c886..b0dd0eb612e1 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -19,10 +19,10 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("S390x Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index 619e83ce620b..3976233819ce 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -20,10 +20,10 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("S390x Linux (kernel 3.2, musl 1.2.3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs index 77c9b4f996aa..eeb7eebfe503 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("SPARC Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs index 42944367cf66..69bb6e1fb60e 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/sparc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs index f0bf55d33e68..08f6eaf83617 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/sparc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs index 5cee06e4936c..8b7ff5d8011c 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit SPARC Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs index cfe8f65d7941..c977fe608a78 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs @@ -21,10 +21,10 @@ pub fn target() -> Target { data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), llvm_target: "sparc-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare 32-bit SPARC V7+".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "sparc".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs index a42243f59dc4..1c0adadece0b 100644 --- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "sparcv9-sun-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("SPARC Solaris 11, illumos".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 9f222522505a..96dd8588d4f6 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv4t-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb-mode Bare ARMv4T".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index 67e57c5fc352..d92e68cebaa6 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv5te-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb-mode Bare ARMv5TE".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs index cac415128b68..a0fa58d8175c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv6m-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv6-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs index 13e1e349b040..e36aa5ab395d 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs @@ -15,9 +15,9 @@ pub fn target() -> Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs index e3e2ea635944..2e68dd0ec4e8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs @@ -5,9 +5,9 @@ pub fn target() -> Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs index ec73cf40a713..bd2df9236f67 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7E-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index bff812a5d5c7..e2499ef54112 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7E-M, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs index 0104cdcc9a24..17e37f800f0b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7m-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs index d50e63b92175..c562f57252e5 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb2-mode ARMv7-A Android with NEON".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs index d630ca214e5d..b5e91d61308b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs @@ -10,10 +10,12 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)".into(), + ), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs index 74d5450c787e..71d5eb43c104 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb2-mode ARMv7-A Linux with NEON, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs index 2f385208f36a..e18bf113fe7c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.base-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Baseline".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs index 29a0803ba07e..5c2f1e093819 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Mainline".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index 88796e7a756b..799ac45b479c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Mainline, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index 195ff46cf9d2..46257a272d1e 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -25,10 +25,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-emscripten".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly via Emscripten".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs index 23f4772c39cb..bf92f30e8b37 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs @@ -37,10 +37,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs index 4c2d222b590e..a8e7f22c0689 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs @@ -51,10 +51,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly with WASI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 38af48ab2665..4e60806f3a73 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -63,9 +63,9 @@ pub fn target() -> Target { llvm_target: "wasm32-wasi".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs index 1259969ac365..63d1f4869be4 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs @@ -62,10 +62,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasip2".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs index 8edde36dac62..bc49a3c9f70d 100644 --- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs @@ -40,10 +40,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm64-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 21acd750df2d..94638ae62f83 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit macOS (10.12+, Sierra+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index ec61b7967646..3cabca033609 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 iOS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index bd967ee972b3..d3ba17cf0271 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: mac_catalyst_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple Catalyst on x86_64".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 55b2e1afcd39..2a3125157dd9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit tvOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index a783eff15b26..62e60b5e32d0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: watchos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit Apple WatchOS simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs index 012450e307e7..5a72fad82632 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs @@ -75,10 +75,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Fortanix ABI for 64-bit Intel SGX".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs index 92711bbe246b..257093b75545 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs index c7169c3d62d5..f6d22ff32049 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit QNX Neutrino 7.1 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index 4dbe049a4b78..697daf590ad0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Solaris 11, illumos".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs index de0f17246c3d..89a9bb1e1cc5 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MinGW (Windows 10+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs index b485970bb416..acf0fd421bac 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs index 8752ba81066e..883da26d786e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Unikraft with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "x86_64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs index aef95e373cbf..171a6f2a51e7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-dragonfly".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit DragonFlyBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs index 15146a5ef729..4692b5a3c74e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit FreeBSD".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index 80cdeab0a677..5ebf1804302b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 Fuchsia".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs index 9f62eb1fa270..b593b79e7bbd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-haiku".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Haiku".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs index 745a658ed00d..3e81ff9a4ec4 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86_64 Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "x86_64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs index c52cdf466abe..d683a4420274 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "x86_64-pc-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("illumos".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs index 6b170c22c9e1..adf489ad7b1d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-l4re-uclibc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index bd12d4d8af0e..4a92d4ef9d5c 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -28,10 +28,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs index f6e0b051e8f5..3c7db0095a14 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnux32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs index 66237f071028..109fc3c0728d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs index db8db1d25382..c1d888899fc2 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86_64 OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs index 38ae3a4fe424..d413caf4aaf7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs @@ -19,10 +19,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/amd64".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 5846dc16d66b..4c67fa0f7aa6 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -30,10 +30,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Freestanding/bare-metal x86_64 softfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs index 4d7eba242139..8f1c3ef9bc7b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs index 99f5d9dc41d2..ae38f63f034f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-redox".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Redox OS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index 0c6e4b2b1ff5..6da1fcca58c8 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -32,10 +32,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-windows".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs index aef6fd1a7814..c71bc9ed9231 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs @@ -17,9 +17,9 @@ pub fn target() -> Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs index 963ccdbfcd06..178baeca6857 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "x86_64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 9b458614f2b8..d44ae9fc4e0a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-win7-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Windows 7 support".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs index b956d228c17f..7b40f7366d0f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs @@ -13,9 +13,9 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index fe6cbca32c74..72cbc1be9310 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -35,10 +35,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("macOS with late-gen Intel (at least Haswell)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: From 7b76b947800bac94d041aaf8156450c8e7289da9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 22 Jun 2024 06:19:07 +0700 Subject: [PATCH 066/361] add test 12969 and 9841 --- tests/ui/explicit_auto_deref.fixed | 32 +++++++++++++++++++++++++++++ tests/ui/explicit_auto_deref.rs | 32 +++++++++++++++++++++++++++++ tests/ui/explicit_auto_deref.stderr | 14 ++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index e6ca4bb66ccd..22bc09496599 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -345,3 +345,35 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 7531e1f87b71..2b3a28f8b6f1 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -345,3 +345,35 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&*wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 56a183de3487..450592673627 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -271,5 +271,17 @@ error: deref which would be done by auto-deref LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` -error: aborting due to 45 previous errors +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:367:13 + | +LL | foo(&*wrapped_bar); + | ^^^^^^^^^^^^^ help: try: `wrapped_bar` + +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:373:21 + | +LL | takes_slice(*array) + | ^^^^^^ help: try: `array` + +error: aborting due to 47 previous errors From 388de386f5ecbbb0eb7a164fe1fa702db2fa4328 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 22 Jun 2024 06:21:35 +0700 Subject: [PATCH 067/361] Make it easier to print debugging with Debug --- clippy_lints/src/dereference.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 3c137b6b70fa..4c1ca75e0dba 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -175,6 +175,7 @@ struct StateData<'tcx> { adjusted_ty: Ty<'tcx>, } +#[derive(Debug)] struct DerefedBorrow { count: usize, msg: &'static str, @@ -182,6 +183,7 @@ struct DerefedBorrow { for_field_access: Option, } +#[derive(Debug)] enum State { // Any number of deref method calls. DerefMethod { @@ -744,7 +746,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum TyCoercionStability { Deref, Reborrow, From c4c41d135227a0a34ddc941ccb6be9296e4cceff Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 3 Jul 2024 21:25:43 +0700 Subject: [PATCH 068/361] Fix 12969 and fix 9841 --- clippy_lints/src/dereference.rs | 33 ++++++++++++++++++++--------- clippy_utils/src/lib.rs | 11 ++++++++++ tests/ui/explicit_auto_deref.fixed | 8 +++++-- tests/ui/explicit_auto_deref.rs | 4 ++++ tests/ui/explicit_auto_deref.stderr | 10 ++------- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 4c1ca75e0dba..164d51ecb75d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, + expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, + ExprUseNode, }; use core::mem; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; @@ -1044,16 +1045,28 @@ fn report<'tcx>( return; } - let (prefix, precedence) = if let Some(mutability) = mutability - && !typeck.expr_ty(expr).is_ref() + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, PREC_PREFIX) - } else { - ("", 0) + let (src, n_src_refs) = peel_middle_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, precedence) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, PREC_PREFIX) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0), + _ => ("", 0), }; span_lint_hir_and_then( cx, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fda870f435a5..89686916671e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2471,6 +2471,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) } } +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { + let mut count = 0; + while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() { + ty = *dest_ty; + count += 1; + } + (ty, count) +} + /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 22bc09496599..255b2c5a220d 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -364,13 +364,17 @@ mod issue_12969 { fn bar() { let wrapped_bar = Wrapper(""); - foo(wrapped_bar); + foo(&wrapped_bar); } } mod issue_9841 { fn takes_array_ref(array: &&[T; N]) { - takes_slice(array) + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) } fn takes_slice(slice: &[T]) { diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 2b3a28f8b6f1..99906999f01d 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -373,6 +373,10 @@ mod issue_9841 { takes_slice(*array) } + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + fn takes_slice(slice: &[T]) { todo!() } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 450592673627..53784934f638 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -275,13 +275,7 @@ error: deref which would be done by auto-deref --> tests/ui/explicit_auto_deref.rs:367:13 | LL | foo(&*wrapped_bar); - | ^^^^^^^^^^^^^ help: try: `wrapped_bar` + | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` -error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:373:21 - | -LL | takes_slice(*array) - | ^^^^^^ help: try: `array` - -error: aborting due to 47 previous errors +error: aborting due to 46 previous errors From 5e83fafd88c2b2f8510f7b9db8c2748be7eb239c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 3 Jul 2024 13:02:47 -0500 Subject: [PATCH 069/361] Use libc::pause instead of std::thread::park in wait-for-exit loop --- library/std/src/sys/pal/common/exit_guard.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index 37c8f97e45d9..06f62941db74 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -10,9 +10,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "linux")] { /// Mitigation for /// - /// On `unix` (where `libc::exit` may not be thread-safe), ensure that only one Rust thread - /// calls `libc::exit` (or returns from `main`) by calling this function before calling - /// `libc::exit` (or returning from `main`). + /// On UNIX-like platforms (where `libc::exit` may not be thread-safe), ensure that only one + /// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before + /// calling `libc::exit` (or returning from `main`). /// /// Technically not enough to ensure soundness, since other code directly calling /// libc::exit will still race with this. @@ -23,7 +23,7 @@ cfg_if::cfg_if! { /// This function will return only the first time it is called in a process. /// /// * If it is called again on the same thread as the first call, it will abort. - /// * If it is called again on a different thread, it will `thread::park()` in a loop + /// * If it is called again on a different thread, it will wait in a loop /// (waiting for the process to exit). pub(crate) fn unique_thread_exit() { let this_thread_id = unsafe { libc::gettid() }; @@ -52,9 +52,10 @@ cfg_if::cfg_if! { } Err(_) => { // This is not the first thread to call `unique_thread_exit`. - // Park until the process exits. + // Pause until the process exits. loop { - crate::thread::park(); + // Safety: libc::pause is safe to call. + unsafe { libc::pause(); } } } } @@ -77,10 +78,12 @@ cfg_if::cfg_if! { core::panicking::panic_nounwind("std::process::exit called re-entrantly") } else { // This is not the first thread to call `unique_thread_exit`. + // Pause until the process exits. // Park until the process exits. drop(exiting_thread_id); loop { - crate::thread::park(); + // Safety: libc::pause is safe to call. + unsafe { libc::pause(); } } } } From 897fb6cb1ab30900a03a2806d312f9d22e43459c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 3 Jul 2024 13:28:44 -0500 Subject: [PATCH 070/361] Use pthread_t instead of numeric thread id --- library/std/src/sys/pal/common/exit_guard.rs | 57 +++++--------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index 06f62941db74..0ea1faacee95 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -26,60 +26,27 @@ cfg_if::cfg_if! { /// * If it is called again on a different thread, it will wait in a loop /// (waiting for the process to exit). pub(crate) fn unique_thread_exit() { - let this_thread_id = unsafe { libc::gettid() }; - debug_assert_ne!(this_thread_id, 0, "thread ID cannot be zero"); - #[cfg(target_has_atomic = "32")] - { - use crate::sync::atomic::{AtomicI32, Ordering}; - static EXITING_THREAD_ID: AtomicI32 = AtomicI32::new(0); - match EXITING_THREAD_ID.compare_exchange( - 0, - this_thread_id, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_zero) => { - // 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 (done by the - // compare_exchange) and return. - } - Err(id) if 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") - } - Err(_) => { - // This is not the first thread to call `unique_thread_exit`. - // Pause until the process exits. - loop { - // Safety: libc::pause is safe to call. - unsafe { libc::pause(); } - } - } - } - } - #[cfg(not(target_has_atomic = "32"))] - { - use crate::sync::{Mutex, PoisonError}; - static EXITING_THREAD_ID: Mutex = Mutex::new(0); - let mut exiting_thread_id = - EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); - if *exiting_thread_id == 0 { + 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 => { // 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 = this_thread_id; - } else if *exiting_thread_id == this_thread_id { + *exiting_thread_id = Some(this_thread_id); + }, + Some(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") - } else { + } + Some(_) => { // This is not the first thread to call `unique_thread_exit`. // Pause until the process exits. - // Park until the process exits. drop(exiting_thread_id); loop { // Safety: libc::pause is safe to call. From b512608275fed67cfccd05bea91d48d708ea7ae9 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 3 Jul 2024 13:33:32 -0500 Subject: [PATCH 071/361] Remove Miri special-case --- library/std/src/sys/pal/common/exit_guard.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index 0ea1faacee95..eb2c14cdecc7 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -1,13 +1,5 @@ cfg_if::cfg_if! { - if #[cfg(miri)] { - /// Mitigation for - /// - /// This mitigation is not necessary when running under Miri, so this function does nothing - /// when running under Miri. - pub(crate) fn unique_thread_exit() { - // Mitigation not required on Miri, where `exit` is thread-safe. - } - } else if #[cfg(target_os = "linux")] { + if #[cfg(target_os = "linux")] { /// Mitigation for /// /// On UNIX-like platforms (where `libc::exit` may not be thread-safe), ensure that only one From 0f915f6f30c2fb267e25b0bf14bc4674ba7accca Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Fri, 31 May 2024 16:58:19 +0100 Subject: [PATCH 072/361] Add new lint `hashset_insert_after_contains` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/hashset_insert_after_contains.rs | 137 ++++++++++++++++++ clippy_lints/src/lib.rs | 2 + tests/ui/hashset_insert_after_contains.rs | 77 ++++++++++ tests/ui/hashset_insert_after_contains.stderr | 112 ++++++++++++++ 6 files changed, 330 insertions(+) create mode 100644 clippy_lints/src/hashset_insert_after_contains.rs create mode 100644 tests/ui/hashset_insert_after_contains.rs create mode 100644 tests/ui/hashset_insert_after_contains.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0974631ac5dc..3c4a24f2b0bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5401,6 +5401,7 @@ Released 2018-09-13 [`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap +[`hashset_insert_after_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#hashset_insert_after_contains [`host_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#host_endian_bytes [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 53f346c04e78..ff6ce7b50907 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -211,6 +211,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::functions::TOO_MANY_ARGUMENTS_INFO, crate::functions::TOO_MANY_LINES_INFO, crate::future_not_send::FUTURE_NOT_SEND_INFO, + crate::hashset_insert_after_contains::HASHSET_INSERT_AFTER_CONTAINS_INFO, crate::if_let_mutex::IF_LET_MUTEX_INFO, crate::if_not_else::IF_NOT_ELSE_INFO, crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO, diff --git a/clippy_lints/src/hashset_insert_after_contains.rs b/clippy_lints/src/hashset_insert_after_contains.rs new file mode 100644 index 000000000000..a793d6e2eb1a --- /dev/null +++ b/clippy_lints/src/hashset_insert_after_contains.rs @@ -0,0 +1,137 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `contains` to see if a value is not + /// present on `HashSet` followed by a `insert`. + /// + /// ### Why is this bad? + /// Using just `insert` and checking the returned `bool` is more efficient. + /// + /// ### Example + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if !set.contains(&value) { + /// set.insert(value); + /// println!("inserted {value:?}"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if set.insert(&value) { + /// println!("inserted {value:?}"); + /// } + /// ``` + #[clippy::version = "1.80.0"] + pub HASHSET_INSERT_AFTER_CONTAINS, + nursery, + "unnecessary call to `HashSet::contains` followed by `HashSet::insert`" +} + +declare_lint_pass!(HashsetInsertAfterContains => [HASHSET_INSERT_AFTER_CONTAINS]); + +impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let Some(higher::If { + cond: cond_expr, + then: then_expr, + .. + }) = higher::If::hir(expr) + && let Some(contains_expr) = try_parse_contains(cx, cond_expr) + && find_insert_calls(cx, &contains_expr, then_expr) + { + span_lint_and_then( + cx, + HASHSET_INSERT_AFTER_CONTAINS, + expr.span, + "usage of `HashSet::insert` after `HashSet::contains`", + |diag| { + diag.note("`HashSet::insert` returns whether it was inserted") + .span_help(contains_expr.span, "remove the `HashSet::contains` call"); + }, + ); + } + } +} + +struct ContainsExpr<'tcx> { + receiver: &'tcx Expr<'tcx>, + value: &'tcx Expr<'tcx>, + span: Span, +} +fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option> { + let expr = peel_hir_expr_while(expr, |e| { + if let ExprKind::Unary(UnOp::Not, e) = e.kind { + Some(e) + } else { + None + } + }); + if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind { + let value = value.peel_borrows(); + let receiver = receiver.peel_borrows(); + let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); + if value.span.eq_ctxt(expr.span) + && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) + && path.ident.name == sym!(contains) + { + return Some(ContainsExpr { receiver, value, span }); + } + } + None +} + +struct InsertExpr<'tcx> { + receiver: &'tcx Expr<'tcx>, + value: &'tcx Expr<'tcx>, +} +fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { + if let ExprKind::MethodCall(path, receiver, [value], _) = expr.kind { + let value = value.peel_borrows(); + let value = peel_hir_expr_while(value, |e| { + if let ExprKind::Unary(UnOp::Deref, e) = e.kind { + Some(e) + } else { + None + } + }); + + let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); + if is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) && path.ident.name == sym!(insert) { + Some(InsertExpr { receiver, value }) + } else { + None + } + } else { + None + } +} + +fn find_insert_calls<'tcx>(cx: &LateContext<'tcx>, contains_expr: &ContainsExpr<'tcx>, expr: &'tcx Expr<'_>) -> bool { + for_each_expr(expr, |e| { + if let Some(insert_expr) = try_parse_insert(cx, e) + && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) + && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fa4c7084f4dd..fd23659d9c50 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -150,6 +150,7 @@ mod from_raw_with_void_ptr; mod from_str_radix_10; mod functions; mod future_not_send; +mod hashset_insert_after_contains; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -1172,6 +1173,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); + store.register_late_pass(|_| Box::new(hashset_insert_after_contains::HashsetInsertAfterContains)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/hashset_insert_after_contains.rs b/tests/ui/hashset_insert_after_contains.rs new file mode 100644 index 000000000000..11e4cde84d64 --- /dev/null +++ b/tests/ui/hashset_insert_after_contains.rs @@ -0,0 +1,77 @@ +#![allow(unused)] +#![allow(clippy::nonminimal_bool)] +#![allow(clippy::needless_borrow)] +#![warn(clippy::hashset_insert_after_contains)] + +use std::collections::HashSet; + +fn main() { + should_warn_cases(); + + should_not_warn_cases(); +} + +fn should_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + + if !set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if !set.contains(&value) { + set.insert(value); + } + + if !!set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if (&set).contains(&value) { + set.insert(value); + } + + let borrow_value = &6; + if !set.contains(borrow_value) { + set.insert(*borrow_value); + } + + let borrow_set = &mut set; + if !borrow_set.contains(&value) { + borrow_set.insert(value); + } +} + +fn should_not_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + let another_value = 6; + + if !set.contains(&value) { + set.insert(another_value); + } + + if !set.contains(&value) { + println!("Just a comment"); + } + + if simply_true() { + set.insert(value); + } + + if !set.contains(&value) { + set.replace(value); //it is not insert + println!("Just a comment"); + } +} + +fn simply_true() -> bool { + true +} diff --git a/tests/ui/hashset_insert_after_contains.stderr b/tests/ui/hashset_insert_after_contains.stderr new file mode 100644 index 000000000000..d547dfa5c1a3 --- /dev/null +++ b/tests/ui/hashset_insert_after_contains.stderr @@ -0,0 +1,112 @@ +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:18:5 + | +LL | / if !set.contains(&value) { +LL | | set.insert(value); +LL | | println!("Just a comment"); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:18:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ + = note: `-D clippy::hashset-insert-after-contains` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::hashset_insert_after_contains)]` + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:23:5 + | +LL | / if set.contains(&value) { +LL | | set.insert(value); +LL | | println!("Just a comment"); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:23:12 + | +LL | if set.contains(&value) { + | ^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:28:5 + | +LL | / if !set.contains(&value) { +LL | | set.insert(value); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:28:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:32:5 + | +LL | / if !!set.contains(&value) { +LL | | set.insert(value); +LL | | println!("Just a comment"); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:32:14 + | +LL | if !!set.contains(&value) { + | ^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:37:5 + | +LL | / if (&set).contains(&value) { +LL | | set.insert(value); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:37:15 + | +LL | if (&set).contains(&value) { + | ^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:42:5 + | +LL | / if !set.contains(borrow_value) { +LL | | set.insert(*borrow_value); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:42:13 + | +LL | if !set.contains(borrow_value) { + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/hashset_insert_after_contains.rs:47:5 + | +LL | / if !borrow_set.contains(&value) { +LL | | borrow_set.insert(value); +LL | | } + | |_____^ + | + = note: `HashSet::insert` returns whether it was inserted +help: remove the `HashSet::contains` call + --> tests/ui/hashset_insert_after_contains.rs:47:20 + | +LL | if !borrow_set.contains(&value) { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + From 6661e83e7bf2adcc9a68d59aee6e281f7c051b82 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Mon, 3 Jun 2024 19:04:07 +0100 Subject: [PATCH 073/361] Rename lint, generalize function, add known issues, use multispan --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 4 +- ..._contains.rs => set_contains_or_insert.rs} | 78 ++++++------ tests/ui/hashset_insert_after_contains.stderr | 112 ------------------ ..._contains.rs => set_contains_or_insert.rs} | 8 +- tests/ui/set_contains_or_insert.stderr | 61 ++++++++++ 7 files changed, 105 insertions(+), 162 deletions(-) rename clippy_lints/src/{hashset_insert_after_contains.rs => set_contains_or_insert.rs} (60%) delete mode 100644 tests/ui/hashset_insert_after_contains.stderr rename tests/ui/{hashset_insert_after_contains.rs => set_contains_or_insert.rs} (89%) create mode 100644 tests/ui/set_contains_or_insert.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4a24f2b0bb..23b3ea9f2213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5401,7 +5401,6 @@ Released 2018-09-13 [`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap -[`hashset_insert_after_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#hashset_insert_after_contains [`host_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#host_endian_bytes [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op @@ -5799,6 +5798,7 @@ Released 2018-09-13 [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse +[`set_contains_or_insert`]: https://rust-lang.github.io/rust-clippy/master/index.html#set_contains_or_insert [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ff6ce7b50907..ef5dfd3ee32c 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -211,7 +211,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::functions::TOO_MANY_ARGUMENTS_INFO, crate::functions::TOO_MANY_LINES_INFO, crate::future_not_send::FUTURE_NOT_SEND_INFO, - crate::hashset_insert_after_contains::HASHSET_INSERT_AFTER_CONTAINS_INFO, crate::if_let_mutex::IF_LET_MUTEX_INFO, crate::if_not_else::IF_NOT_ELSE_INFO, crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO, @@ -646,6 +645,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO, crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO, crate::serde_api::SERDE_API_MISUSE_INFO, + crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO, crate::shadow::SHADOW_REUSE_INFO, crate::shadow::SHADOW_SAME_INFO, crate::shadow::SHADOW_UNRELATED_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fd23659d9c50..1747d5085597 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -150,7 +150,6 @@ mod from_raw_with_void_ptr; mod from_str_radix_10; mod functions; mod future_not_send; -mod hashset_insert_after_contains; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -319,6 +318,7 @@ mod self_named_constructors; mod semicolon_block; mod semicolon_if_nothing_returned; mod serde_api; +mod set_contains_or_insert; mod shadow; mod significant_drop_tightening; mod single_call_fn; @@ -1173,7 +1173,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); - store.register_late_pass(|_| Box::new(hashset_insert_after_contains::HashsetInsertAfterContains)); + store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/hashset_insert_after_contains.rs b/clippy_lints/src/set_contains_or_insert.rs similarity index 60% rename from clippy_lints/src/hashset_insert_after_contains.rs rename to clippy_lints/src/set_contains_or_insert.rs index a793d6e2eb1a..d6b6f655ac36 100644 --- a/clippy_lints/src/hashset_insert_after_contains.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -1,12 +1,13 @@ use std::ops::ControlFlow; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -17,6 +18,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// Using just `insert` and checking the returned `bool` is more efficient. /// + /// ### Known problems + /// In case the value that wants to be inserted is borrowed and also expensive or impossible + /// to clone. In such scenario, the developer might want to check with `contain` before inserting, + /// to avoid the clone. In this case, it will report a false positive. + /// /// ### Example /// ```rust /// use std::collections::HashSet; @@ -37,12 +43,12 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.80.0"] - pub HASHSET_INSERT_AFTER_CONTAINS, + pub SET_CONTAINS_OR_INSERT, nursery, - "unnecessary call to `HashSet::contains` followed by `HashSet::insert`" + "call to `HashSet::contains` followed by `HashSet::insert`" } -declare_lint_pass!(HashsetInsertAfterContains => [HASHSET_INSERT_AFTER_CONTAINS]); +declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]); impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -52,29 +58,26 @@ impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { then: then_expr, .. }) = higher::If::hir(expr) - && let Some(contains_expr) = try_parse_contains(cx, cond_expr) - && find_insert_calls(cx, &contains_expr, then_expr) + && let Some(contains_expr) = 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_and_then( + span_lint( cx, - HASHSET_INSERT_AFTER_CONTAINS, - expr.span, + SET_CONTAINS_OR_INSERT, + vec![contains_expr.span, insert_expr.span], "usage of `HashSet::insert` after `HashSet::contains`", - |diag| { - diag.note("`HashSet::insert` returns whether it was inserted") - .span_help(contains_expr.span, "remove the `HashSet::contains` call"); - }, ); } } } -struct ContainsExpr<'tcx> { +struct OpExpr<'tcx> { receiver: &'tcx Expr<'tcx>, value: &'tcx Expr<'tcx>, span: Span, } -fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option> { + +fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option> { let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Unary(UnOp::Not, e) = e.kind { Some(e) @@ -82,26 +85,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio None } }); - if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind { - let value = value.peel_borrows(); - let receiver = receiver.peel_borrows(); - let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if value.span.eq_ctxt(expr.span) - && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) - && path.ident.name == sym!(contains) - { - return Some(ContainsExpr { receiver, value, span }); - } - } - None -} -struct InsertExpr<'tcx> { - receiver: &'tcx Expr<'tcx>, - value: &'tcx Expr<'tcx>, -} -fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { - if let ExprKind::MethodCall(path, receiver, [value], _) = expr.kind { + if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind { let value = value.peel_borrows(); let value = peel_hir_expr_while(value, |e| { if let ExprKind::Unary(UnOp::Deref, e) = e.kind { @@ -110,28 +95,31 @@ fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio None } }); - + let receiver = receiver.peel_borrows(); let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) && path.ident.name == sym!(insert) { - Some(InsertExpr { receiver, value }) - } else { - None + if value.span.eq_ctxt(expr.span) + && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) + && path.ident.name == symbol + { + return Some(OpExpr { receiver, value, span }); } - } else { - None } + None } -fn find_insert_calls<'tcx>(cx: &LateContext<'tcx>, contains_expr: &ContainsExpr<'tcx>, expr: &'tcx Expr<'_>) -> bool { +fn find_insert_calls<'tcx>( + cx: &LateContext<'tcx>, + contains_expr: &OpExpr<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option> { for_each_expr(expr, |e| { - if let Some(insert_expr) = try_parse_insert(cx, e) + 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) { - ControlFlow::Break(()) + ControlFlow::Break(insert_expr) } else { ControlFlow::Continue(()) } }) - .is_some() } diff --git a/tests/ui/hashset_insert_after_contains.stderr b/tests/ui/hashset_insert_after_contains.stderr deleted file mode 100644 index d547dfa5c1a3..000000000000 --- a/tests/ui/hashset_insert_after_contains.stderr +++ /dev/null @@ -1,112 +0,0 @@ -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:18:5 - | -LL | / if !set.contains(&value) { -LL | | set.insert(value); -LL | | println!("Just a comment"); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:18:13 - | -LL | if !set.contains(&value) { - | ^^^^^^^^^^^^^^^^ - = note: `-D clippy::hashset-insert-after-contains` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::hashset_insert_after_contains)]` - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:23:5 - | -LL | / if set.contains(&value) { -LL | | set.insert(value); -LL | | println!("Just a comment"); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:23:12 - | -LL | if set.contains(&value) { - | ^^^^^^^^^^^^^^^^ - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:28:5 - | -LL | / if !set.contains(&value) { -LL | | set.insert(value); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:28:13 - | -LL | if !set.contains(&value) { - | ^^^^^^^^^^^^^^^^ - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:32:5 - | -LL | / if !!set.contains(&value) { -LL | | set.insert(value); -LL | | println!("Just a comment"); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:32:14 - | -LL | if !!set.contains(&value) { - | ^^^^^^^^^^^^^^^^ - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:37:5 - | -LL | / if (&set).contains(&value) { -LL | | set.insert(value); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:37:15 - | -LL | if (&set).contains(&value) { - | ^^^^^^^^^^^^^^^^ - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:42:5 - | -LL | / if !set.contains(borrow_value) { -LL | | set.insert(*borrow_value); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:42:13 - | -LL | if !set.contains(borrow_value) { - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/hashset_insert_after_contains.rs:47:5 - | -LL | / if !borrow_set.contains(&value) { -LL | | borrow_set.insert(value); -LL | | } - | |_____^ - | - = note: `HashSet::insert` returns whether it was inserted -help: remove the `HashSet::contains` call - --> tests/ui/hashset_insert_after_contains.rs:47:20 - | -LL | if !borrow_set.contains(&value) { - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui/hashset_insert_after_contains.rs b/tests/ui/set_contains_or_insert.rs similarity index 89% rename from tests/ui/hashset_insert_after_contains.rs rename to tests/ui/set_contains_or_insert.rs index 11e4cde84d64..8465007402ab 100644 --- a/tests/ui/hashset_insert_after_contains.rs +++ b/tests/ui/set_contains_or_insert.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![allow(clippy::nonminimal_bool)] #![allow(clippy::needless_borrow)] -#![warn(clippy::hashset_insert_after_contains)] +#![warn(clippy::set_contains_or_insert)] use std::collections::HashSet; @@ -70,6 +70,12 @@ fn should_not_warn_cases() { set.replace(value); //it is not insert println!("Just a comment"); } + + if set.contains(&value) { + println!("value is already in set"); + } else { + set.insert(value); + } } fn simply_true() -> bool { diff --git a/tests/ui/set_contains_or_insert.stderr b/tests/ui/set_contains_or_insert.stderr new file mode 100644 index 000000000000..507e20964fc2 --- /dev/null +++ b/tests/ui/set_contains_or_insert.stderr @@ -0,0 +1,61 @@ +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:18:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::set-contains-or-insert` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]` + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:23:12 + | +LL | if set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:28:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:32:14 + | +LL | if !!set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:37:15 + | +LL | if (&set).contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:42:13 + | +LL | if !set.contains(borrow_value) { + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | set.insert(*borrow_value); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:47:20 + | +LL | if !borrow_set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | borrow_set.insert(value); + | ^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + From eff6f68caf08a5c055778150e2154e3061e002a2 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Wed, 3 Jul 2024 19:40:05 +0100 Subject: [PATCH 074/361] Fix typos --- clippy_lints/src/set_contains_or_insert.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index d6b6f655ac36..cf8ad0935e8c 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// /// ### Known problems /// In case the value that wants to be inserted is borrowed and also expensive or impossible - /// to clone. In such scenario, the developer might want to check with `contain` before inserting, + /// to clone. In such a scenario, the developer might want to check with `contains` before inserting, /// to avoid the clone. In this case, it will report a false positive. /// /// ### Example From b4149c6ad479cb35006355a1f1a3c0992a9f8b0e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 3 Jul 2024 13:45:37 -0500 Subject: [PATCH 075/361] Move unique_thread_exit call to lang_start_internal so it is not in a generic function, and wrap it in `catch_unwind` --- library/std/src/rt.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 376bf3440693..8a6f3fe291a7 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -144,6 +144,10 @@ fn lang_start_internal( rtabort!("drop of the panic payload panicked"); }); panic::catch_unwind(cleanup).map_err(rt_abort)?; + // Guard against multple threads calling `libc::exit` concurrently. + // See the documentation for `unique_thread_exit` for more information. + panic::catch_unwind(|| crate::sys::common::exit_guard::unique_thread_exit()) + .map_err(rt_abort)?; ret_code } @@ -161,8 +165,5 @@ fn lang_start( argv, sigpipe, ); - // Guard against multple threads calling `libc::exit` concurrently. - // See the documentation for `unique_thread_exit` for more information. - crate::sys::common::exit_guard::unique_thread_exit(); v } From 4e71fc4302898e28d7e4c570edf2f3d1feffe116 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Wed, 3 Jul 2024 19:54:02 +0100 Subject: [PATCH 076/361] Small fix after rebase --- clippy_lints/src/set_contains_or_insert.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index cf8ad0935e8c..5e65b9fa5171 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -112,7 +112,7 @@ fn find_insert_calls<'tcx>( contains_expr: &OpExpr<'tcx>, expr: &'tcx Expr<'_>, ) -> Option> { - for_each_expr(expr, |e| { + for_each_expr(cx, expr, |e| { 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) From 903874d2f49d615505cb5940c2fd2b12b330d573 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 1 Jul 2024 13:49:16 +0200 Subject: [PATCH 077/361] `needless_return`: Support `#[expect]` on the return statement --- clippy_lints/src/returns.rs | 47 ++++++++++++++++++++++++++------- tests/ui/needless_return.fixed | 35 +++++++++++++++++++++--- tests/ui/needless_return.rs | 35 +++++++++++++++++++++--- tests/ui/needless_return.stderr | 28 ++++++++++---------- 4 files changed, 116 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index c11da3147ef4..8ced47b48a43 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -7,6 +7,7 @@ use clippy_utils::{ path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; +use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; @@ -14,13 +15,13 @@ use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, }; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{sym, BytePos, Pos, Span}; use std::borrow::Cow; use std::fmt::Display; @@ -80,6 +81,9 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_RETURN, + // This lint requires some special handling in `check_final_expr` for `#[expect]`. + // This handling needs to be updated if the group gets changed. This should also + // be caught by tests. style, "using a return statement like `return expr;` where an expression would suffice" } @@ -91,6 +95,9 @@ declare_clippy_lint! { /// ### Why is this bad? /// The `return` is unnecessary. /// + /// Returns may be used to add attributes to the return expression. Return + /// statements with attributes are therefore be accepted by this lint. + /// /// ### Example /// ```rust,ignore /// fn foo(x: usize) -> Result<(), Box> { @@ -377,13 +384,39 @@ fn check_final_expr<'tcx>( } }; - if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { - return; - } let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); if borrows { return; } + if ret_span.from_expansion() { + return; + } + + // Returns may be used to turn an expression into a statement in rustc's AST. + // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) + // `#[expect(clippy::needless_return)]` needs to be handled separatly to + // actually fullfil the expectation (clippy::#12998) + match cx.tcx.hir().attrs(expr.hir_id) { + [] => {}, + [attr] => { + if matches!(Level::from_attr(attr), Some(Level::Expect(_))) + && let metas = attr.meta_item_list() + && let Some(lst) = metas + && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice() + && let [tool, lint_name] = meta_item.path.segments.as_slice() + && tool.ident.name == sym::clippy + && matches!( + lint_name.ident.name.as_str(), + "needless_return" | "style" | "all" | "warnings" + ) + { + // This is an expectation of the `needless_return` lint + } else { + return; + } + }, + _ => return, + } emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); }, @@ -415,10 +448,6 @@ fn emit_return_lint( replacement: &RetReplacement<'_>, at: HirId, ) { - if ret_span.from_expansion() { - return; - } - span_lint_hir_and_then( cx, NEEDLESS_RETURN, diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 853f685f04c7..fc4129e1db84 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -228,12 +228,41 @@ fn needless_return_macro() -> String { format!("Hello {}", "world!") } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index e9c1e0e8ae8e..61c7a02008f0 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -236,12 +236,41 @@ fn needless_return_macro() -> String { return format!("Hello {}", "world!"); } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 6c891fe7ad3f..ea9c230eafd2 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:248:9 + --> tests/ui/needless_return.rs:277:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:250:9 + --> tests/ui/needless_return.rs:279:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:257:13 + --> tests/ui/needless_return.rs:286:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:260:13 + --> tests/ui/needless_return.rs:289:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:268:9 + --> tests/ui/needless_return.rs:297:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:275:13 + --> tests/ui/needless_return.rs:304:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:277:13 + --> tests/ui/needless_return.rs:306:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:284:20 + --> tests/ui/needless_return.rs:313:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:291:20 + --> tests/ui/needless_return.rs:320:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:303:9 + --> tests/ui/needless_return.rs:332:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:305:9 + --> tests/ui/needless_return.rs:334:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:311:9 + --> tests/ui/needless_return.rs:340:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:315:9 + --> tests/ui/needless_return.rs:344:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:336:5 + --> tests/ui/needless_return.rs:365:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 9b7227cf3f2083d258230f50a25a7b65481a3f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 21:03:37 +0000 Subject: [PATCH 078/361] Properly handle removal suggestion rendering Do not leave a `+ ` line with only whitespace. In reality, the user will want to remove the entire line. --- tests/ui/dbg_macro/dbg_macro.stderr | 2 -- tests/ui/dbg_macro/dbg_macro_unfixable.stderr | 1 - tests/ui/manual_split_once.stderr | 10 ---------- tests/ui/significant_drop_tightening.stderr | 2 -- 4 files changed, 15 deletions(-) diff --git a/tests/ui/dbg_macro/dbg_macro.stderr b/tests/ui/dbg_macro/dbg_macro.stderr index 86667701da0f..7d3c3f7c918e 100644 --- a/tests/ui/dbg_macro/dbg_macro.stderr +++ b/tests/ui/dbg_macro/dbg_macro.stderr @@ -86,7 +86,6 @@ LL | dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool @@ -146,7 +145,6 @@ LL | expand_to_dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr index d21595c2fcd4..16e51f4742e3 100644 --- a/tests/ui/dbg_macro/dbg_macro_unfixable.stderr +++ b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr @@ -9,7 +9,6 @@ LL | dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index b4e51f473cf4..c5c9be3ac63d 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -96,12 +96,10 @@ LL | let (l, r) = "a.b.c".split_once('.').unwrap(); help: remove the `iter` usages | LL - let l = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let r = iter.next().unwrap(); -LL + | error: manual implementation of `split_once` @@ -121,12 +119,10 @@ LL | let (l, r) = "a.b.c".split_once('.')?; help: remove the `iter` usages | LL - let l = iter.next()?; -LL + | help: remove the `iter` usages | LL - let r = iter.next()?; -LL + | error: manual implementation of `rsplit_once` @@ -146,12 +142,10 @@ LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap(); help: remove the `iter` usages | LL - let r = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let l = iter.next().unwrap(); -LL + | error: manual implementation of `rsplit_once` @@ -171,12 +165,10 @@ LL | let (l, r) = "a.b.c".rsplit_once('.')?; help: remove the `iter` usages | LL - let r = iter.next()?; -LL + | help: remove the `iter` usages | LL - let l = iter.next()?; -LL + | error: manual implementation of `split_once` @@ -202,12 +194,10 @@ LL | let (a, b) = "a.b.c".split_once('.').unwrap(); help: remove the `iter` usages | LL - let a = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let b = iter.next().unwrap(); -LL + | error: aborting due to 19 previous errors diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index f818a14cbe68..5fc66279f00e 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -64,7 +64,6 @@ LL + let rslt0 = mutex.lock().unwrap().abs(); help: remove separated single usage | LL - let rslt0 = lock.abs(); -LL + | error: temporary with significant `Drop` can be early dropped @@ -88,7 +87,6 @@ LL + mutex.lock().unwrap().clear(); help: remove separated single usage | LL - lock.clear(); -LL + | error: aborting due to 4 previous errors From 378962f861ccf98ea33f41dee30282e1ad1c5feb Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Mon, 29 Apr 2024 12:39:31 +0800 Subject: [PATCH 079/361] Lint significant drop on `while let` and `if let` --- clippy_lints/src/matches/mod.rs | 13 +- .../matches/significant_drop_in_scrutinee.rs | 111 ++++++++++++++---- tests/ui/significant_drop_in_scrutinee.rs | 26 ++++ tests/ui/significant_drop_in_scrutinee.stderr | 29 ++++- 4 files changed, 149 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index bf7156cc53ec..22a299ae3d82 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [ ]); impl<'tcx> LateLintPass<'tcx> for Matches { + #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) { return; @@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { - significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); + significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source); } collapsible_match::check_match(cx, arms, &self.msrv); @@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); + significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { if self.msrv.meets(msrvs::MATCHES_MACRO) { @@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches { ); needless_match::check_if_let(cx, expr, &if_let); } - } else if !from_expansion { - redundant_pattern_match::check(cx, expr); + } else { + if let Some(while_let) = higher::WhileLet::hir(expr) { + significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then); + } + if !from_expansion { + redundant_pattern_match::check(cx, expr); + } } } diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 2f72e59834fa..9047c9627d9a 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; -pub(super) fn check<'tcx>( +pub(super) fn check_match<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, scrutinee: &'tcx Expr<'_>, @@ -27,10 +27,89 @@ pub(super) fn check<'tcx>( return; } - let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source); + let scrutinee = match (source, &scrutinee.kind) { + (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, + _ => scrutinee, + }; + + let message = if source == MatchSource::Normal { + "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" + } else { + "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" + }; + + let arms = arms.iter().map(|arm| arm.body).collect::>(); + + check(cx, expr, scrutinee, &arms, message, Suggestion::Emit); +} + +pub(super) fn check_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + if_then: &'tcx Expr<'_>, + if_else: Option<&'tcx Expr<'_>>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + let message = + "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression"; + + if let Some(if_else) = if_else { + check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit); + } else { + check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit); + } +} + +pub(super) fn check_while_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + check( + cx, + expr, + scrutinee, + &[body], + "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression", + // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply + // moving it out. We need to change the `while` to a `loop` instead. + Suggestion::DontEmit, + ); +} + +#[derive(Copy, Clone, Debug)] +enum Suggestion { + Emit, + DontEmit, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + arms: &[&'tcx Expr<'_>], + message: &'static str, + sugg: Suggestion, +) { + let mut helper = SigDropHelper::new(cx); + let suggestions = helper.find_sig_drop(scrutinee); + for found in suggestions { span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { - set_diagnostic(diag, cx, expr, found); + match sugg { + Suggestion::Emit => set_suggestion(diag, cx, expr, found), + Suggestion::DontEmit => (), + } + let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); diag.span_label(s, "temporary lives until here"); for span in has_significant_drop_in_arms(cx, arms) { @@ -41,7 +120,7 @@ pub(super) fn check<'tcx>( } } -fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { +fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { let original = snippet(cx, found.found_span, ".."); let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); @@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: & ); } -/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that -/// may have a surprising lifetime. -fn has_significant_drop_in_scrutinee<'tcx>( - cx: &LateContext<'tcx>, - scrutinee: &'tcx Expr<'tcx>, - source: MatchSource, -) -> (Vec, &'static str) { - let mut helper = SigDropHelper::new(cx); - let scrutinee = match (source, &scrutinee.kind) { - (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, - _ => scrutinee, - }; - let message = if source == MatchSource::Normal { - "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" - } else { - "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" - }; - (helper.find_sig_drop(scrutinee), message) -} - struct SigDropChecker<'a, 'tcx> { seen_types: FxHashSet>, cx: &'a LateContext<'tcx>, @@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { } } -fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet { let mut helper = ArmSigDropHelper::new(cx); for arm in arms { - helper.visit_expr(arm.body); + helper.visit_expr(arm); } helper.found_sig_drop_spans } diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 8ee15440ccf0..0db6fbfb7be9 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -801,4 +801,30 @@ fn should_not_trigger_lint_with_explicit_drop() { } } +fn should_trigger_lint_in_if_let() { + let mutex = Mutex::new(vec![1]); + + if let Some(val) = mutex.lock().unwrap().first().copied() { + //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } + + // Should not trigger lint without the final `copied()`, because we actually hold a reference + // (i.e., the `val`) to the locked data. + if let Some(val) = mutex.lock().unwrap().first() { + println!("{}", val); + }; +} + +fn should_trigger_lint_in_while_let() { + let mutex = Mutex::new(vec![1]); + + while let Some(val) = mutex.lock().unwrap().pop() { + //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } +} + fn main() {} diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 4a483e79d8ad..c0c93cd10c02 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -541,5 +541,32 @@ LL ~ let value = mutex.lock().unwrap()[0]; LL ~ for val in [value, 2] { | -error: aborting due to 27 previous errors +error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:807:24 + | +LL | if let Some(val) = mutex.lock().unwrap().first().copied() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().first().copied(); +LL ~ if let Some(val) = value { + | + +error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:823:27 + | +LL | while let Some(val) = mutex.lock().unwrap().pop() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior + +error: aborting due to 29 previous errors From 3a712238127424ca7e40f900bc40252f46627c2f Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Thu, 4 Jul 2024 15:56:11 +0800 Subject: [PATCH 080/361] [`missing_const_for_fn`]: fix suggestions for fn with abi that requires `const_extern_fn` feature --- clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 16 ++++- .../ui/missing_const_for_fn/cant_be_const.rs | 9 +++ .../missing_const_for_fn/could_be_const.fixed | 15 +++++ .../ui/missing_const_for_fn/could_be_const.rs | 15 +++++ .../could_be_const.stderr | 30 ++++++++-- .../could_be_const_with_const_extern_fn.fixed | 14 +++++ .../could_be_const_with_const_extern_fn.rs | 14 +++++ ...could_be_const_with_const_extern_fn.stderr | 59 +++++++++++++++++++ 9 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a5761d3270cd..78fd6149dc09 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -25,7 +25,7 @@ msrv_aliases! { 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO } - 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN } 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,56,0 { CONST_FN_UNION } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bb0d714a31fd..44ec1bd08cf3 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_target::spec::abi::Abi; declare_clippy_lint! { /// ### What it does @@ -115,7 +116,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { .iter() .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); - if already_const(header) || has_const_generic_params { + if already_const(header) + || has_const_generic_params + || !could_be_const_with_abi(cx, &self.msrv, header.abi) + { return; } }, @@ -171,3 +175,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } + +fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool { + match abi { + Abi::Rust => true, + // `const extern "C"` was stablized after 1.62.0 + Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN), + // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled. + _ => cx.tcx.features().const_extern_fn, + } +} diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 2750e0cdf3f7..952ff8283632 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -180,4 +180,13 @@ mod msrv { unsafe { *self.1 as usize } } } + + #[clippy::msrv = "1.61"] + extern "C" fn c() {} +} + +mod with_extern { + extern "C-unwind" fn c_unwind() {} + extern "system" fn system() {} + extern "system-unwind" fn system_unwind() {} } 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 921dcf0b1626..572ca52439a6 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -140,6 +140,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + const extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + const extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { 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 58e639cc7fd1..4d19c4d7a48e 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -140,6 +140,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { 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 8999af761e31..ab36e0a281a7 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -200,7 +200,29 @@ 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:152:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:146:9 + | +LL | extern "C" fn c() {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "C" fn c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:150:9 + | +LL | extern fn implicit_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern fn implicit_c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:167:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -213,7 +235,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:172:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -226,7 +248,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:183:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -239,5 +261,5 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 17 previous errors +error: aborting due to 19 previous errors diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed new file mode 100644 index 000000000000..c103db536ab5 --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +const extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +const extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +const extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs new file mode 100644 index 000000000000..0f7020ae559a --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr new file mode 100644 index 000000000000..036094a367b2 --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr @@ -0,0 +1,59 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1 + | +LL | extern "C-unwind" fn c_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const extern "C-unwind" fn c_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1 + | +LL | extern "system" fn system() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system" fn system() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1 + | +LL | extern "system-unwind" fn system_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system-unwind" fn system_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1 + | +LL | pub extern "stdcall" fn std_call() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall" fn std_call() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1 + | +LL | pub extern "stdcall-unwind" fn std_call_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} + | +++++ + +error: aborting due to 5 previous errors + From fe5581dd31eb1b86c915e5c3eaae9ebfdea28037 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 4 Jul 2024 09:55:00 +0000 Subject: [PATCH 081/361] Fix import suggestion ice --- compiler/rustc_resolve/src/diagnostics.rs | 10 ++--- ...import-ice-issue-127302.edition2015.stderr | 41 +++++++++++++++++++ ...import-ice-issue-127302.edition2021.stderr | 41 +++++++++++++++++++ .../suggest-import-ice-issue-127302.rs | 12 ++++++ ...st-import-issue-120074.edition2015.stderr} | 2 +- ...est-import-issue-120074.edition2021.stderr | 23 +++++++++++ .../ui/imports/suggest-import-issue-120074.rs | 2 + 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr create mode 100644 tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr create mode 100644 tests/ui/imports/suggest-import-ice-issue-127302.rs rename tests/ui/imports/{suggest-import-issue-120074.stderr => suggest-import-issue-120074.edition2015.stderr} (93%) create mode 100644 tests/ui/imports/suggest-import-issue-120074.edition2021.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 50a4e03d233a..7e1251b3a3a5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1989,12 +1989,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(candidate) = candidates.get(0) { let path = { // remove the possible common prefix of the path - let start_index = (0..failed_segment_idx) - .find(|&i| path[i].ident != candidate.path.segments[i].ident) + let len = candidate.path.segments.len(); + let start_index = (0..=failed_segment_idx.min(len - 1)) + .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name) .unwrap_or_default(); - let segments = (start_index..=failed_segment_idx) - .map(|s| candidate.path.segments[s].clone()) - .collect(); + let segments = + (start_index..len).map(|s| candidate.path.segments[s].clone()).collect(); Path { segments, span: Span::default(), tokens: None } }; ( diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr new file mode 100644 index 000000000000..24574c8796b9 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr @@ -0,0 +1,41 @@ +error[E0583]: file not found for module `config` + --> $DIR/suggest-import-ice-issue-127302.rs:3:1 + | +LL | mod config; + | ^^^^^^^^^^^ + | + = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs" + = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead + +error: format argument must be a string literal + --> $DIR/suggest-import-ice-issue-127302.rs:10:14 + | +LL | println!(args.ctx.compiler.display()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", args.ctx.compiler.display()); + | +++++ + +error[E0425]: cannot find value `args` in this scope + --> $DIR/suggest-import-ice-issue-127302.rs:6:12 + | +LL | match &args.cmd { + | ^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::env::args; + | + +error[E0532]: expected unit struct, unit variant or constant, found module `crate::config` + --> $DIR/suggest-import-ice-issue-127302.rs:7:9 + | +LL | crate::config => {} + | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0532, E0583. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr new file mode 100644 index 000000000000..24574c8796b9 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr @@ -0,0 +1,41 @@ +error[E0583]: file not found for module `config` + --> $DIR/suggest-import-ice-issue-127302.rs:3:1 + | +LL | mod config; + | ^^^^^^^^^^^ + | + = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs" + = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead + +error: format argument must be a string literal + --> $DIR/suggest-import-ice-issue-127302.rs:10:14 + | +LL | println!(args.ctx.compiler.display()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", args.ctx.compiler.display()); + | +++++ + +error[E0425]: cannot find value `args` in this scope + --> $DIR/suggest-import-ice-issue-127302.rs:6:12 + | +LL | match &args.cmd { + | ^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::env::args; + | + +error[E0532]: expected unit struct, unit variant or constant, found module `crate::config` + --> $DIR/suggest-import-ice-issue-127302.rs:7:9 + | +LL | crate::config => {} + | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0532, E0583. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.rs b/tests/ui/imports/suggest-import-ice-issue-127302.rs new file mode 100644 index 000000000000..6b8d4c718310 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.rs @@ -0,0 +1,12 @@ +//@ revisions: edition2015 edition2021 + +mod config; //~ ERROR file not found for module + +fn main() { + match &args.cmd { //~ ERROR cannot find value `args` in this scope + crate::config => {} //~ ERROR expected unit struct, unit variant or constant, found module `crate::config` + } + + println!(args.ctx.compiler.display()); + //~^ ERROR format argument must be a string literal +} diff --git a/tests/ui/imports/suggest-import-issue-120074.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr similarity index 93% rename from tests/ui/imports/suggest-import-issue-120074.stderr rename to tests/ui/imports/suggest-import-issue-120074.edition2015.stderr index c1dff93bbdbf..414eeee0fedc 100644 --- a/tests/ui/imports/suggest-import-issue-120074.stderr +++ b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: unresolved import - --> $DIR/suggest-import-issue-120074.rs:10:35 + --> $DIR/suggest-import-issue-120074.rs:12:35 | LL | println!("Hello, {}!", crate::bar::do_the_thing); | ^^^ unresolved import diff --git a/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr new file mode 100644 index 000000000000..414eeee0fedc --- /dev/null +++ b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr @@ -0,0 +1,23 @@ +error[E0433]: failed to resolve: unresolved import + --> $DIR/suggest-import-issue-120074.rs:12:35 + | +LL | println!("Hello, {}!", crate::bar::do_the_thing); + | ^^^ unresolved import + | +help: a similar path exists + | +LL | println!("Hello, {}!", crate::foo::bar::do_the_thing); + | ~~~~~~~~ +help: consider importing this module + | +LL + use foo::bar; + | +help: if you import `bar`, refer to it directly + | +LL - println!("Hello, {}!", crate::bar::do_the_thing); +LL + println!("Hello, {}!", bar::do_the_thing); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs index a798e9eeeb80..7b6b5c73103a 100644 --- a/tests/ui/imports/suggest-import-issue-120074.rs +++ b/tests/ui/imports/suggest-import-issue-120074.rs @@ -1,3 +1,5 @@ +//@ revisions: edition2015 edition2021 + pub mod foo { pub mod bar { pub fn do_the_thing() -> usize { From 88c4a224807144b535854b53fbd46e6dc18555a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 4 Jan 2023 09:31:12 +0100 Subject: [PATCH 082/361] New Lint: `byte_char_slices` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a new lint that checks for potentially harder to read byte char slices: `&[b'a', b'b']` and suggests to replace them with the easier to read `b"ab"` form. Signed-Off-By: Marcel Müller Co-authored-by: Matthias Beyer Use iterator to skip validation Signed-off-by: Marcel Müller Suggested-by: Alex Macleod Convert quote escapes to proper form Signed-off-by: Marcel Müller Add more convertable test cases Signed-off-by: Marcel Müller --- CHANGELOG.md | 1 + clippy_lints/src/byte_char_slices.rs | 80 ++++++++++++++++++++++++++++ clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + tests/ui/byte_char_slices.fixed | 13 +++++ tests/ui/byte_char_slices.rs | 13 +++++ tests/ui/byte_char_slices.stderr | 38 +++++++++++++ 7 files changed, 148 insertions(+) create mode 100644 clippy_lints/src/byte_char_slices.rs create mode 100644 tests/ui/byte_char_slices.fixed create mode 100644 tests/ui/byte_char_slices.rs create mode 100644 tests/ui/byte_char_slices.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b3ea9f2213..d919b521e715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5236,6 +5236,7 @@ Released 2018-09-13 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs new file mode 100644 index 000000000000..a9fe190f1777 --- /dev/null +++ b/clippy_lints/src/byte_char_slices.rs @@ -0,0 +1,80 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_ast::token::{Lit, LitKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for hard to read slices of byte characters, that could be more easily expressed as a + /// byte string. + /// + /// ### Why is this bad? + /// + /// Potentially makes the string harder to read. + /// + /// ### Example + /// ```ignore + /// &[b'H', b'e', b'l', b'l', b'o']; + /// ``` + /// Use instead: + /// ```ignore + /// b"Hello" + /// ``` + #[clippy::version = "1.68.0"] + pub BYTE_CHAR_SLICES, + style, + "hard to read byte char slice" +} +declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]); + +impl EarlyLintPass for ByteCharSlice { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let Some(slice) = is_byte_char_slices(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + BYTE_CHAR_SLICES, + expr.span, + "can be more succinctly written as a byte str", + "try", + format!("b\"{slice}\""), + Applicability::MaybeIncorrect, + ); + } + } +} + +fn is_byte_char_slices(expr: &Expr) -> Option { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind { + match &expr.kind { + ExprKind::Array(members) => { + if members.is_empty() { + return None; + } + + members + .iter() + .map(|member| match &member.kind { + ExprKind::Lit(Lit { + kind: LitKind::Byte, + symbol, + .. + }) => Some(symbol.as_str()), + _ => None, + }) + .map(|maybe_quote| match maybe_quote { + Some("\"") => Some("\\\""), + Some("\\'") => Some("'"), + other => other, + }) + .collect::>() + }, + _ => None, + } + } else { + None + } +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ef5dfd3ee32c..50661bf46a0a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -73,6 +73,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO, crate::borrow_deref_ref::BORROW_DEREF_REF_INFO, crate::box_default::BOX_DEFAULT_INFO, + crate::byte_char_slices::BYTE_CHAR_SLICES_INFO, crate::cargo::CARGO_COMMON_METADATA_INFO, crate::cargo::LINT_GROUPS_PRIORITY_INFO, crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1747d5085597..8a9d3b43fb3a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -89,6 +89,7 @@ mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; mod box_default; +mod byte_char_slices; mod cargo; mod casts; mod checked_conversions; @@ -1174,6 +1175,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains)); + store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/byte_char_slices.fixed b/tests/ui/byte_char_slices.fixed new file mode 100644 index 000000000000..d1db58f9363e --- /dev/null +++ b/tests/ui/byte_char_slices.fixed @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = b"abc"; + let quotes = b"\"Hi"; + let quotes = b"'Sup"; + let escapes = b"\x42Esc"; + + let good = &[b'a', 0x42]; + let good = [b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/tests/ui/byte_char_slices.rs b/tests/ui/byte_char_slices.rs new file mode 100644 index 000000000000..18648fffceb4 --- /dev/null +++ b/tests/ui/byte_char_slices.rs @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = &[b'a', b'b', b'c']; + let quotes = &[b'"', b'H', b'i']; + let quotes = &[b'\'', b'S', b'u', b'p']; + let escapes = &[b'\x42', b'E', b's', b'c']; + + let good = &[b'a', 0x42]; + let good = vec![b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/tests/ui/byte_char_slices.stderr b/tests/ui/byte_char_slices.stderr new file mode 100644 index 000000000000..4e2b5d8a7329 --- /dev/null +++ b/tests/ui/byte_char_slices.stderr @@ -0,0 +1,38 @@ +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:5:15 + | +LL | let bad = &[b'a', b'b', b'c']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"` + | + = note: `-D clippy::byte-char-slices` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:6:18 + | +LL | let quotes = &[b'"', b'H', b'i']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:7:18 + | +LL | let quotes = &[b'\'', b'S', b'u', b'p']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:8:19 + | +LL | let escapes = &[b'\x42', b'E', b's', b'c']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` + +error: useless use of `vec!` + --> tests/ui/byte_char_slices.rs:11:16 + | +LL | let good = vec![b'a', b'a']; + | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 5 previous errors + From 937b5c459464e39e2c541a48b9c8118ca6b98b46 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 4 Jul 2024 17:09:36 +0300 Subject: [PATCH 083/361] remove leading space on `frame-pointers` Leading spaces in config options cause `configure` script to fail. Signed-off-by: onur-ozkan --- config.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.example.toml b/config.example.toml index 679abcdc7771..ae5f991263b5 100644 --- a/config.example.toml +++ b/config.example.toml @@ -609,7 +609,7 @@ # Forces frame pointers to be used with `-Cforce-frame-pointers`. # This can be helpful for profiling at a small performance cost. -# frame-pointers = false +#frame-pointers = false # Indicates whether stack protectors should be used # via the unstable option `-Zstack-protector`. From 2d33d7bc6236b2c9add0aec9befa1459ef160583 Mon Sep 17 00:00:00 2001 From: Konstantinos Andrikopoulos Date: Sat, 22 Jun 2024 16:36:54 +0200 Subject: [PATCH 084/361] Run tests for all specified targets Currently cargo-miri uses the first target specified in the command line. However, when multiple targets are specified in a `cargo build` invocation, cargo will build for all of them. Miri should match this behaviour to reduce surprises. Fixes: #3460 --- src/tools/miri/cargo-miri/src/phases.rs | 26 +++++++++++++------ src/tools/miri/ci/ci.sh | 4 ++- src/tools/miri/test-cargo-miri/run-test.py | 20 ++++++++++++-- .../test.multiple_targets.stdout.ref | 22 ++++++++++++++++ 4 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 8d48b9c8ad14..3743446e2764 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -104,9 +104,17 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { miri_for_host() ) }); - let host = &rustc_version.host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(host); + let mut targets = get_arg_flag_values("--target").collect::>(); + // If `targets` is empty, we need to add a `--target $HOST` flag ourselves, and also ensure + // that the host target is indeed setup. + let target_flag = if targets.is_empty() { + let host = &rustc_version.host; + targets.push(host.clone()); + Some(host) + } else { + // We don't need to add a `--target` flag, we just forward the user's flags. + None + }; // If cleaning the target directory & sysroot cache, // delete them then exit. There is no reason to setup a new @@ -118,8 +126,11 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { return; } - // We always setup. - let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose, quiet); + for target in &targets { + // We always setup. + setup(&subcommand, target.as_str(), &rustc_version, verbose, quiet); + } + let miri_sysroot = get_sysroot_dir(); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -155,10 +166,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // No target given. Explicitly pick the host. + if let Some(target_flag) = target_flag { cmd.arg("--target"); - cmd.arg(host); + cmd.arg(target_flag); } // Set ourselves as runner for al binaries invoked by cargo. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 67985f9b7d6e..5e75638f4670 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -41,9 +41,11 @@ function run_tests { if [ -n "${TEST_TARGET-}" ]; then begingroup "Testing foreign architecture $TEST_TARGET" TARGET_FLAG="--target $TEST_TARGET" + MULTI_TARGET_FLAG="" else begingroup "Testing host architecture" TARGET_FLAG="" + MULTI_TARGET_FLAG="--multi-target" fi ## ui test suite @@ -93,7 +95,7 @@ function run_tests { echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml fi # Run the actual test - time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG + time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG $MULTI_TARGET_FLAG # Clean up unset RUSTC MIRI rm -rf .cargo diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index d855c333a756..5b77092979d3 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -22,12 +22,17 @@ def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) -def cargo_miri(cmd, quiet = True): +def cargo_miri(cmd, quiet = True, targets = None): args = ["cargo", "miri", cmd] + CARGO_EXTRA_FLAGS if quiet: args += ["-q"] - if ARGS.target: + + if targets is not None: + for target in targets: + args.extend(("--target", target)) + elif ARGS.target is not None: args += ["--target", ARGS.target] + return args def normalize_stdout(str): @@ -186,10 +191,21 @@ def test_cargo_miri_test(): default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) + if ARGS.multi_target: + test_cargo_miri_multi_target() + + +def test_cargo_miri_multi_target(): + test("`cargo miri test` (multiple targets)", + cargo_miri("test", targets = ["aarch64-unknown-linux-gnu", "s390x-unknown-linux-gnu"]), + "test.multiple_targets.stdout.ref", "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + ) args_parser = argparse.ArgumentParser(description='`cargo miri` testing') args_parser.add_argument('--target', help='the target to test') args_parser.add_argument('--bless', help='bless the reference files', action='store_true') +args_parser.add_argument('--multi-target', help='run tests related to multiple targets', action='store_true') ARGS = args_parser.parse_args() os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref new file mode 100644 index 000000000000..567c5db07d06 --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -0,0 +1,22 @@ + +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +imported main +imported main + +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + From c5e9513aa2aee071d05bdf0acae9c110aaa040ff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 20 Jun 2024 01:27:42 -0500 Subject: [PATCH 085/361] Refactor float casting tests This is an attempt to remove the magic from a lot of the numbers tested, which should make things easier when it is time to add `f16` and `f128`. A nice side effect is that these tests now cover all int <-> float conversions with the same amount of tests. Co-authored-by: Ralf Jung --- src/tools/miri/tests/pass/float.rs | 570 ++++++++++++++++++++--------- 1 file changed, 387 insertions(+), 183 deletions(-) diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 5464627fa144..a4589847fc1f 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -4,8 +4,11 @@ #![feature(f128)] #![feature(f16)] #![allow(arithmetic_overflow)] +#![allow(internal_features)] -use std::fmt::Debug; +use std::any::type_name; +use std::cmp::min; +use std::fmt::{Debug, Display, LowerHex}; use std::hint::black_box; use std::{f32, f64}; @@ -29,15 +32,39 @@ fn main() { test_algebraic(); } -// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. -// Doesn't make a big difference when running this in Miri, but it means we can compare this -// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. -#[track_caller] -#[inline(never)] -fn assert_eq(x: T, y: T) { - assert_eq!(x, y); +trait Float: Copy + PartialEq + Debug { + /// The unsigned integer with the same bit width as this float + type Int: Copy + PartialEq + LowerHex + Debug; + const BITS: u32 = size_of::() as u32 * 8; + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + const SIGNIFICAND_BITS: u32; + + /// The saturated (all ones) value of the exponent (infinity representation) + const EXPONENT_SAT: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value (max representable positive exponent) + const EXPONENT_BIAS: u32 = Self::EXPONENT_SAT >> 1; + + fn to_bits(self) -> Self::Int; } +macro_rules! impl_float { + ($ty:ty, $ity:ty) => { + impl Float for $ty { + type Int = $ity; + // Just get this from std's value, which includes the implicit digit + const SIGNIFICAND_BITS: u32 = <$ty>::MANTISSA_DIGITS - 1; + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + } + }; +} + +impl_float!(f32, u32); +impl_float!(f64, u64); + trait FloatToInt: Copy { fn cast(self) -> Int; unsafe fn cast_unchecked(self) -> Int; @@ -64,13 +91,53 @@ float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] -fn test_both_cast(x: F, y: I) +fn test_both_cast(x: F, y: I, msg: impl Display) where F: FloatToInt, I: PartialEq + Debug, { - assert_eq!(x.cast(), y); - assert_eq!(unsafe { x.cast_unchecked() }, y); + let f_tname = type_name::(); + let i_tname = type_name::(); + assert_eq!(x.cast(), y, "{f_tname} -> {i_tname}: {msg}"); + assert_eq!(unsafe { x.cast_unchecked() }, y, "{f_tname} -> {i_tname}: {msg}",); +} + +/// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. +/// Doesn't make a big difference when running this in Miri, but it means we can compare this +/// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. +#[track_caller] +#[inline(never)] +fn assert_eq(x: T, y: T) { + assert_eq!(x, y); +} + +/// The same as `assert_eq` except prints a specific message on failure +#[track_caller] +#[inline(never)] +fn assert_eq_msg(x: T, y: T, msg: impl Display) { + assert_eq!(x, y, "{msg}"); +} + +/// Check that floats have bitwise equality +fn assert_biteq(a: F, b: F, msg: impl Display) { + let ab = a.to_bits(); + let bb = b.to_bits(); + let tname = type_name::(); + let width = (2 + F::BITS / 4) as usize; + assert_eq_msg::( + ab, + bb, + format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}"), + ); +} + +/// Check that two floats have equality +fn assert_feq(a: F, b: F, msg: impl Display) { + let ab = a.to_bits(); + let bb = b.to_bits(); + let tname = type_name::(); + let width = (2 + F::BITS / 4) as usize; + assert_eq_msg::(a, b, format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}")); } fn basic() { @@ -148,155 +215,316 @@ fn basic() { assert_eq!(34.2f64.abs(), 34.2f64); } -/// Many of these test values are taken from +/// Test casts from floats to ints and back +macro_rules! test_ftoi_itof { + ( + f: $fty:ty, + i: $ity:ty, + // Int min and max as float literals + imin_f: $imin_f:literal, + imax_f: $imax_f:literal $(,)? + ) => {{ + /// By default we test float to int `as` casting as well as to_int_unchecked + fn assert_ftoi(f: $fty, i: $ity, msg: &str) { + #[allow(unused_comparisons)] + if <$ity>::MIN >= 0 && f < 0.0 { + // If `ity` is signed and `f` is negative, it is unrepresentable so skip + // unchecked casts. + assert_ftoi_unrep(f, i, msg); + } else { + test_both_cast::<$fty, $ity>(f, i, msg); + } + } + + /// Unrepresentable values only get tested with `as` casting, not unchecked + fn assert_ftoi_unrep(f: $fty, i: $ity, msg: &str) { + assert_eq_msg::<$ity>( + f as $ity, + i, + format_args!("{} -> {}: {msg}", stringify!($fty), stringify!($ity)), + ); + } + + /// Int to float checks + fn assert_itof(i: $ity, f: $fty, msg: &str) { + assert_eq_msg::<$fty>( + i as $fty, + f, + format_args!("{} -> {}: {msg}", stringify!($ity), stringify!($fty)), + ); + } + + /// Check both float to int and int to float + fn assert_bidir(f: $fty, i: $ity, msg: &str) { + assert_ftoi(f, i, msg); + assert_itof(i, f, msg); + } + + /// Check both float to int and int to float for unrepresentable numbers + fn assert_bidir_unrep(f: $fty, i: $ity, msg: &str) { + assert_ftoi_unrep(f, i, msg); + assert_itof(i, f, msg); + } + + let fbits = <$fty>::BITS; + let fsig_bits = <$fty>::SIGNIFICAND_BITS; + let ibits = <$ity>::BITS; + let imax: $ity = <$ity>::MAX; + let imin: $ity = <$ity>::MIN; + let izero: $ity = 0; + #[allow(unused_comparisons)] + let isigned = <$ity>::MIN < 0; + + #[allow(overflowing_literals)] + let imin_f: $fty = $imin_f; + #[allow(overflowing_literals)] + let imax_f: $fty = $imax_f; + + // If an integer can fit entirely in the mantissa (counting the hidden bit), every value + // can be represented exactly. + let all_ints_exact_rep = ibits <= fsig_bits + 1; + + // We can represent the full range of the integer (but possibly not every value) without + // saturating to infinity if `1 << (I::BITS - 1)` (single one in the MSB position) is + // within the float's dynamic range. + let int_range_rep = ibits - 1 < <$fty>::EXPONENT_BIAS; + + // Skip unchecked cast when int min/max would be unrepresentable + let assert_ftoi_big = if all_ints_exact_rep { assert_ftoi } else { assert_ftoi_unrep }; + let assert_bidir_big = if all_ints_exact_rep { assert_bidir } else { assert_bidir_unrep }; + + // Near zero representations + assert_bidir(0.0, 0, "zero"); + assert_ftoi(-0.0, 0, "negative zero"); + assert_ftoi(1.0, 1, "one"); + assert_ftoi(-1.0, izero.saturating_sub(1), "negative one"); + assert_ftoi(1.0 - <$fty>::EPSILON, 0, "1.0 - ε"); + assert_ftoi(1.0 + <$fty>::EPSILON, 1, "1.0 + ε"); + assert_ftoi(-1.0 + <$fty>::EPSILON, 0, "-1.0 + ε"); + assert_ftoi(-1.0 - <$fty>::EPSILON, izero.saturating_sub(1), "-1.0 - ε"); + assert_ftoi(<$fty>::from_bits(0x1), 0, "min subnormal"); + assert_ftoi(<$fty>::from_bits(0x1 | 1 << (fbits - 1)), 0, "min neg subnormal"); + + // Spot checks. Use `saturating_sub` to create negative integers so that unsigned + // integers stay at zero. + assert_ftoi(0.9, 0, "0.9"); + assert_ftoi(-0.9, 0, "-0.9"); + assert_ftoi(1.1, 1, "1.1"); + assert_ftoi(-1.1, izero.saturating_sub(1), "-1.1"); + assert_ftoi(1.9, 1, "1.9"); + assert_ftoi(-1.9, izero.saturating_sub(1), "-1.9"); + assert_ftoi(5.0, 5, "5.0"); + assert_ftoi(-5.0, izero.saturating_sub(5), "-5.0"); + assert_ftoi(5.9, 5, "5.0"); + assert_ftoi(-5.9, izero.saturating_sub(5), "-5.0"); + + // Exercise the middle of the integer's bit range. A power of two fits as long as the + // exponent can fit its log2, so cap at the maximum representable power of two (which + // is the exponent's bias). + let half_i_max: $ity = 1 << min(ibits / 2, <$fty>::EXPONENT_BIAS); + let half_i_min = izero.saturating_sub(half_i_max); + assert_bidir(half_i_max as $fty, half_i_max, "half int max"); + assert_bidir(half_i_min as $fty, half_i_min, "half int min"); + + // Integer limits + assert_bidir_big(imax_f, imax, "i max"); + assert_bidir_big(imin_f, imin, "i min"); + + // We need a small perturbation to test against that does not round up to the next + // integer. `f16` needs a smaller perturbation since it only has resolution for ~1 decimal + // place near 10^3. + let perturb = if fbits < 32 { 0.9 } else { 0.99 }; + assert_ftoi_big(imax_f + perturb, <$ity>::MAX, "slightly above i max"); + assert_ftoi_big(imin_f - perturb, <$ity>::MIN, "slightly below i min"); + + // Tests for when we can represent the integer's magnitude + if int_range_rep { + // If the float can represent values larger than the integer, float extremes + // will saturate. + assert_ftoi_unrep(<$fty>::MAX, imax, "f max"); + assert_ftoi_unrep(<$fty>::MIN, imin, "f min"); + + // Max representable power of 10 + let pow10_max = (10 as $ity).pow(imax.ilog10()); + + // If the power of 10 should be representable (fits in a mantissa), check it + if ibits - pow10_max.leading_zeros() - pow10_max.trailing_zeros() <= fsig_bits + 1 { + assert_bidir(pow10_max as $fty, pow10_max, "pow10 max"); + } + } + + // Test rounding the largest and smallest integers, but skip this when + // all integers have an exact representation (it's less interesting then and the arithmetic gets more complicated). + if int_range_rep && !all_ints_exact_rep { + // The maximum representable integer is a saturated mantissa (including the implicit + // bit), shifted into the int's leftmost position. + // + // Positive signed integers never use their top bit, so shift by one bit fewer. + let sat_mantissa: $ity = (1 << (fsig_bits + 1)) - 1; + let adj = if isigned { 1 } else { 0 }; + let max_rep = sat_mantissa << (sat_mantissa.leading_zeros() - adj); + + // This value should roundtrip exactly + assert_bidir(max_rep as $fty, max_rep, "max representable int"); + + // The cutoff for where to round to `imax` is halfway between the maximum exactly + // representable integer and `imax`. This should round down (to `max_rep`), + // i.e., `max_rep as $fty == max_non_sat as $fty`. + let max_non_sat = max_rep + ((imax - max_rep) / 2); + assert_bidir(max_non_sat as $fty, max_rep, "max non saturating int"); + + // So the next value up should round up to the maximum value of the integer + assert_bidir_unrep((max_non_sat + 1) as $fty, imax, "min infinite int"); + + if isigned { + // Floats can always represent the minimum signed number if they can fit the + // exponent, because it is just a `1` in the MSB. So, no negative int -> float + // conversion will round to negative infinity (if the exponent fits). + // + // Since `imin` is thus the minimum representable value, we test rounding near + // the next value. This happens to be the opposite of the maximum representable + // value, and it should roundtrip exactly. + let next_min_rep = max_rep.wrapping_neg(); + assert_bidir(next_min_rep as $fty, next_min_rep, "min representable above imin"); + + // Following a similar pattern as for positive numbers, halfway between this value + // and `imin` should round back to `next_min_rep`. + let min_non_sat = imin - ((imin - next_min_rep) / 2) + 1; + assert_bidir( + min_non_sat as $fty, + next_min_rep, + "min int that does not round to imin", + ); + + // And then anything else saturates to the minimum value. + assert_bidir_unrep( + (min_non_sat - 1) as $fty, + imin, + "max negative int that rounds to imin", + ); + } + } + + // Check potentially saturating int ranges. (`imax_f` here will be `$fty::INFINITY` if + // it cannot be represented as a finite value.) + assert_itof(imax, imax_f, "imax"); + assert_itof(imin, imin_f, "imin"); + + // Float limits + assert_ftoi_unrep(<$fty>::INFINITY, imax, "f inf"); + assert_ftoi_unrep(<$fty>::NEG_INFINITY, imin, "f neg inf"); + assert_ftoi_unrep(<$fty>::NAN, 0, "f nan"); + assert_ftoi_unrep(-<$fty>::NAN, 0, "f neg nan"); + }}; +} + +/// Test casts from one float to another +macro_rules! test_ftof { + ( + f1: $f1:ty, + f2: $f2:ty $(,)? + ) => {{ + type F2Int = <$f2 as Float>::Int; + + let f1zero: $f1 = 0.0; + let f2zero: $f2 = 0.0; + let f1five: $f1 = 5.0; + let f2five: $f2 = 5.0; + + assert_biteq((f1zero as $f2), f2zero, "0.0"); + assert_biteq(((-f1zero) as $f2), (-f2zero), "-0.0"); + assert_biteq((f1five as $f2), f2five, "5.0"); + assert_biteq(((-f1five) as $f2), (-f2five), "-5.0"); + + assert_feq(<$f1>::INFINITY as $f2, <$f2>::INFINITY, "max -> inf"); + assert_feq(<$f1>::NEG_INFINITY as $f2, <$f2>::NEG_INFINITY, "max -> inf"); + assert!((<$f1>::NAN as $f2).is_nan(), "{} -> {} nan", stringify!($f1), stringify!($f2)); + + let min_sub_casted = <$f1>::from_bits(0x1) as $f2; + let min_neg_sub_casted = <$f1>::from_bits(0x1 | 1 << (<$f1>::BITS - 1)) as $f2; + + if <$f1>::BITS > <$f2>::BITS { + assert_feq(<$f1>::MAX as $f2, <$f2>::INFINITY, "max -> inf"); + assert_feq(<$f1>::MIN as $f2, <$f2>::NEG_INFINITY, "max -> inf"); + assert_biteq(min_sub_casted, f2zero, "min subnormal -> 0.0"); + assert_biteq(min_neg_sub_casted, -f2zero, "min neg subnormal -> -0.0"); + } else { + // When increasing precision, the minimum subnormal will just roll to the next + // exponent. This exponent will be the current exponent (with bias), plus + // `sig_bits - 1` to account for the implicit change in exponent (since the + // mantissa starts with 0). + let sub_casted = <$f2>::from_bits( + ((<$f2>::EXPONENT_BIAS - (<$f1>::EXPONENT_BIAS + <$f1>::SIGNIFICAND_BITS - 1)) + as F2Int) + << <$f2>::SIGNIFICAND_BITS, + ); + assert_biteq(min_sub_casted, sub_casted, "min subnormal"); + assert_biteq(min_neg_sub_casted, -sub_casted, "min neg subnormal"); + } + }}; +} + +/// Many of these test patterns were adapted from the values in /// https://github.com/WebAssembly/testsuite/blob/master/conversions.wast. fn casts() { - // f32 -> i8 - test_both_cast::(127.99, 127); - test_both_cast::(-128.99, -128); + /* int <-> float generic tests */ - // f32 -> i32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); - test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_both_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); - test_both_cast::(1.9, 1); - test_both_cast::(-1.9, -1); - test_both_cast::(5.0, 5); - test_both_cast::(-5.0, -5); - test_both_cast::(2147483520.0, 2147483520); - test_both_cast::(-2147483648.0, -2147483648); - // unrepresentable casts - assert_eq::(2147483648.0f32 as i32, i32::MAX); - assert_eq::(-2147483904.0f32 as i32, i32::MIN); - assert_eq::(f32::MAX as i32, i32::MAX); - assert_eq::(f32::MIN as i32, i32::MIN); - assert_eq::(f32::INFINITY as i32, i32::MAX); - assert_eq::(f32::NEG_INFINITY as i32, i32::MIN); - assert_eq::(f32::NAN as i32, 0); - assert_eq::((-f32::NAN) as i32, 0); + test_ftoi_itof! { f: f32, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f32, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f32, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f32, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f32, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f32, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f32, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f32, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f32, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f32, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f32 -> u32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(-0.9999999, 0); - test_both_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); - test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_both_cast::(1.9, 1); - test_both_cast::(5.0, 5); - test_both_cast::(2147483648.0, 0x8000_0000); - test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); - test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); - test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_both_cast::((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss - // unrepresentable casts - assert_eq::((u32::MAX - 127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable - assert_eq::(4294967296.0f32 as u32, u32::MAX); - assert_eq::(-5.0f32 as u32, 0); - assert_eq::(f32::MAX as u32, u32::MAX); - assert_eq::(f32::MIN as u32, 0); - assert_eq::(f32::INFINITY as u32, u32::MAX); - assert_eq::(f32::NEG_INFINITY as u32, 0); - assert_eq::(f32::NAN as u32, 0); - assert_eq::((-f32::NAN) as u32, 0); + test_ftoi_itof! { f: f64, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f64, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f64, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f64, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f64, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f64, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f64, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f64, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f64, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f64, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f32 -> i64 - test_both_cast::(4294967296.0, 4294967296); - test_both_cast::(-4294967296.0, -4294967296); - test_both_cast::(9223371487098961920.0, 9223371487098961920); - test_both_cast::(-9223372036854775808.0, -9223372036854775808); - - // f64 -> i8 - test_both_cast::(127.99, 127); - test_both_cast::(-128.99, -128); - - // f64 -> i32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::( - /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), - -1, - ); - test_both_cast::(1.9, 1); - test_both_cast::(-1.9, -1); - test_both_cast::(1e8, 100_000_000); - test_both_cast::(2147483647.0, 2147483647); - test_both_cast::(-2147483648.0, -2147483648); - // unrepresentable casts - assert_eq::(2147483648.0f64 as i32, i32::MAX); - assert_eq::(-2147483649.0f64 as i32, i32::MIN); - - // f64 -> i64 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_both_cast::( - /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), - 0, - ); - test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::( - /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), - -1, - ); - test_both_cast::(5.0, 5); - test_both_cast::(5.9, 5); - test_both_cast::(-5.0, -5); - test_both_cast::(-5.9, -5); - test_both_cast::(4294967296.0, 4294967296); - test_both_cast::(-4294967296.0, -4294967296); - test_both_cast::(9223372036854774784.0, 9223372036854774784); - test_both_cast::(-9223372036854775808.0, -9223372036854775808); - // unrepresentable casts - assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); - assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); - assert_eq::(f64::MAX as i64, i64::MAX); - assert_eq::(f64::MIN as i64, i64::MIN); - assert_eq::(f64::INFINITY as i64, i64::MAX); - assert_eq::(f64::NEG_INFINITY as i64, i64::MIN); - assert_eq::(f64::NAN as i64, 0); - assert_eq::((-f64::NAN) as i64, 0); - - // f64 -> u64 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(-0.99999999999, 0); - test_both_cast::(5.0, 5); - test_both_cast::(1e16, 10000000000000000); - test_both_cast::((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss - test_both_cast::(9223372036854775808.0, 9223372036854775808); - // unrepresentable casts - assert_eq::(-5.0f64 as u64, 0); - assert_eq::((u64::MAX - 1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable - assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); - assert_eq::(f64::MAX as u64, u64::MAX); - assert_eq::(f64::MIN as u64, 0); - assert_eq::(f64::INFINITY as u64, u64::MAX); - assert_eq::(f64::NEG_INFINITY as u64, 0); - assert_eq::(f64::NAN as u64, 0); - assert_eq::((-f64::NAN) as u64, 0); - - // f64 -> i128 - assert_eq::(f64::MAX as i128, i128::MAX); - assert_eq::(f64::MIN as i128, i128::MIN); - - // f64 -> u128 - assert_eq::(f64::MAX as u128, u128::MAX); - assert_eq::(f64::MIN as u128, 0); + /* int <-> float spot checks */ // int -> f32 - assert_eq::(127i8 as f32, 127.0); - assert_eq::(2147483647i32 as f32, 2147483648.0); - assert_eq::((-2147483648i32) as f32, -2147483648.0); assert_eq::(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06)); - assert_eq::(16777217i32 as f32, 16777216.0); - assert_eq::((-16777217i32) as f32, -16777216.0); - assert_eq::(16777219i32 as f32, 16777220.0); - assert_eq::((-16777219i32) as f32, -16777220.0); assert_eq::( 0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff), @@ -313,36 +541,23 @@ fn casts() { 0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001), ); - assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation // int -> f64 - assert_eq::(127i8 as f64, 127.0); - assert_eq::(i16::MIN as f64, -32768.0f64); - assert_eq::(2147483647i32 as f64, 2147483647.0); - assert_eq::(-2147483648i32 as f64, -2147483648.0); assert_eq::(987654321i32 as f64, 987654321.0); - assert_eq::(9223372036854775807i64 as f64, 9223372036854775807.0); - assert_eq::(-9223372036854775808i64 as f64, -9223372036854775808.0); assert_eq::(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?) assert_eq::(9007199254740993i64 as f64, 9007199254740992.0); assert_eq::(-9007199254740993i64 as f64, -9007199254740992.0); assert_eq::(9007199254740995i64 as f64, 9007199254740996.0); assert_eq::(-9007199254740995i64 as f64, -9007199254740996.0); - assert_eq::(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... + + /* float -> float generic tests */ + + test_ftof! { f1: f32, f2: f64 }; + test_ftof! { f1: f64, f2: f32 }; + + /* float -> float spot checks */ // f32 -> f64 - assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); - assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); - assert_eq::(5.0f32 as f64, 5.0f64); - assert_eq::( - /*0x1p-149*/ f32::from_bits(0x1) as f64, - /*0x1p-149*/ f64::from_bits(0x36a0000000000000), - ); - assert_eq::( - /*-0x1p-149*/ f32::from_bits(0x80000001) as f64, - /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000), - ); assert_eq::( /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000), @@ -359,15 +574,8 @@ fn casts() { /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37, ); - assert_eq::(f32::INFINITY as f64, f64::INFINITY); - assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); // f64 -> f32 - assert_eq::((0.0f64 as f32).to_bits(), 0.0f32.to_bits()); - assert_eq::(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits()); - assert_eq::(5.0f64 as f32, 5.0f32); - assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); - assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); assert_eq::( /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000), @@ -376,10 +584,6 @@ fn casts() { /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728), ); - assert_eq::(f64::MAX as f32, f32::INFINITY); - assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); - assert_eq::(f64::INFINITY as f32, f32::INFINITY); - assert_eq::(f64::NEG_INFINITY as f32, f32::NEG_INFINITY); } fn ops() { From 93c174985c1b90c22f930dcc43847ff031b35be8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 27 Jun 2024 04:24:35 -0500 Subject: [PATCH 086/361] Add casting tests for `f16` and `f128` --- src/tools/miri/src/intrinsics/mod.rs | 4 +- src/tools/miri/tests/pass/float.rs | 66 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 313eac363372..9cd776c93710 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -392,10 +392,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { bug!("float_finite: non-float input type {}", x.layout.ty) }; Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(), FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(), FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => x.to_scalar().to_f128()?.is_finite(), }) }; match (float_finite(&a)?, float_finite(&b)?) { diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index a4589847fc1f..6ab18a5345ea 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -62,8 +62,10 @@ macro_rules! impl_float { }; } +impl_float!(f16, u16); impl_float!(f32, u32); impl_float!(f64, u64); +impl_float!(f128, u128); trait FloatToInt: Copy { fn cast(self) -> Int; @@ -85,8 +87,10 @@ macro_rules! float_to_int { }; } +float_to_int!(f16 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); +float_to_int!(f128 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -469,6 +473,32 @@ macro_rules! test_ftof { fn casts() { /* int <-> float generic tests */ + test_ftoi_itof! { f: f16, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f16, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f16, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f16, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f16, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f16, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f16, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f16, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f16, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f16, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; + test_ftoi_itof! { f: f32, i: i8, imin_f: -128.0, imax_f: 127.0 }; test_ftoi_itof! { f: f32, i: u8, imin_f: 0.0, imax_f: 255.0 }; test_ftoi_itof! { f: f32, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; @@ -521,6 +551,32 @@ fn casts() { imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 }; + test_ftoi_itof! { f: f128, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f128, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f128, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f128, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f128, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f128, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f128, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f128, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f128, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f128, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; + /* int <-> float spot checks */ // int -> f32 @@ -552,8 +608,18 @@ fn casts() { /* float -> float generic tests */ + test_ftof! { f1: f16, f2: f32 }; + test_ftof! { f1: f16, f2: f64 }; + test_ftof! { f1: f16, f2: f128 }; + test_ftof! { f1: f32, f2: f16 }; test_ftof! { f1: f32, f2: f64 }; + test_ftof! { f1: f32, f2: f128 }; + test_ftof! { f1: f64, f2: f16 }; test_ftof! { f1: f64, f2: f32 }; + test_ftof! { f1: f64, f2: f128 }; + test_ftof! { f1: f128, f2: f16 }; + test_ftof! { f1: f128, f2: f32 }; + test_ftof! { f1: f128, f2: f64 }; /* float -> float spot checks */ From 253436c04c87b7d8dfed2fb14e42a67427196bc1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 4 Jul 2024 21:52:25 +0200 Subject: [PATCH 087/361] Better parsing of #[section_name] on Mach-O This is required by the objc2 crate Fixes rust-lang/rustc_codegen_cranelift#1504 --- src/constant.rs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/constant.rs b/src/constant.rs index 87c5da3b7c3e..77203ece312d 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -383,15 +383,43 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant if let Some(section_name) = section_name { let (segment_name, section_name) = if tcx.sess.target.is_like_osx { - let section_name = section_name.as_str(); - if let Some(names) = section_name.split_once(',') { - names - } else { + // See https://github.com/llvm/llvm-project/blob/main/llvm/lib/MC/MCSectionMachO.cpp + let mut parts = section_name.as_str().split(','); + let Some(segment_name) = parts.next() else { tcx.dcx().fatal(format!( "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", section_name )); + }; + let Some(section_name) = parts.next() else { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", + section_name + )); + }; + if section_name.len() > 16 { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: section name bigger than 16 bytes", + section_name + )); } + let section_type = parts.next().unwrap_or("regular"); + if section_type != "regular" && section_type != "cstring_literals" { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not supported: unsupported section type {}", + section_name, section_type, + )); + } + let _attrs = parts.next(); + if parts.next().is_some() { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: too many components", + section_name + )); + } + // FIXME(bytecodealliance/wasmtime#8901) set S_CSTRING_LITERALS section type when + // cstring_literals is specified + (segment_name, section_name) } else { ("", section_name.as_str()) }; From 5b30f6a1a3fbd78eb810c02787ad8af4956de305 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 17:18:28 -0400 Subject: [PATCH 088/361] `almost_complete_range`: Delay suggestion creation. --- clippy_lints/src/almost_complete_range.rs | 104 +++++++++++++--------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 57a5cd8fba81..96e9c949b750 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -41,61 +40,80 @@ impl AlmostCompleteRange { } impl EarlyLintPass for AlmostCompleteRange { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind { - let ctxt = e.span.ctxt(); - let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) - && let Some(end) = walk_span_to_context(end.span, ctxt) - && self.msrv.meets(msrvs::RANGE_INCLUSIVE) - { - Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) - } else { - None - }; - check_range(cx, e.span, start, end, sugg); + if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), e.span) + { + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + e.span, + "almost complete ascii range", + |diag| { + let ctxt = e.span.ctxt(); + if let Some(start) = walk_span_to_context(start.span, ctxt) + && let Some(end) = walk_span_to_context(end.span, ctxt) + && self.msrv.meets(msrvs::RANGE_INCLUSIVE) + { + diag.span_suggestion( + trim_span(cx.sess().source_map(), start.between(end)), + "use an inclusive range", + "..=".to_owned(), + Applicability::MaybeIncorrect, + ); + } + }, + ); } } fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) { if let PatKind::Range(Some(start), Some(end), kind) = &p.kind && matches!(kind.node, RangeEnd::Excluded) + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), p.span) { - let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { - "..=" - } else { - "..." - }; - check_range(cx, p.span, start, end, Some((kind.span, sugg))); + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + p.span, + "almost complete ascii range", + |diag| { + diag.span_suggestion( + kind.span, + "use an inclusive range", + if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { + "..=".to_owned() + } else { + "...".to_owned() + }, + Applicability::MaybeIncorrect, + ); + }, + ); } } extract_msrv_attr!(EarlyContext); } -fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) { - if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind - && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind - && matches!( - ( - LitKind::from_token_lit(start_token_lit), - LitKind::from_token_lit(end_token_lit), - ), - ( - Ok(LitKind::Byte(b'a') | LitKind::Char('a')), - Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) | ( - Ok(LitKind::Byte(b'A') | LitKind::Char('A')), - Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) | ( - Ok(LitKind::Byte(b'0') | LitKind::Char('0')), - Ok(LitKind::Byte(b'9') | LitKind::Char('9')), +fn is_incomplete_range(start: &Expr, end: &Expr) -> bool { + match (&start.peel_parens().kind, &end.peel_parens().kind) { + (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => { + matches!( + (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),), + ( + Ok(LitKind::Byte(b'a') | LitKind::Char('a')), + Ok(LitKind::Byte(b'z') | LitKind::Char('z')) + ) | ( + Ok(LitKind::Byte(b'A') | LitKind::Char('A')), + Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), + ) | ( + Ok(LitKind::Byte(b'0') | LitKind::Char('0')), + Ok(LitKind::Byte(b'9') | LitKind::Char('9')), + ) ) - ) - && !in_external_macro(cx.sess(), span) - { - span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); - } - }); + }, + _ => false, } } From d9ab0a70f6fa79a6fb2169bc62e4fa59a689165a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 21:27:46 -0400 Subject: [PATCH 089/361] Refactor `assigning_clones`: * Merge some code paths * Use `find` instead of a loop * Move macro check to after hir pattern matching --- clippy_lints/src/assigning_clones.rs | 500 ++++++++++----------------- 1 file changed, 178 insertions(+), 322 deletions(-) diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 05ea74b0d534..84e3eb53cc08 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,18 +1,16 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::HirNode; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local}; 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::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -68,167 +66,84 @@ impl AssigningClones { impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { - fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { - // Do not fire the lint in macros - let ctxt = assign_expr.span().ctxt(); - let expn_data = ctxt.outer_expn_data(); - match expn_data.kind { - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return, - ExpnKind::Root => {}, - } - - let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else { - return; - }; - - let Some(call) = extract_call(cx, rhs) else { - return; - }; - - if is_ok_to_suggest(cx, lhs, &call, &self.msrv) { - suggest(cx, ctxt, assign_expr, lhs, &call); + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Assign(lhs, rhs, _) = e.kind + && let typeck = cx.typeck_results() + && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind { + ExprKind::Call(f, [arg]) + if let ExprKind::Path(fn_path) = &f.kind + && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() => + { + (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id)) + }, + ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => { + (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id)) + }, + _ => return, + } + && let ctxt = e.span.ctxt() + // Don't lint in macros. + && 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(msrvs::CLONE_INTO) => + { + CloneTrait::ToOwned + }, + _ => return, + } + && let Ok(Some(resolved_fn)) = Instance::resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args) + // TODO: This check currently bails if the local variable has no initializer. + // That is overly conservative - the lint should fire even if there was no initializer, + // but the variable has been initialized before `lhs` was evaluated. + && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs)) + && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id()) + // Derived forms don't implement `clone_from`/`clone_into`. + // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 + && !cx.tcx.is_builtin_derived(resolved_impl) + // Don't suggest calling a function we're implementing. + && resolved_impl.as_local().map_or(true, |block_id| { + cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id) + }) + && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl) + // Only suggest if `clone_from`/`clone_into` is explicitly implemented + && 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", + } + ) + && !clone_source_borrows_from_dest(cx, lhs, rhs.span) + { + span_lint_and_then( + cx, + ASSIGNING_CLONES, + e.span, + match which_trait { + CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", + CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", + }, + |diag| { + let mut app = Applicability::Unspecified; + diag.span_suggestion( + e.span, + match which_trait { + CloneTrait::Clone => "use `clone_from()`", + CloneTrait::ToOwned => "use `clone_into()`", + }, + build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app), + app, + ); + }, + ); } } extract_msrv_attr!(LateContext); } -// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`. -fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { - let fn_def_id = clippy_utils::fn_def_id(cx, expr)?; - - // Fast paths to only check method calls without arguments or function calls with a single argument - let (target, kind, resolved_method) = match expr.kind { - ExprKind::MethodCall(path, receiver, [], _span) => { - let args = cx.typeck_results().node_args(expr.hir_id); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else { - return None; - }; - if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { - (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method) - } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" { - (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method) - } else { - return None; - } - }, - ExprKind::Call(function, [arg]) => { - let kind = cx.typeck_results().node_type(function.hir_id).kind(); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args), - _ => Ok(None), - }) else { - return None; - }; - if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) { - ( - TargetTrait::ToOwned, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id) - && cx.tcx.is_diagnostic_item(sym::Clone, trait_did) - { - ( - TargetTrait::Clone, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else { - return None; - } - }, - _ => return None, - }; - - Some(CallCandidate { - span: expr.span, - target, - kind, - method_def_id: resolved_method.def_id(), - }) -} - -// Return true if we find that the called method has a custom implementation and isn't derived or -// provided by default by the corresponding trait. -fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { - // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. - // If the current MSRV is below that, don't suggest the lint. - if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) { - return false; - } - - // If the left-hand side is a local variable, it might be uninitialized at this point. - // In that case we do not want to suggest the lint. - if let Some(local) = path_to_local(lhs) { - // TODO: This check currently bails if the local variable has no initializer. - // That is overly conservative - the lint should fire even if there was no initializer, - // but the variable has been initialized before `lhs` was evaluated. - if !local_is_initialized(cx, local) { - return false; - } - } - - let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else { - return false; - }; - - // If the method implementation comes from #[derive(Clone)], then don't suggest the lint. - // Automatically generated Clone impls do not currently override `clone_from`. - // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details. - if cx.tcx.is_builtin_derived(impl_block) { - return false; - } - - // If the call expression is inside an impl block that contains the method invoked by the - // call expression, we bail out to avoid suggesting something that could result in endless - // recursion. - if let Some(local_block_id) = impl_block.as_local() - && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner() - { - let impl_block_owner = block.def_id(); - if cx - .tcx - .hir() - .parent_id_iter(lhs.hir_id) - .any(|parent| parent.owner == impl_block_owner) - { - return false; - } - } - - // Find the function for which we want to check that it is implemented. - let provided_fn = match call.target { - TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { - cx.tcx - .provided_trait_methods(clone) - .find(|item| item.name == sym::clone_from) - }), - TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| { - cx.tcx - .provided_trait_methods(to_owned) - .find(|item| item.name.as_str() == "clone_into") - }), - }; - let Some(provided_fn) = provided_fn else { - return false; - }; - - if clone_source_borrows_from_dest(cx, lhs, call.span) { - return false; - } - - // Now take a look if the impl block defines an implementation for the method that we're interested - // in. If not, then we're using a default implementation, which is not interesting, so we will - // not suggest the lint. - let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block); - implemented_fns.contains_key(&provided_fn.def_id) -} - /// Checks if the data being cloned borrows from the place that is being assigned to: /// /// ``` @@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC /// /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows. fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool { - /// If this basic block only exists to drop a local as part of an assignment, returns its - /// successor. Otherwise returns the basic block that was passed in. - fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock { - if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind { - target - } else { - bb - } - } - let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else { return false; }; @@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa // // bb2: // s = s_temp - for bb in mir.basic_blocks.iter() { - let terminator = bb.terminator(); - - // Look for the to_owned/clone call. - if terminator.source_info.span != call_span { - continue; + if let Some(terminator) = mir.basic_blocks.iter() + .map(mir::BasicBlockData::terminator) + .find(|term| term.source_info.span == call_span) + && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind + && let [source] = &**args + && let mir::Operand::Move(source) = &source.node + && let assign_bb = &mir.basic_blocks[assign_bb] + && let assign_bb = match assign_bb.terminator().kind { + // Skip the drop of the assignment's destination. + mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target], + _ => assign_bb, } - - if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind - && let [source] = &**args - && let mir::Operand::Move(source) = &source.node - && let assign_bb = skip_drop_block(mir, assign_bb) - // Skip any storage statements as they are just noise - && let Some(assignment) = mir.basic_blocks[assign_bb].statements - .iter() - .find(|stmt| { - !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) - }) - && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind - && let Some(borrowers) = borrow_map.get(&borrowed.local) - && borrowers.contains(source.local) - { - return true; - } - - return false; + // Skip any storage statements as they are just noise + && let Some(assignment) = assign_bb.statements + .iter() + .find(|stmt| { + !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) + }) + && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind + && let Some(borrowers) = borrow_map.get(&borrowed.local) + { + borrowers.contains(source.local) + } else { + false } - false } -fn suggest<'tcx>( - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - assign_expr: &Expr<'tcx>, - lhs: &Expr<'tcx>, - call: &CallCandidate<'tcx>, -) { - span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { - let mut applicability = Applicability::Unspecified; - - diag.span_suggestion( - assign_expr.span, - call.suggestion_msg(), - call.suggested_replacement(cx, ctxt, lhs, &mut applicability), - applicability, - ); - }); -} - -#[derive(Copy, Clone, Debug)] -enum CallKind<'tcx> { - MethodCall { receiver: &'tcx Expr<'tcx> }, - FunctionCall { self_arg: &'tcx Expr<'tcx> }, -} - -#[derive(Copy, Clone, Debug)] -enum TargetTrait { +#[derive(Clone, Copy)] +enum CloneTrait { Clone, ToOwned, } -#[derive(Debug)] -struct CallCandidate<'tcx> { - span: Span, - target: TargetTrait, - kind: CallKind<'tcx>, - // DefId of the called method from an impl block that implements the target trait - method_def_id: DefId, +#[derive(Copy, Clone)] +enum CallKind { + Ufcs, + Method, } -impl<'tcx> CallCandidate<'tcx> { - #[inline] - fn message(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", - TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", - } - } - - #[inline] - fn suggestion_msg(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "use `clone_from()`", - TargetTrait::ToOwned => "use `clone_into()`", - } - } - - fn suggested_replacement( - &self, - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - lhs: &Expr<'tcx>, - applicability: &mut Applicability, - ) -> String { - match self.target { - TargetTrait::Clone => { - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability) - } - .maybe_par(); - - // Determine whether we need to reference the argument to clone_from(). - let clone_receiver_type = cx.typeck_results().expr_ty(receiver); - let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver); - let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - if clone_receiver_type != clone_receiver_adj_type { - // The receiver may have been a value type, so we need to add an `&` to - // be sure the argument to clone_from will be a reference. - arg_sugg = arg_sugg.addr(); - }; - - format!("{receiver_sugg}.clone_from({arg_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr() - }; - // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. - let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - - format!("Clone::clone_from({self_sugg}, {rhs_sugg})") - }, - } - }, - TargetTrait::ToOwned => { - 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, "_", applicability).maybe_par(); - 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. - if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { - sugg +fn build_sugg<'tcx>( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + lhs: &'tcx Expr<'_>, + fn_arg: &'tcx Expr<'_>, + which_trait: CloneTrait, + call_kind: CallKind, + app: &mut Applicability, +) -> String { + match which_trait { + CloneTrait::Clone => { + match call_kind { + CallKind::Method => { + let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) } else { - sugg.mut_addr() + // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app) } - } 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, "_", applicability) - .maybe_par() - .mut_addr() - }; + .maybe_par(); - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - format!("{receiver_sugg}.clone_into({rhs_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") - }, + // Determine whether we need to reference the argument to clone_from(). + let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg); + let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg); + let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + if clone_receiver_type != clone_receiver_adj_type { + // The receiver may have been a value type, so we need to add an `&` to + // be sure the argument to clone_from will be a reference. + arg_sugg = arg_sugg.addr(); + }; + + format!("{receiver_sugg}.clone_from({arg_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) + } else { + // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr() + }; + // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. + let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + + format!("Clone::clone_from({self_sugg}, {rhs_sugg})") + }, + } + }, + CloneTrait::ToOwned => { + 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 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. + if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { + sugg + } else { + sugg.mut_addr() } - }, - } + } 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() + }; + + match call_kind { + CallKind::Method => { + let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("{receiver_sugg}.clone_into({rhs_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") + }, + } + }, } } From 9d8a17794fcec862f8896738cfbb7a8e02c0e111 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 21:55:29 -0400 Subject: [PATCH 090/361] Refactor `bool_to_int_with_if`: * Check hir structure before macro checks * Simplify constant checking --- clippy_lints/src/bool_to_int_with_if.rs | 134 ++++++++++-------------- 1 file changed, 58 insertions(+), 76 deletions(-) diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index cfb76cab6dc2..561ca9bd9866 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,13 +1,11 @@ -use clippy_utils::higher::If; -use rustc_ast::LitKind; -use rustc_hir::{Block, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; -use clippy_utils::{in_constant, is_else_clause, is_integer_literal}; +use clippy_utils::{in_constant, is_else_clause}; +use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -47,80 +45,64 @@ declare_clippy_lint! { 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 rustc_hir::Expr<'tcx>) { - if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { - check_if_else(cx, expr); + 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(_)) + && let Some(then_lit) = as_int_bool_lit(then) + && let Some(else_lit) = as_int_bool_lit(else_) + && then_lit != else_lit + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { + let ty = cx.typeck_results().expr_ty(then); + let mut applicability = Applicability::MachineApplicable; + let snippet = { + let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + if !then_lit { + sugg = !sugg; + } + sugg + }; + let suggestion = { + let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); + // when used in else clause if statement should be wrapped in curly braces + if is_else_clause(cx.tcx, expr) { + s = s.blockify(); + } + s + }; + + let into_snippet = snippet.clone().maybe_par(); + let as_snippet = snippet.as_ty(ty); + + span_lint_and_then( + cx, + BOOL_TO_INT_WITH_IF, + expr.span, + "boolean to int conversion using if", + |diag| { + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); } } } -fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { - cond, - then, - r#else: Some(r#else), - }) = If::hir(expr) - && let Some(then_lit) = int_literal(then) - && let Some(else_lit) = int_literal(r#else) +fn as_int_bool_lit(e: &Expr<'_>) -> Option { + if let ExprKind::Block(b, _) = e.kind + && b.stmts.is_empty() + && let Some(e) = b.expr + && let ExprKind::Lit(lit) = e.kind + && let LitKind::Int(x, _) = lit.node { - let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) { - false - } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) { - true - } else { - // Expression isn't boolean, exit - return; - }; - let mut applicability = Applicability::MachineApplicable; - let snippet = { - let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - if inverted { - sugg = !sugg; - } - sugg - }; - - let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type - - let suggestion = { - let wrap_in_curly = is_else_clause(cx.tcx, expr); - let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); - if wrap_in_curly { - s = s.blockify(); - } - s - }; // when used in else clause if statement should be wrapped in curly braces - - let into_snippet = snippet.clone().maybe_par(); - let as_snippet = snippet.as_ty(ty); - - span_lint_and_then( - cx, - BOOL_TO_INT_WITH_IF, - expr.span, - "boolean to int conversion using if", - |diag| { - diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); - diag.note(format!( - "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" - )); - }, - ); - }; -} - -// If block contains only a int literal expression, return literal expression -fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { - if let ExprKind::Block(block, _) = expr.kind - && let Block { - stmts: [], // Shouldn't lint if statements with side effects - expr: Some(expr), - .. - } = block - && let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(_, _) = lit.node - { - Some(expr) + match x.get() { + 0 => Some(false), + 1 => Some(true), + _ => None, + } } else { None } From 987f973a5911851f3e2a03b0fef850e8468aa3f4 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 5 Jul 2024 04:55:42 +0000 Subject: [PATCH 091/361] 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 5a35166769e8..dd5355134c5e 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -66b4f0021bfb11a8c20d084c99a40f4a78ce1d38 +51917ba8f215f76e9d3fa8e77cd0a781bb28dab7 From ac939ad3a1ba16a798d0b697e5b9b84f8c2b5f5d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 22:19:35 -0400 Subject: [PATCH 092/361] Refactor `disallowed_script_idents`: Simplify script checking loop. --- clippy_lints/src/disallowed_script_idents.rs | 41 +++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index a995f06fb73d..5ce11900adf8 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents { // Note: `symbol.as_str()` is an expensive operation, thus should not be called // more than once for a single symbol. let symbol_str = symbol.as_str(); - if symbol_str.is_ascii() { - continue; - } - for c in symbol_str.chars() { - // We want to iterate through all the scripts associated with this character - // and check whether at least of one scripts is in the whitelist. - let forbidden_script = c - .script_extension() - .iter() - .find(|script| !self.whitelist.contains(script)); - if let Some(script) = forbidden_script { - span_lint( - cx, - DISALLOWED_SCRIPT_IDENTS, - span, - format!( - "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", - script.full_name() - ), - ); - // We don't want to spawn warning multiple times over a single identifier. - break; - } + // Check if any character in the symbol is not part of any allowed script. + // Fast path for ascii-only idents. + if !symbol_str.is_ascii() + && let Some(script) = symbol_str.chars().find_map(|c| { + c.script_extension() + .iter() + .find(|script| !self.whitelist.contains(script)) + }) + { + span_lint( + cx, + DISALLOWED_SCRIPT_IDENTS, + span, + format!( + "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", + script.full_name() + ), + ); } } } From 4c44b4e3c85a1ee3ec1d77f97737aa689234f0b6 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 22:11:47 -0400 Subject: [PATCH 093/361] Remove `is_test_module_or_function` and use `is_in_test` instead. --- clippy_lints/src/disallowed_names.rs | 46 +++++-------------- clippy_lints/src/wildcard_imports.rs | 19 ++------ tests/ui/disallowed_names.rs | 1 + tests/ui/wildcard_imports.fixed | 3 ++ tests/ui/wildcard_imports.rs | 3 ++ tests/ui/wildcard_imports.stderr | 10 ++-- .../wildcard_imports_2021.edition2018.fixed | 3 ++ .../wildcard_imports_2021.edition2018.stderr | 10 ++-- .../wildcard_imports_2021.edition2021.fixed | 3 ++ .../wildcard_imports_2021.edition2021.stderr | 10 ++-- tests/ui/wildcard_imports_2021.rs | 3 ++ 11 files changed, 47 insertions(+), 64 deletions(-) diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 2afbf184117e..58809604c373 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Item, Pat, PatKind}; +use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -27,52 +27,30 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedNames { disallow: FxHashSet, - test_modules_deep: u32, } impl DisallowedNames { pub fn new(disallowed_names: &[String]) -> Self { Self { disallow: disallowed_names.iter().cloned().collect(), - test_modules_deep: 0, } } - - fn in_test_module(&self) -> bool { - self.test_modules_deep != 0 - } } impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { - fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } - } - fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - // Check whether we are under the `test` attribute. - if self.in_test_module() { - return; - } - - if let PatKind::Binding(.., ident, _) = pat.kind { - if self.disallow.contains(&ident.name.to_string()) { - span_lint( - cx, - DISALLOWED_NAMES, - ident.span, - format!("use of a disallowed/placeholder name `{}`", ident.name), - ); - } - } - } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); + if let PatKind::Binding(.., ident, _) = pat.kind + && self.disallow.contains(&ident.name.to_string()) + && !is_in_test(cx.tcx, pat.hir_id) + { + span_lint( + cx, + DISALLOWED_NAMES, + ident.span, + format!("use of a disallowed/placeholder name `{}`", ident.name), + ); } } } diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 436f0cb79fb2..a0a60ca88758 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use clippy_utils::source::{snippet, snippet_with_applicability}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -100,7 +100,6 @@ declare_clippy_lint! { #[derive(Default)] pub struct WildcardImports { warn_on_all: bool, - test_modules_deep: u32, allowed_segments: FxHashSet, } @@ -108,7 +107,6 @@ impl WildcardImports { pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet) -> Self { Self { warn_on_all, - test_modules_deep: 0, allowed_segments: allowed_wildcard_imports, } } @@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports { return; } - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } 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()) { return; } if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind - && (self.warn_on_all || !self.check_exceptions(item, use_path.segments)) + && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments)) && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id) && !used_imports.is_empty() // Already handled by `unused_imports` && !used_imports.contains(&kw::Underscore) @@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports { span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability); } } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); - } - } } impl WildcardImports { - fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { + fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { item.span.from_expansion() || is_prelude_import(segments) - || (is_super_only_import(segments) && self.test_modules_deep > 0) || is_allowed_via_config(segments, &self.allowed_segments) + || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) } } diff --git a/tests/ui/disallowed_names.rs b/tests/ui/disallowed_names.rs index 13c883409bf6..96531bf8d88c 100644 --- a/tests/ui/disallowed_names.rs +++ b/tests/ui/disallowed_names.rs @@ -60,6 +60,7 @@ fn issue_1647_ref_mut() { //~^ ERROR: use of a disallowed/placeholder name `quux` } +#[cfg(test)] mod tests { fn issue_7305() { // `disallowed_names` lint should not be triggered inside of the test code. diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 6fdd728b9b72..46890ee9213f 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -204,6 +204,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -212,6 +213,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -219,6 +221,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 20e06d4b3664..1a5586cbb88d 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -205,6 +205,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -213,6 +214,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -220,6 +222,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 0c69d5262c26..8e88f216394d 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:236:17 + --> tests/ui/wildcard_imports.rs:239:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:244:13 + --> tests/ui/wildcard_imports.rs:247:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:253:17 + --> tests/ui/wildcard_imports.rs:256:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:262:13 + --> tests/ui/wildcard_imports.rs:265:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:270:13 + --> tests/ui/wildcard_imports.rs:273:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 18ebc0f51274..606ff080e774 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -199,6 +199,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -207,6 +208,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -214,6 +216,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { From 60af2585f74b889da6be05a379c8dad5e0897cf9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 16:26:26 -0400 Subject: [PATCH 094/361] Refactor `disallowed_methods`: * Simplify `def_id` extraction. * Use the span of the method name instead of the call. --- clippy_lints/src/disallowed_methods.rs | 42 +++++++++---------- tests/ui-internal/disallow_span_lint.stderr | 16 +++---- .../conf_disallowed_methods.stderr | 36 ++++++++-------- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 9de879604e2e..38fe687f7ccf 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,6 +1,6 @@ use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::Call(receiver, _) = parent.kind - && receiver.hir_id == expr.hir_id - { - None - } else { - path_def_id(cx, 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::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { + (id, name.ident.span) + }, + _ => return, }; - let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else { - return; - }; - let conf = match self.disallowed.get(&def_id) { - Some(&index) => &self.conf_disallowed[index], - None => return, - }; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&index) = self.disallowed.get(&id) { + let conf = &self.conf_disallowed[index]; + let msg = format!("use of a disallowed method `{}`", conf.path()); + span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { + if let Some(reason) = conf.reason() { + diag.note(reason); + } + }); + } } } diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 1be4b665bcba..66eda44f7455 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -1,22 +1,18 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> tests/ui-internal/disallow_span_lint.rs:14:5 + --> tests/ui-internal/disallow_span_lint.rs:14:8 | -LL | / cx.span_lint(lint, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +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 (from clippy.toml) = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:20:5 + --> tests/ui-internal/disallow_span_lint.rs:20:9 | -LL | / tcx.node_span_lint(lint, hir_id, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +LL | tcx.node_span_lint(lint, hir_id, span, |lint| { + | ^^^^^^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml) diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 4afbbf5f8079..f661e76cc746 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -2,36 +2,36 @@ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8 | LL | re.is_match("abc"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: no matching allowed (from clippy.toml) error: use of a disallowed method `std::iter::Iterator::sum` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14 | LL | a.iter().sum::(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7 | LL | a.sort_unstable(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61 @@ -55,37 +55,37 @@ error: use of a disallowed method `futures::stream::select_all` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 | LL | local_fn(); - | ^^^^^^^^^^ + | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5 | LL | local_mod::f(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7 | LL | s.method(); - | ^^^^^^^^^^ + | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7 | LL | s.provided_method(); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7 | LL | s.implemented_method(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors From 6d61bdabeaaf806cc9b45a85fc5231fc6cf2743a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 5 Jul 2024 02:29:23 -0400 Subject: [PATCH 095/361] Use `is_in_test` in more places. --- clippy_lints/src/functions/impl_trait_in_params.rs | 8 ++++---- clippy_lints/src/incompatible_msrv.rs | 4 ++-- clippy_lints/src/methods/unwrap_expect_used.rs | 4 ++-- clippy_lints/src/missing_assert_message.rs | 4 ++-- clippy_lints/src/write.rs | 5 ++--- clippy_utils/src/lib.rs | 10 ---------- 6 files changed, 12 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 6fb38a0d6dd8..cf85c74e688d 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { if let FnKind::ItemFn(_, generics, _) = kind && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, hir_id) + && !is_in_test(cx.tcx, hir_id) { for param in generics.params { if param.is_impl_trait() { @@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { && of_trait.is_none() && let body = cx.tcx.hir().body(body_id) && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, impl_item.hir_id()) + && !is_in_test(cx.tcx, impl_item.hir_id()) { for param in impl_item.generics.params { if param.is_impl_trait() { @@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id()) // ^^ (Will always be a trait) && !item.vis_span.is_empty() // Is public - && !is_in_test_function(cx.tcx, trait_item.hir_id()) + && !is_in_test(cx.tcx, trait_item.hir_id()) { for param in trait_item.generics.params { if param.is_impl_trait() { diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 35b4481bfee7..5c63d48adaf0 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; @@ -88,7 +88,7 @@ impl IncompatibleMsrv { return; } let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) { + if self.msrv.meets(version) || is_in_test(cx.tcx, node) { return; } if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 516b8984ad79..5b0bd0f716ab 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; -use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; +use clippy_utils::{is_in_test, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; @@ -61,7 +61,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { + if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index dd98352da860..935ed48dacc5 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test; use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { }; // This lint would be very noisy in tests, so just ignore if we're in test context - if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) { + if is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 652ce88bd951..96e53b7ef0ba 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .as_ref() .map_or(false, |crate_name| crate_name == "build_script_build"); - let allowed_in_tests = self.allow_print_in_tests - && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)); + let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 45a31fe442ba..28d1eeb4e28c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2625,16 +2625,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { .any(|attr| attr.has_name(sym::cfg)) } -/// Checks whether item either has `test` attribute applied, or -/// is a module with `test` in its name. -/// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function -pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { - is_in_test_function(tcx, item.hir_id()) - || matches!(item.kind, ItemKind::Mod(..)) - && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") -} - /// Walks up the HIR tree from the given expression in an attempt to find where the value is /// consumed. /// From 2c09ac3d39c272469b4f9a581f4a5507bcc09ca1 Mon Sep 17 00:00:00 2001 From: Milo Moisson Date: Wed, 12 Jun 2024 18:10:56 +0200 Subject: [PATCH 096/361] feat: add cfg_not_test lint --- CHANGELOG.md | 1 + clippy_lints/src/cfg_not_test.rs | 60 ++++++++++++++++++++++++++++++ clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + 4 files changed, 64 insertions(+) create mode 100644 clippy_lints/src/cfg_not_test.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d919b521e715..5258cd9f41aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5254,6 +5254,7 @@ Released 2018-09-13 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss [`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_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 diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs new file mode 100644 index 000000000000..b54f392bf2fa --- /dev/null +++ b/clippy_lints/src/cfg_not_test.rs @@ -0,0 +1,60 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::NestedMetaItem; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`) + /// + /// ### Why is this bad? + /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code. + /// Enabling this also guards against excessive mockery as well, which is an anti-pattern. + /// + /// ### Example + /// ```rust + /// # fn important_check() {} + /// #[cfg(not(test))] + /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage! + /// ``` + /// Use instead: + /// ```rust + /// # fn important_check() {} + /// important_check(); + /// ``` + #[clippy::version = "1.73.0"] + pub CFG_NOT_TEST, + restriction, + "enforce against excluding code from test builds" +} + +declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); + +impl EarlyLintPass for CfgNotTest { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { + if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } + } +} + +fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool { + list.is_some_and(|list| { + list.iter().any(|item| { + item.ident().is_some_and(|ident| match ident.name { + rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), + rustc_span::sym::test => not, + _ => contains_not_test(item.meta_item_list(), not), + }) + }) + }) +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 50661bf46a0a..0b674a7d7ab3 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -104,6 +104,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::casts::REF_AS_PTR_INFO, crate::casts::UNNECESSARY_CAST_INFO, crate::casts::ZERO_PTR_INFO, + crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8a9d3b43fb3a..3d40b397ab9b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -92,6 +92,7 @@ mod box_default; mod byte_char_slices; mod cargo; mod casts; +mod cfg_not_test; mod checked_conversions; mod cognitive_complexity; mod collapsible_if; @@ -1176,6 +1177,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains)); store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); + store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); // add lints here, do not remove this comment, it's used in `new_lint` } From dd37441a646c64c89150cc008dacdbb1f68d3f14 Mon Sep 17 00:00:00 2001 From: Milo Moisson Date: Wed, 12 Jun 2024 18:11:01 +0200 Subject: [PATCH 097/361] test: add cfg_not_test tests --- tests/ui/cfg_not_test.rs | 32 +++++++++++++++++++++++++ tests/ui/cfg_not_test.stderr | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/ui/cfg_not_test.rs create mode 100644 tests/ui/cfg_not_test.stderr diff --git a/tests/ui/cfg_not_test.rs b/tests/ui/cfg_not_test.rs new file mode 100644 index 000000000000..da3e29d28966 --- /dev/null +++ b/tests/ui/cfg_not_test.rs @@ -0,0 +1,32 @@ +#![allow(unused)] +#![warn(clippy::cfg_not_test)] + +fn important_check() {} + +fn main() { + // Statement + #[cfg(not(test))] + let answer = 42; + + // Expression + #[cfg(not(test))] + important_check(); + + // Make sure only not(test) are checked, not other attributes + #[cfg(not(foo))] + important_check(); +} + +#[cfg(not(not(test)))] +struct CfgNotTest; + +// Deeply nested `not(test)` +#[cfg(not(test))] +fn foo() {} +#[cfg(all(debug_assertions, not(test)))] +fn bar() {} +#[cfg(not(any(not(debug_assertions), test)))] +fn baz() {} + +#[cfg(test)] +mod tests {} diff --git a/tests/ui/cfg_not_test.stderr b/tests/ui/cfg_not_test.stderr new file mode 100644 index 000000000000..c1bf626887af --- /dev/null +++ b/tests/ui/cfg_not_test.stderr @@ -0,0 +1,45 @@ +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:8:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + = note: this could increase code coverage despite not actually being tested + = note: `-D clippy::cfg-not-test` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]` + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:12:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:24:1 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:26:1 + | +LL | #[cfg(all(debug_assertions, not(test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:28:1 + | +LL | #[cfg(not(any(not(debug_assertions), test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: aborting due to 5 previous errors + From 6621e6cbfaddd39a7abeab92a30c7c6175184a6f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 21 Jun 2024 17:53:22 +0500 Subject: [PATCH 098/361] Rename thread_local_initializer_can_be_made_const to missing_const_for_thread_local --- CHANGELOG.md | 1 + clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 7 +- ...t.rs => missing_const_for_thread_local.rs} | 14 +- clippy_lints/src/renamed_lints.rs | 1 + ...d => missing_const_for_thread_local.fixed} | 2 +- ...t.rs => missing_const_for_thread_local.rs} | 2 +- ... => missing_const_for_thread_local.stderr} | 16 +-- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 124 +++++++++--------- 12 files changed, 93 insertions(+), 82 deletions(-) rename clippy_lints/src/{thread_local_initializer_can_be_made_const.rs => missing_const_for_thread_local.rs} (92%) rename tests/ui/{thread_local_initializer_can_be_made_const.fixed => missing_const_for_thread_local.fixed} (97%) rename tests/ui/{thread_local_initializer_can_be_made_const.rs => missing_const_for_thread_local.rs} (97%) rename tests/ui/{thread_local_initializer_can_be_made_const.stderr => missing_const_for_thread_local.stderr} (72%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d919b521e715..8e5a7a34c8ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5589,6 +5589,7 @@ Released 2018-09-13 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message [`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn +[`missing_const_for_thread_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_thread_local [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 78fd6149dc09..fc56ac517968 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -26,7 +26,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_FN } - 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } + 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,56,0 { CONST_FN_UNION } 1,55,0 { SEEK_REWIND } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 50661bf46a0a..8b1b16de0a12 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -505,6 +505,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO, crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO, crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO, + crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO, crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO, crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO, crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO, @@ -682,7 +683,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, - crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8a9d3b43fb3a..c09d23d06ffb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -230,6 +230,7 @@ mod mismatching_type_param_order; mod missing_assert_message; mod missing_asserts_for_indexing; mod missing_const_for_fn; +mod missing_const_for_thread_local; mod missing_doc; mod missing_enforced_import_rename; mod missing_fields_in_debug; @@ -341,7 +342,6 @@ mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; mod tests_outside_test_module; -mod thread_local_initializer_can_be_made_const; mod to_digit_is_some; mod to_string_trait_impl; mod trailing_empty_array; @@ -1156,9 +1156,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { behavior: pub_underscore_fields_behavior, }) }); - store.register_late_pass(move |_| { - Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv())) - }); + store + .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv()))); store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/missing_const_for_thread_local.rs similarity index 92% rename from clippy_lints/src/thread_local_initializer_can_be_made_const.rs rename to clippy_lints/src/missing_const_for_thread_local.rs index 4af3ee74d0ea..ab1b4aa3dee6 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -39,23 +39,23 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.77.0"] - pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + pub MISSING_CONST_FOR_THREAD_LOCAL, perf, "suggest using `const` in `thread_local!` macro" } -pub struct ThreadLocalInitializerCanBeMadeConst { +pub struct MissingConstForThreadLocal { msrv: Msrv, } -impl ThreadLocalInitializerCanBeMadeConst { +impl MissingConstForThreadLocal { #[must_use] pub fn new(msrv: Msrv) -> Self { Self { msrv } } } -impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]); +impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]); #[inline] fn is_thread_local_initializer( @@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id false } -impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { +impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { local_defid: rustc_span::def_id::LocalDefId, ) { let defid = local_defid.to_def_id(); - if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST) + if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT) && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) // Some implementations of `thread_local!` include an initializer fn. // In the case of a const initializer, the init fn is also const, @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { { span_lint_and_sugg( cx, - THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + MISSING_CONST_FOR_THREAD_LOCAL, unpeeled.span, "initializer for `thread_local` value can be made `const`", "replace with", diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 85979903b587..e0e1279873e6 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -32,6 +32,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::result_unwrap_used", "clippy::unwrap_used"), ("clippy::single_char_push_str", "clippy::single_char_add_str"), ("clippy::stutter", "clippy::module_name_repetitions"), + ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), ("clippy::zero_width_space", "clippy::invisible_characters"), diff --git a/tests/ui/thread_local_initializer_can_be_made_const.fixed b/tests/ui/missing_const_for_thread_local.fixed similarity index 97% rename from tests/ui/thread_local_initializer_can_be_made_const.fixed rename to tests/ui/missing_const_for_thread_local.fixed index 4c9bd0bd8634..90b31b9b5d21 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/tests/ui/missing_const_for_thread_local.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/tests/ui/thread_local_initializer_can_be_made_const.rs b/tests/ui/missing_const_for_thread_local.rs similarity index 97% rename from tests/ui/thread_local_initializer_can_be_made_const.rs rename to tests/ui/missing_const_for_thread_local.rs index eb336f0dd191..f97e4848fd7a 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/tests/ui/missing_const_for_thread_local.rs @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/tests/ui/thread_local_initializer_can_be_made_const.stderr b/tests/ui/missing_const_for_thread_local.stderr similarity index 72% rename from tests/ui/thread_local_initializer_can_be_made_const.stderr rename to tests/ui/missing_const_for_thread_local.stderr index b4f8bd822b0d..c143a37454f5 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.stderr +++ b/tests/ui/missing_const_for_thread_local.stderr @@ -1,38 +1,38 @@ error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:8:41 + --> tests/ui/missing_const_for_thread_local.rs:8:41 | LL | static BUF_1: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` | - = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]` + = note: `-D clippy::missing-const-for-thread-local` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_thread_local)]` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:18:29 + --> tests/ui/missing_const_for_thread_local.rs:18:29 | LL | static SIMPLE:i32 = 1; | ^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:24:59 + --> tests/ui/missing_const_for_thread_local.rs:24:59 | LL | static BUF_3_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:26:59 + --> tests/ui/missing_const_for_thread_local.rs:26:59 | LL | static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31 + --> tests/ui/missing_const_for_thread_local.rs:32:31 | LL | static PEEL_ME: i32 = { 1 }; | ^^^^^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36 + --> tests/ui/missing_const_for_thread_local.rs:34:36 | LL | static PEEL_ME_MANY: i32 = { let x = 1; x * x }; | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }` diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 24d0f7975428..df39afcc1ad6 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -27,6 +27,7 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -83,6 +84,7 @@ #![warn(clippy::unwrap_used)] #![warn(clippy::single_char_add_str)] #![warn(clippy::module_name_repetitions)] +#![warn(clippy::missing_const_for_thread_local)] #![warn(clippy::recursive_format_impl)] #![warn(clippy::unwrap_or_default)] #![warn(clippy::invisible_characters)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index be8da2fa1a38..c57a4e1bde26 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -27,6 +27,7 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -83,6 +84,7 @@ #![warn(clippy::result_unwrap_used)] #![warn(clippy::single_char_push_str)] #![warn(clippy::stutter)] +#![warn(clippy::thread_local_initializer_can_be_made_const)] #![warn(clippy::to_string_in_display)] #![warn(clippy::unwrap_or_else_default)] #![warn(clippy::zero_width_space)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 777ac20153da..3abab593a6ba 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:56:9 + --> tests/ui/rename.rs:57:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,346 +8,352 @@ 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:57:9 + --> tests/ui/rename.rs:58: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:58:9 + --> tests/ui/rename.rs:59: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:59:9 + --> tests/ui/rename.rs:60: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:60:9 + --> tests/ui/rename.rs:61: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:61:9 + --> tests/ui/rename.rs:62: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:62:9 + --> tests/ui/rename.rs:63: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:63:9 + --> tests/ui/rename.rs:64: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:64:9 + --> tests/ui/rename.rs:65: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:65:9 + --> tests/ui/rename.rs:66: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:66:9 + --> tests/ui/rename.rs:67: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:67:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70: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:70:9 + --> tests/ui/rename.rs:71: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:71:9 + --> tests/ui/rename.rs:72: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:72:9 + --> tests/ui/rename.rs:73: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:73:9 + --> tests/ui/rename.rs:74: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:74:9 + --> tests/ui/rename.rs:75: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:75:9 + --> tests/ui/rename.rs:76: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:76:9 + --> tests/ui/rename.rs:77: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:77:9 + --> tests/ui/rename.rs:78: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:78:9 + --> tests/ui/rename.rs:79: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:79:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:81: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:81:9 + --> tests/ui/rename.rs:82: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:82:9 + --> tests/ui/rename.rs:83: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:83:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:85: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:85:9 + --> tests/ui/rename.rs:86: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:87: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:86:9 + --> tests/ui/rename.rs:88: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:87:9 + --> tests/ui/rename.rs:89: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:88:9 + --> tests/ui/rename.rs:90: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:89:9 + --> tests/ui/rename.rs:91: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:90:9 + --> tests/ui/rename.rs:92: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:91:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:94: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:93:9 + --> tests/ui/rename.rs:95: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:94:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:97: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:96:9 + --> tests/ui/rename.rs:98: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:97:9 + --> tests/ui/rename.rs:99: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:98:9 + --> tests/ui/rename.rs:100: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:99:9 + --> tests/ui/rename.rs:101: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:100:9 + --> tests/ui/rename.rs:102: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:101:9 + --> tests/ui/rename.rs:103: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:102:9 + --> tests/ui/rename.rs:104: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:103:9 + --> tests/ui/rename.rs:105: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:104:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 58 previous errors +error: aborting due to 59 previous errors From 25bb612538e7883fd30c355fbccf9457a46fec01 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 5 Jul 2024 16:36:24 +0200 Subject: [PATCH 099/361] Lintcheck: Add `--warn-all` and make it the CI default --- .github/workflows/lintcheck.yml | 4 +-- lintcheck/src/config.rs | 4 +++ lintcheck/src/main.rs | 56 ++++++++++++++++++++++----------- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index 91c98b3a2560..f016a7700592 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -58,7 +58,7 @@ jobs: - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload base JSON uses: actions/upload-artifact@v4 @@ -86,7 +86,7 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload head JSON uses: actions/upload-artifact@v4 diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index e6cd7c9fdc2b..b35a62eed440 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -36,6 +36,10 @@ pub(crate) struct LintcheckConfig { /// Apply a filter to only collect specified lints, this also overrides `allow` attributes #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)] pub lint_filter: Vec, + /// Set all lints to the "warn" lint level, even resitriction ones. Usually, + /// it's better to use `--filter` instead + #[clap(long, conflicts_with("lint_filter"))] + pub warn_all: bool, /// Set the output format of the log file #[clap(long, short, default_value = "text")] pub format: OutputFormat, diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index ec72e0eb5dcb..70b8af0fdb95 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -5,6 +5,7 @@ // When a new lint is introduced, we can search the results for new warnings and check for false // positives. +#![feature(iter_collect_into)] #![warn( trivial_casts, trivial_numeric_casts, @@ -352,7 +353,7 @@ impl Crate { target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, - lint_filter: &[String], + lint_levels_args: &[String], server: &Option, ) -> Vec { // advance the atomic index by one @@ -398,16 +399,9 @@ impl Crate { for opt in options { clippy_args.push(opt); } - } else { - clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]); } - if lint_filter.is_empty() { - clippy_args.push("--cap-lints=warn"); - } else { - clippy_args.push("--cap-lints=allow"); - clippy_args.extend(lint_filter.iter().map(String::as_str)); - } + clippy_args.extend(lint_levels_args.iter().map(String::as_str)); let mut cmd = Command::new("cargo"); cmd.arg(if config.fix { "fix" } else { "check" }) @@ -638,15 +632,39 @@ fn lintcheck(config: LintcheckConfig) { let (crates, recursive_options) = read_crates(&config.sources_toml_path); let counter = AtomicUsize::new(1); - let lint_filter: Vec = config - .lint_filter - .iter() - .map(|filter| { - let mut filter = filter.clone(); - filter.insert_str(0, "--force-warn="); - filter - }) - .collect(); + let mut lint_level_args: Vec = vec![]; + if config.lint_filter.is_empty() { + lint_level_args.push("--cap-lints=warn".to_string()); + + // Set allow-by-default to warn + if config.warn_all { + [ + "clippy::cargo", + "clippy::nursery", + "clippy::pedantic", + "clippy::restriction", + ] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } else { + ["clippy::cargo", "clippy::pedantic"] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } + } else { + lint_level_args.push("--cap-lints=allow".to_string()); + config + .lint_filter + .iter() + .map(|filter| { + let mut filter = filter.clone(); + filter.insert_str(0, "--force-warn="); + filter + }) + .collect_into(&mut lint_level_args); + }; let crates: Vec = crates .into_iter() @@ -698,7 +716,7 @@ fn lintcheck(config: LintcheckConfig) { &counter, crates.len(), &config, - &lint_filter, + &lint_level_args, &server, ) }) From c77a2c6c0c463a1b53eafd1eb65d55600a0d5045 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 21 Jun 2024 20:44:25 +0200 Subject: [PATCH 100/361] implement `libc::sched_getaffinity` and `libc::sched_setaffinity` --- src/tools/miri/src/bin/miri.rs | 3 + .../miri/src/concurrency/cpu_affinity.rs | 95 +++++++++ src/tools/miri/src/concurrency/mod.rs | 1 + src/tools/miri/src/concurrency/thread.rs | 5 + src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/machine.rs | 25 ++- .../miri/src/shims/unix/foreign_items.rs | 97 +++++++++ .../src/shims/unix/linux/foreign_items.rs | 13 -- .../miri/tests/fail-dep/libc/affinity.rs | 17 ++ .../miri/tests/fail-dep/libc/affinity.stderr | 20 ++ .../miri/tests/pass-dep/libc/libc-affinity.rs | 194 ++++++++++++++++++ 11 files changed, 457 insertions(+), 14 deletions(-) create mode 100644 src/tools/miri/src/concurrency/cpu_affinity.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/affinity.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/affinity.stderr create mode 100644 src/tools/miri/tests/pass-dep/libc/libc-affinity.rs diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9d8e44ce409e..9f3fa075f38f 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -592,6 +592,9 @@ fn main() { let num_cpus = param .parse::() .unwrap_or_else(|err| show_error!("-Zmiri-num-cpus requires a `u32`: {}", err)); + if !(1..=miri::MAX_CPUS).contains(&usize::try_from(num_cpus).unwrap()) { + show_error!("-Zmiri-num-cpus must be in the range 1..={}", miri::MAX_CPUS); + } miri_config.num_cpus = num_cpus; } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") { let page_size = param.parse::().unwrap_or_else(|err| { diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs new file mode 100644 index 000000000000..085900ac3aa6 --- /dev/null +++ b/src/tools/miri/src/concurrency/cpu_affinity.rs @@ -0,0 +1,95 @@ +use crate::bug; +use rustc_target::abi::Endian; + +/// The maximum number of CPUs supported by miri. +/// +/// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number +/// of CPUs that a `cpu_set_t` can contain. +/// +/// Real machines can have more CPUs than this number, and there exist APIs to set their affinity, +/// but this is not currently supported by miri. +pub const MAX_CPUS: usize = 1024; + +/// A thread's CPU affinity mask determines the set of CPUs on which it is eligible to run. +// the actual representation depends on the target's endianness and pointer width. +// See CpuAffinityMask::set for details +#[derive(Clone)] +pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]); + +impl CpuAffinityMask { + pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8; + + pub fn new(target: &rustc_target::spec::Target, cpu_count: u32) -> Self { + let mut this = Self([0; Self::CPU_MASK_BYTES]); + + // the default affinity mask includes only the available CPUs + for i in 0..cpu_count as usize { + this.set(target, i); + } + + this + } + + pub fn chunk_size(target: &rustc_target::spec::Target) -> u64 { + // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either + // + // - [u32; 32] on 32-bit platforms + // - [u64; 16] everywhere else + + // FIXME: this should be `size_of::()` + u64::from(target.pointer_width / 8) + } + + fn set(&mut self, target: &rustc_target::spec::Target, cpu: usize) { + // we silently ignore CPUs that are out of bounds. This matches the behavior of + // `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs. + if cpu >= MAX_CPUS { + return; + } + + // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either + // + // - [u32; 32] on 32-bit platforms + // - [u64; 16] everywhere else + // + // Within the array elements, we need to use the endianness of the target. + match Self::chunk_size(target) { + 4 => { + let start = cpu / 32 * 4; // first byte of the correct u32 + let chunk = self.0[start..].first_chunk_mut::<4>().unwrap(); + let offset = cpu % 32; + *chunk = match target.options.endian { + Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), + Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + }; + } + 8 => { + let start = cpu / 64 * 8; // first byte of the correct u64 + let chunk = self.0[start..].first_chunk_mut::<8>().unwrap(); + let offset = cpu % 64; + *chunk = match target.options.endian { + Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), + Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + }; + } + other => bug!("other chunk sizes are not supported: {other}"), + }; + } + + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + pub fn from_array( + target: &rustc_target::spec::Target, + cpu_count: u32, + bytes: [u8; Self::CPU_MASK_BYTES], + ) -> Option { + // mask by what CPUs are actually available + let default = Self::new(target, cpu_count); + let masked = std::array::from_fn(|i| bytes[i] & default.0[i]); + + // at least one thread must be set for the input to be valid + masked.iter().any(|b| *b != 0).then_some(Self(masked)) + } +} diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 822d173ac06a..17789fe9f87f 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,3 +1,4 @@ +pub mod cpu_affinity; pub mod data_race; pub mod init_once; mod range_object_map; diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 718daf93ea00..a53dd7eac1e9 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -936,6 +936,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // After this all accesses will be treated as occurring in the new thread. let old_thread_id = this.machine.threads.set_active_thread_id(new_thread_id); + // The child inherits its parent's cpu affinity. + if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&old_thread_id).cloned() { + this.machine.thread_cpu_affinity.insert(new_thread_id, cpuset); + } + // Perform the function pointer load in the new thread frame. let instance = this.get_ptr_fn(start_routine)?.as_instance()?; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 8da00861f905..7fb68d782f11 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -129,6 +129,7 @@ pub use crate::borrow_tracker::{ }; pub use crate::clock::{Clock, Instant}; pub use crate::concurrency::{ + cpu_affinity::MAX_CPUS, data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _}, init_once::{EvalContextExt as _, InitOnceId}, sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects}, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index e321237bb4a2..fee6ab068175 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -30,6 +30,7 @@ use rustc_target::spec::abi::Abi; use crate::{ concurrency::{ + cpu_affinity::{self, CpuAffinityMask}, data_race::{self, NaReadType, NaWriteType}, weak_memory, }, @@ -471,6 +472,12 @@ pub struct MiriMachine<'tcx> { /// The set of threads. pub(crate) threads: ThreadManager<'tcx>, + + /// Stores which thread is eligible to run on which CPUs. + /// This has no effect at all, it is just tracked to produce the correct result + /// in `sched_getaffinity` + pub(crate) thread_cpu_affinity: FxHashMap, + /// The state of the primitive synchronization objects. pub(crate) sync: SynchronizationObjects, @@ -627,6 +634,20 @@ impl<'tcx> MiriMachine<'tcx> { let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 }; let stack_size = if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 }; + assert!( + usize::try_from(config.num_cpus).unwrap() <= cpu_affinity::MAX_CPUS, + "miri only supports up to {} CPUs, but {} were configured", + cpu_affinity::MAX_CPUS, + config.num_cpus + ); + let threads = ThreadManager::default(); + let mut thread_cpu_affinity = FxHashMap::default(); + if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") { + thread_cpu_affinity.insert( + threads.active_thread(), + CpuAffinityMask::new(&tcx.sess.target, config.num_cpus), + ); + } MiriMachine { tcx, borrow_tracker, @@ -644,7 +665,8 @@ impl<'tcx> MiriMachine<'tcx> { fds: shims::FdTable::new(config.mute_stdout_stderr), dirs: Default::default(), layouts, - threads: ThreadManager::default(), + threads, + thread_cpu_affinity, sync: SynchronizationObjects::default(), static_roots: Vec::new(), profiler, @@ -765,6 +787,7 @@ impl VisitProvenance for MiriMachine<'_> { #[rustfmt::skip] let MiriMachine { threads, + thread_cpu_affinity: _, sync: _, tls, env_vars, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 2421f9244f36..f5d3e0b536be 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -3,8 +3,10 @@ use std::str; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use crate::concurrency::cpu_affinity::CpuAffinityMask; use crate::shims::alloc::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -571,6 +573,101 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "sched_getaffinity" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { + throw_unsup_format!( + "`sched_getaffinity` is not supported on {}", + this.tcx.sess.target.os + ); + } + + let [pid, cpusetsize, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let pid = this.read_scalar(pid)?.to_u32()?; + let cpusetsize = this.read_target_usize(cpusetsize)?; + let mask = this.read_pointer(mask)?; + + // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid + let thread_id = match pid { + 0 => this.active_thread(), + _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"), + }; + + // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either + // + // - [u32; 32] on 32-bit platforms + // - [u64; 16] everywhere else + let chunk_size = CpuAffinityMask::chunk_size(&this.tcx.sess.target); + + if this.ptr_is_null(mask)? { + let einval = this.eval_libc("EFAULT"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 { + // we only copy whole chunks of size_of::() + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { + let cpuset = cpuset.clone(); + // we only copy whole chunks of size_of::() + let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap()); + this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?; + this.write_scalar(Scalar::from_i32(0), dest)?; + } else { + // The thread whose ID is pid could not be found + let einval = this.eval_libc("ESRCH"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } + } + "sched_setaffinity" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { + throw_unsup_format!( + "`sched_setaffinity` is not supported on {}", + this.tcx.sess.target.os + ); + } + + let [pid, cpusetsize, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let pid = this.read_scalar(pid)?.to_u32()?; + let cpusetsize = this.read_target_usize(cpusetsize)?; + let mask = this.read_pointer(mask)?; + + // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid + let thread_id = match pid { + 0 => this.active_thread(), + _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"), + }; + + #[allow(clippy::map_entry)] + if this.ptr_is_null(mask)? { + let einval = this.eval_libc("EFAULT"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else { + // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES` + let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; + // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES` + let bits_array: [u8;CpuAffinityMask::CPU_MASK_BYTES] = + std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0)); + match CpuAffinityMask::from_array(&this.tcx.sess.target, this.machine.num_cpus, bits_array) { + Some(cpuset) => { + this.machine.thread_cpu_affinity.insert(thread_id, cpuset); + this.write_scalar(Scalar::from_i32(0), dest)?; + } + None => { + // The intersection between the mask and the available CPUs was empty. + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } + } + } + } // Miscellaneous "isatty" => { diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e31d43d9190a..95bee38cd783 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -178,19 +178,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?; } - "sched_getaffinity" => { - // This shim isn't useful, aside from the fact that it makes `num_cpus` - // fall back to `sysconf` where it will successfully determine the number of CPUs. - let [pid, cpusetsize, mask] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(pid)?.to_i32()?; - this.read_target_usize(cpusetsize)?; - this.deref_pointer_as(mask, this.libc_ty_layout("cpu_set_t"))?; - // FIXME: we just return an error. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; - } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs new file mode 100644 index 000000000000..c41d1d18018c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs @@ -0,0 +1,17 @@ +//@ignore-target-windows: only very limited libc on Windows +//@ignore-target-apple: `sched_setaffinity` is not supported on macOS +//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 + +fn main() { + use libc::{cpu_set_t, sched_setaffinity}; + + use std::mem::size_of; + + // If pid is zero, then the calling thread is used. + const PID: i32 = 0; + + let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; //~ ERROR: memory access failed + assert_eq!(err, 0); +} diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr new file mode 100644 index 000000000000..c01f15800fac --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds + --> $DIR/affinity.rs:LL:CC + | +LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds + | + = 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 +help: ALLOC was allocated here: + --> $DIR/affinity.rs:LL:CC + | +LL | let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + | ^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/affinity.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-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs new file mode 100644 index 000000000000..d360864b97c3 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -0,0 +1,194 @@ +//@ignore-target-windows: only very limited libc on Windows +//@ignore-target-apple: `sched_{g, s}etaffinity` are not supported on macOS +//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 +#![feature(io_error_more)] +#![feature(pointer_is_aligned_to)] +#![feature(strict_provenance)] + +use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity}; +use std::mem::{size_of, size_of_val}; + +// If pid is zero, then the calling thread is used. +const PID: i32 = 0; + +fn null_pointers() { + let err = unsafe { sched_getaffinity(PID, size_of::(), std::ptr::null_mut()) }; + assert_eq!(err, -1); + + let err = unsafe { sched_setaffinity(PID, size_of::(), std::ptr::null()) }; + assert_eq!(err, -1); +} + +fn configure_no_cpus() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // configuring no CPUs will fail + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + + // configuring no (physically available) CPUs will fail + unsafe { libc::CPU_SET(cpu_count, &mut cpuset) }; + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); +} + +fn configure_unavailable_cpu() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + // Safety: valid value for this type + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // by default, only available CPUs are configured + for i in 0..cpu_count { + assert!(unsafe { libc::CPU_ISSET(i, &cpuset) }); + } + assert!(unsafe { !libc::CPU_ISSET(cpu_count, &cpuset) }); + + // configure CPU that we don't have + unsafe { libc::CPU_SET(cpu_count, &mut cpuset) }; + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // the CPU is not set because it is not available + assert!(!unsafe { libc::CPU_ISSET(cpu_count, &cpuset) }); +} + +fn large_set() { + // rust's libc does not currently implement dynamic cpu set allocation + // and related functions like `CPU_ZERO_S`. So we have to be creative + + // i.e. this has 2048 bits, twice the standard number + let mut cpuset = [u64::MAX; 32]; + + let err = unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) }; + assert_eq!(err, 0); + + let err = unsafe { sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) }; + assert_eq!(err, 0); +} + +fn get_small_cpu_mask() { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // should be 4 on 32-bit systems and 8 otherwise for systems that implement sched_getaffinity + let step = size_of::(); + + for i in (0..=2).map(|x| x * step) { + if i == 0 { + // 0 always fails + let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) }; + assert_eq!(err, -1, "fail for {}", i); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + } else { + // other whole multiples of the size of c_ulong works + let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) }; + assert_eq!(err, 0, "fail for {i}"); + } + + // anything else returns an error + for j in 1..step { + let err = unsafe { sched_getaffinity(PID, i + j, &mut cpuset) }; + assert_eq!(err, -1, "success for {}", i + j); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + } + } +} + +fn set_custom_cpu_mask() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread"); + + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // at the start, thread 1 should be set + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + assert!(unsafe { libc::CPU_ISSET(1, &cpuset) }); + + // make a valid mask + unsafe { libc::CPU_ZERO(&mut cpuset) }; + unsafe { libc::CPU_SET(0, &mut cpuset) }; + + // giving a smaller mask is fine + let err = unsafe { sched_setaffinity(PID, 8, &cpuset) }; + assert_eq!(err, 0); + + // and actually disables other threads + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) }); + + // it is important that we reset the cpu mask now for future tests + for i in 0..cpu_count { + unsafe { libc::CPU_SET(i, &mut cpuset) }; + } + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); +} + +fn parent_child() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread"); + + // configure the parent thread to only run only on CPU 0 + let mut parent_cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + unsafe { libc::CPU_SET(0, &mut parent_cpuset) }; + + let err = unsafe { sched_setaffinity(PID, size_of::(), &parent_cpuset) }; + assert_eq!(err, 0); + + std::thread::scope(|spawner| { + spawner.spawn(|| { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // the child inherits its parent's set + assert!(unsafe { libc::CPU_ISSET(0, &cpuset) }); + assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) }); + + // configure cpu 1 for the child + unsafe { libc::CPU_SET(1, &mut cpuset) }; + }); + }); + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut parent_cpuset) }; + assert_eq!(err, 0); + + // the parent's set should be unaffected + assert!(unsafe { !libc::CPU_ISSET(1, &parent_cpuset) }); + + // it is important that we reset the cpu mask now for future tests + let mut cpuset = parent_cpuset; + for i in 0..cpu_count { + unsafe { libc::CPU_SET(i, &mut cpuset) }; + } + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); +} + +fn main() { + null_pointers(); + configure_no_cpus(); + configure_unavailable_cpu(); + large_set(); + get_small_cpu_mask(); + set_custom_cpu_mask(); + parent_child(); +} From a5dc082d6f51b1df9dc0bf0daf365ccf933f46d5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 5 Jul 2024 15:43:12 +0000 Subject: [PATCH 101/361] Use windows_targets macro for alloc --- library/std/src/sys/pal/windows/alloc.rs | 129 +++++++++++------------ library/std/src/sys/pal/windows/c.rs | 2 +- 2 files changed, 64 insertions(+), 67 deletions(-) diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 24c237b5eb03..e6cbdb6ef7d6 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -4,7 +4,7 @@ use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering}; -use crate::sys::c; +use crate::sys::c::{self, windows_targets}; use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN}; use core::mem::MaybeUninit; @@ -17,74 +17,71 @@ mod tests; // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed. const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008; -#[link(name = "kernel32")] -extern "system" { - // Get a handle to the default heap of the current process, or null if the operation fails. - // - // SAFETY: Successful calls to this function within the same process are assumed to - // always return the same handle, which remains valid for the entire lifetime of the process. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap - fn GetProcessHeap() -> c::HANDLE; +// Get a handle to the default heap of the current process, or null if the operation fails. +// +// SAFETY: Successful calls to this function within the same process are assumed to +// always return the same handle, which remains valid for the entire lifetime of the process. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap +windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE); - // Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`. - // The allocated memory may be uninitialized, or zeroed if `dwFlags` is - // set to `HEAP_ZERO_MEMORY`. - // - // Returns a pointer to the newly-allocated memory or null if the operation fails. - // The returned pointer will be aligned to at least `MIN_ALIGN`. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`. - // - // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc - fn HeapAlloc(hHeap: c::HANDLE, dwFlags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID; +// Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`. +// The allocated memory may be uninitialized, or zeroed if `dwFlags` is +// set to `HEAP_ZERO_MEMORY`. +// +// Returns a pointer to the newly-allocated memory or null if the operation fails. +// The returned pointer will be aligned to at least `MIN_ALIGN`. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`. +// +// Note that `dwBytes` is allowed to be zero, contrary to some other allocators. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc +windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void); - // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, - // to a block of at least `dwBytes` bytes, either shrinking the block in place, - // or allocating at a new location, copying memory, and freeing the original location. - // - // Returns a pointer to the reallocated memory or null if the operation fails. - // The returned pointer will be aligned to at least `MIN_ALIGN`. - // If the operation fails the given block will never have been freed. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to zero. - // - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or - // `HeapReAlloc`, that has not already been freed. - // If the block was successfully reallocated at a new location, pointers pointing to - // the freed memory, such as `lpMem`, must not be dereferenced ever again. - // - // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc - fn HeapReAlloc( - hHeap: c::HANDLE, - dwFlags: c::DWORD, - lpMem: c::LPVOID, - dwBytes: c::SIZE_T, - ) -> c::LPVOID; +// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, +// to a block of at least `dwBytes` bytes, either shrinking the block in place, +// or allocating at a new location, copying memory, and freeing the original location. +// +// Returns a pointer to the reallocated memory or null if the operation fails. +// The returned pointer will be aligned to at least `MIN_ALIGN`. +// If the operation fails the given block will never have been freed. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to zero. +// - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or +// `HeapReAlloc`, that has not already been freed. +// If the block was successfully reallocated at a new location, pointers pointing to +// the freed memory, such as `lpMem`, must not be dereferenced ever again. +// +// Note that `dwBytes` is allowed to be zero, contrary to some other allocators. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc +windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( + hheap: c::HANDLE, + dwflags : u32, + lpmem: *const core::ffi::c_void, + dwbytes: usize +) -> *mut core::ffi::c_void); - // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. - // Returns a nonzero value if the operation is successful, and zero if the operation fails. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to zero. - // - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`, - // that has not already been freed. - // If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`, - // must not be dereferenced ever again. - // - // Note that `lpMem` is allowed to be null, which will not cause the operation to fail. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree - fn HeapFree(hHeap: c::HANDLE, dwFlags: c::DWORD, lpMem: c::LPVOID) -> c::BOOL; -} +// Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. +// Returns a nonzero value if the operation is successful, and zero if the operation fails. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to zero. +// - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`, +// that has not already been freed. +// If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`, +// must not be dereferenced ever again. +// +// Note that `lpMem` is allowed to be null, which will not cause the operation to fail. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree +windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL); // Cached handle to the default heap of the current process. // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 27aa35f69f1b..7dfda4f714c7 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -13,7 +13,7 @@ use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_vo use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; -mod windows_targets; +pub(super) mod windows_targets; mod windows_sys; pub use windows_sys::*; From e136f08a6f4f784d1a1751aced5bf919bb094436 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 5 Jul 2024 14:04:26 +0000 Subject: [PATCH 102/361] Add experimental raw-dylib feature to std For Windows, this allows defining imports without needing the user to have import libraries. It's intended for this to become the default. --- library/std/Cargo.toml | 4 ++++ .../std/src/sys/pal/windows/c/windows_targets.rs | 13 +++++++++++++ library/sysroot/Cargo.toml | 1 + 3 files changed, 18 insertions(+) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 358510b8f77d..b991b1cf22dd 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -87,6 +87,10 @@ 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. +windows_raw_dylib = [] + [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing threads = 125 diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs index 56c563462d36..252bceb70942 100644 --- a/library/std/src/sys/pal/windows/c/windows_targets.rs +++ b/library/std/src/sys/pal/windows/c/windows_targets.rs @@ -3,6 +3,18 @@ //! This is a simple wrapper around an `extern` block with a `#[link]` attribute. //! It's very roughly equivalent to the windows-targets crate. +#[cfg(feature = "windows_raw_dylib")] +pub macro link { + ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] + #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] + extern $abi { + $(#[link_name=$link_name])? + pub fn $($function)*; + } + ) +} +#[cfg(not(feature = "windows_raw_dylib"))] pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't @@ -17,6 +29,7 @@ pub macro link { ) } +#[cfg(not(feature = "windows_raw_dylib"))] #[link(name = "advapi32")] #[link(name = "ntdll")] #[link(name = "userenv")] diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 1ddacd92e6b9..169eeeca8c2e 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -27,3 +27,4 @@ profiler = ["std/profiler"] 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 de14f1f932f4f11130be3fed5cd370bd0936032e Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 5 Jul 2024 16:34:32 -0400 Subject: [PATCH 103/361] add test that multi-threaded panics aren't interleaved --- tests/ui/backtrace/synchronized-panic-handler.rs | 15 +++++++++++++++ .../synchronized-panic-handler.run.stderr | 5 +++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/backtrace/synchronized-panic-handler.rs create mode 100644 tests/ui/backtrace/synchronized-panic-handler.run.stderr diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs new file mode 100644 index 000000000000..0ea285968d59 --- /dev/null +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -0,0 +1,15 @@ +//@ run-pass +//@ check-run-results +//@ edition:2021 +use std::thread; +const PANIC_MESSAGE: &str = "oops oh no woe is me"; + +fn entry() { + panic!("{PANIC_MESSAGE}") +} + +fn main() { + let (a, b) = (thread::spawn(entry), thread::spawn(entry)); + assert_eq!(&**a.join().unwrap_err().downcast::().unwrap(), PANIC_MESSAGE); + assert_eq!(&**b.join().unwrap_err().downcast::().unwrap(), PANIC_MESSAGE); +} diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr new file mode 100644 index 000000000000..06ef53836c26 --- /dev/null +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -0,0 +1,5 @@ +thread '' panicked at $DIR/synchronized-panic-handler.rs:thread '8:5' panicked at : +oops oh no woe is me$DIR/synchronized-panic-handler.rs +:note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +8:5: +oops oh no woe is me From 9de76e3201a557f0ea9b076c8b38629c5f2b60d0 Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:45:03 -0500 Subject: [PATCH 104/361] Update library/std/src/sys/pal/common/exit_guard.rs Co-authored-by: Ralf Jung --- library/std/src/sys/pal/common/exit_guard.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/pal/common/exit_guard.rs index eb2c14cdecc7..a1b0309b003e 100644 --- a/library/std/src/sys/pal/common/exit_guard.rs +++ b/library/std/src/sys/pal/common/exit_guard.rs @@ -2,12 +2,14 @@ cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { /// Mitigation for /// - /// On UNIX-like platforms (where `libc::exit` may not be thread-safe), ensure that only one + /// On glibc, `libc::exit` has been observed to not always be thread-safe. + /// It is currently unclear whether that is a glibc bug or allowed by the standard. + /// To mitigate this problem, we ensure that only one /// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before /// calling `libc::exit` (or returning from `main`). /// - /// Technically not enough to ensure soundness, since other code directly calling - /// libc::exit will still race with this. + /// Technically, this is not enough to ensure soundness, since other code directly calling + /// `libc::exit` will still race with this. /// /// *This function does not itself call `libc::exit`.* This is so it can also be used /// to guard returning from `main`. From a6093701437be909614bc49d63406dfaa63d3b13 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 5 Jul 2024 16:59:57 -0500 Subject: [PATCH 105/361] Move exit guard from sys::common::exit_guard to sys::exit_guard. --- library/std/src/rt.rs | 3 +-- library/std/src/sys/{pal/common => }/exit_guard.rs | 0 library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/common/mod.rs | 1 - library/std/src/sys/pal/unix/os.rs | 2 +- 5 files changed, 3 insertions(+), 4 deletions(-) rename library/std/src/sys/{pal/common => }/exit_guard.rs (100%) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 8a6f3fe291a7..c0a1c5f5594a 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -146,8 +146,7 @@ fn lang_start_internal( panic::catch_unwind(cleanup).map_err(rt_abort)?; // Guard against multple threads calling `libc::exit` concurrently. // See the documentation for `unique_thread_exit` for more information. - panic::catch_unwind(|| crate::sys::common::exit_guard::unique_thread_exit()) - .map_err(rt_abort)?; + panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?; ret_code } diff --git a/library/std/src/sys/pal/common/exit_guard.rs b/library/std/src/sys/exit_guard.rs similarity index 100% rename from library/std/src/sys/pal/common/exit_guard.rs rename to library/std/src/sys/exit_guard.rs diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8aa35c40fe05..22ebc979bf7e 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -3,6 +3,7 @@ /// descriptors. mod pal; +pub(crate) mod exit_guard; mod personality; pub mod backtrace; diff --git a/library/std/src/sys/pal/common/mod.rs b/library/std/src/sys/pal/common/mod.rs index cc1dceb63e2f..29fc0835d766 100644 --- a/library/std/src/sys/pal/common/mod.rs +++ b/library/std/src/sys/pal/common/mod.rs @@ -11,7 +11,6 @@ #![allow(dead_code)] pub mod alloc; -pub mod exit_guard; pub mod small_c_string; #[cfg(test)] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 3f598a095c15..397a0debe58c 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -758,7 +758,7 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { - crate::sys::common::exit_guard::unique_thread_exit(); + crate::sys::exit_guard::unique_thread_exit(); unsafe { libc::exit(code as c_int) } } From ecbb2d7ba95b94a25df55a01669d8cda080b7011 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 6 Jul 2024 00:51:58 +0200 Subject: [PATCH 106/361] remove internal `compiler_lint_functions` lint --- clippy.toml | 4 + clippy_lints/src/declared_lints.rs | 2 - clippy_lints/src/lib.rs | 3 - clippy_lints/src/utils/internal_lints.rs | 1 - .../internal_lints/compiler_lint_functions.rs | 73 ------------------- 5 files changed, 4 insertions(+), 79 deletions(-) delete mode 100644 clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs diff --git a/clippy.toml b/clippy.toml index 62ed55beb1f3..319b72e8c5d5 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,5 +1,9 @@ avoid-breaking-exported-api = false +[[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" + [[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" diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 50661bf46a0a..8ba5fa6a5608 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_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, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8a9d3b43fb3a..5de31d50156e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -641,9 +641,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); 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::compiler_lint_functions::CompilerLintFunctions::new()) - }); store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); store.register_late_pass(|_| { Box::::default() diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 877a77fd6d24..1d294c2944b2 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,5 @@ pub mod almost_standard_lint_formulation; pub mod collapsible_calls; -pub mod compiler_lint_functions; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs deleted file mode 100644 index 9b6b68718186..000000000000 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ /dev/null @@ -1,73 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::match_type; -use clippy_utils::{is_lint_allowed, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*` - /// variant of the function. - /// - /// ### Why is this bad? - /// The `utils::*` variants also add a link to the Clippy documentation to the - /// warning/error messages. - /// - /// ### Example - /// ```rust,ignore - /// cx.span_lint(LINT_NAME, "message"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// utils::span_lint(cx, LINT_NAME, "message"); - /// ``` - pub COMPILER_LINT_FUNCTIONS, - internal, - "usage of the lint functions of the compiler instead of the utils::* variant" -} - -impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]); - -#[derive(Clone, Default)] -pub struct CompilerLintFunctions { - map: FxHashMap<&'static str, &'static str>, -} - -impl CompilerLintFunctions { - #[must_use] - pub fn new() -> Self { - let mut map = FxHashMap::default(); - map.insert("span_lint", "utils::span_lint"); - map.insert("lint", "utils::span_lint"); - map.insert("span_lint_note", "utils::span_lint_and_note"); - map.insert("span_lint_help", "utils::span_lint_and_help"); - Self { map } - } -} - -impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) { - return; - } - - if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind - && let fn_name = path.ident - && let Some(sugg) = self.map.get(fn_name.as_str()) - && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() - && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT)) - { - span_lint_and_help( - cx, - COMPILER_LINT_FUNCTIONS, - path.ident.span, - "usage of a compiler lint function", - None, - format!("please use the Clippy variant of this function: `{sugg}`"), - ); - } - } -} From 5db165504ada6fde86f93d275a0d6380263ee381 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 5 Jul 2024 17:59:46 -0500 Subject: [PATCH 107/361] Attempt to fix CI --- library/std/src/sys/exit_guard.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index a1b0309b003e..ad6246cc8318 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -19,6 +19,7 @@ cfg_if::cfg_if! { /// * If it is called again on the same thread as the first call, it will abort. /// * If it is called again on a different thread, it will wait in a loop /// (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}; @@ -54,6 +55,7 @@ cfg_if::cfg_if! { /// /// Mitigation is ***NOT*** implemented on this platform, either because this platform /// is not affected, or because mitigation is not yet implemented for this platform. + #[cfg_attr(any(test, doctest), allow(dead_code))] pub(crate) fn unique_thread_exit() { // Mitigation not required on platforms where `exit` is thread-safe. } From d8fb164a7cfde2cdd70d2070b6e01d70a65217aa Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 15:46:39 -0400 Subject: [PATCH 108/361] Rename `any_parent_is_automatically_derived` to `in_automatically_derived`. Only check for the attribute on an impl block. --- clippy_lints/src/default.rs | 10 +++++----- clippy_lints/src/misc.rs | 6 +++--- clippy_lints/src/no_effect.rs | 4 ++-- clippy_utils/src/lib.rs | 19 +++++++++++++++---- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 2b3f4854255c..72fa05be3cc6 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // Avoid cases already linted by `field_reassign_with_default` && !self.reassigned_linted.contains(&expr.span) && let ExprKind::Call(path, ..) = expr.kind - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::default_fn, def_id) @@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding let stmts_head = match block.stmts { + [] | [_] => return, // Skip the last statement since there cannot possibly be any following statements that re-assign fields. - [head @ .., _] if !head.is_empty() => head, - _ => return, + [head @ .., _] => head, }; for (stmt_idx, stmt) in stmts_head.iter().enumerate() { // find all binding statements like `let mut _ = T::default()` where `T::default()` is the @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind // only take `let ...` statements && let Some(expr) = local.init - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && !expr.span.from_expansion() // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index f3f9bf11a61c..32c8731c5374 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats, - last_path_segment, SpanlessEq, + fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, + SpanlessEq, }; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || expr.span.desugaring_kind().is_some() - || any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + || in_automatically_derived(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 139c33d3f4a4..0ecfa7baa72d 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; use clippy_utils::{ - any_parent_is_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, + in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -187,7 +187,7 @@ impl NoEffect { && has_no_effect(cx, init) && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && ident.name.to_ident_string().starts_with('_') - && !any_parent_is_automatically_derived(cx.tcx, local.hir_id) + && !in_automatically_derived(cx.tcx, local.hir_id) { if let Some(l) = self.local_bindings.last_mut() { l.push(hir_id); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 28d1eeb4e28c..c24cb12845ba 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -103,8 +103,9 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, - ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, - PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -1924,8 +1925,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool false } -pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { - any_parent_has_attr(tcx, node, sym::automatically_derived) +/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived` +/// attribute. +pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.hir() + .parent_owner_iter(id) + .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_)))) + .any(|(id, _)| { + has_attr( + tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)), + sym::automatically_derived, + ) + }) } /// Matches a function call with the given path and returns the arguments. From 4b69da91c1a05db55b7661120ca2b201e4aa6133 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 6 Jul 2024 05:13:08 +0000 Subject: [PATCH 109/361] 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 dd5355134c5e..25d559d789fd 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -51917ba8f215f76e9d3fa8e77cd0a781bb28dab7 +51917e2e69702e5752bce6a4f3bfd285d0f4ae39 From 9a0e671cc28d0b95ec238f858cecbf765fdf7f7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2024 11:24:11 +0200 Subject: [PATCH 110/361] lookup c_ulong instead of hard-coding the chunk size --- .../miri/src/concurrency/cpu_affinity.rs | 39 ++++++------- src/tools/miri/src/eval.rs | 3 +- src/tools/miri/src/helpers.rs | 55 +++++++++++-------- src/tools/miri/src/machine.rs | 6 +- .../miri/src/shims/unix/foreign_items.rs | 12 ++-- 5 files changed, 58 insertions(+), 57 deletions(-) diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs index 085900ac3aa6..8df26d718bf6 100644 --- a/src/tools/miri/src/concurrency/cpu_affinity.rs +++ b/src/tools/miri/src/concurrency/cpu_affinity.rs @@ -1,6 +1,8 @@ -use crate::bug; +use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::Endian; +use crate::*; + /// The maximum number of CPUs supported by miri. /// /// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number @@ -19,41 +21,34 @@ pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]); impl CpuAffinityMask { pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8; - pub fn new(target: &rustc_target::spec::Target, cpu_count: u32) -> Self { + pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self { let mut this = Self([0; Self::CPU_MASK_BYTES]); // the default affinity mask includes only the available CPUs for i in 0..cpu_count as usize { - this.set(target, i); + this.set(cx, i); } this } - pub fn chunk_size(target: &rustc_target::spec::Target) -> u64 { - // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either - // - // - [u32; 32] on 32-bit platforms - // - [u64; 16] everywhere else - - // FIXME: this should be `size_of::()` - u64::from(target.pointer_width / 8) + pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 { + // The actual representation of the CpuAffinityMask is [c_ulong; _]. + let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]); + ulong.size.bytes() } - fn set(&mut self, target: &rustc_target::spec::Target, cpu: usize) { + fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) { // we silently ignore CPUs that are out of bounds. This matches the behavior of // `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs. if cpu >= MAX_CPUS { return; } - // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either - // - // - [u32; 32] on 32-bit platforms - // - [u64; 16] everywhere else - // + // The actual representation of the CpuAffinityMask is [c_ulong; _]. // Within the array elements, we need to use the endianness of the target. - match Self::chunk_size(target) { + let target = &cx.tcx().sess.target; + match Self::chunk_size(cx) { 4 => { let start = cpu / 32 * 4; // first byte of the correct u32 let chunk = self.0[start..].first_chunk_mut::<4>().unwrap(); @@ -72,7 +67,7 @@ impl CpuAffinityMask { Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), }; } - other => bug!("other chunk sizes are not supported: {other}"), + other => bug!("chunk size not supported: {other}"), }; } @@ -80,13 +75,13 @@ impl CpuAffinityMask { self.0.as_slice() } - pub fn from_array( - target: &rustc_target::spec::Target, + pub fn from_array<'tcx>( + cx: &impl LayoutOf<'tcx>, cpu_count: u32, bytes: [u8; Self::CPU_MASK_BYTES], ) -> Option { // mask by what CPUs are actually available - let default = Self::new(target, cpu_count); + let default = Self::new(cx, cpu_count); let masked = std::array::from_fn(|i| bytes[i] & default.0[i]); // at least one thread must be set for the input to be valid diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 9142b8b5fdbc..2184a4426c8d 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>( })?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS); + let sentinel = + helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS); if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) { tcx.dcx().fatal( "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \ diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 590e8984e990..ba094c988e5a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -18,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::mir; +use rustc_middle::ty::layout::MaybeResult; use rustc_middle::ty::{ self, layout::{LayoutOf, TyAndLayout}, @@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) None } +/// Gets an instance for a path; fails gracefully if the path does not exist. +pub fn try_resolve_path<'tcx>( + tcx: TyCtxt<'tcx>, + path: &[&str], + namespace: Namespace, +) -> Option> { + let did = try_resolve_did(tcx, path, Some(namespace))?; + Some(ty::Instance::mono(tcx, did)) +} + +/// Gets an instance for a path. +#[track_caller] +pub fn resolve_path<'tcx>( + tcx: TyCtxt<'tcx>, + path: &[&str], + namespace: Namespace, +) -> ty::Instance<'tcx> { + try_resolve_path(tcx, path, namespace) + .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}")) +} + +/// Gets the layout of a type at a path. +#[track_caller] +pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> { + let ty = + resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all()); + cx.layout_of(ty).to_result().ok().unwrap() +} + /// Call `f` for each exported symbol. pub fn iter_exported_symbols<'tcx>( tcx: TyCtxt<'tcx>, @@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some() } - /// Gets an instance for a path; fails gracefully if the path does not exist. - fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option> { - let tcx = self.eval_context_ref().tcx.tcx; - let did = try_resolve_did(tcx, path, Some(namespace))?; - Some(ty::Instance::mono(tcx, did)) - } - - /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> { - self.try_resolve_path(path, namespace) - .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}")) - } - /// Evaluates the scalar at the specified path. fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> { let this = self.eval_context_ref(); - let instance = this.resolve_path(path, Namespace::ValueNS); + let instance = resolve_path(*this.tcx, path, Namespace::ValueNS); // We don't give a span -- this isn't actually used directly by the program anyway. let const_val = this.eval_global(instance).unwrap_or_else(|err| { panic!("failed to evaluate required Rust item: {path:?}\n{err:?}") @@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "`libc` crate is not reliably available on Windows targets; Miri should not use it there" ); } - let ty = this - .resolve_path(&["libc", name], Namespace::TypeNS) - .ty(*this.tcx, ty::ParamEnv::reveal_all()); - this.layout_of(ty).unwrap() + path_ty_layout(this, &["libc", name]) } /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> { let this = self.eval_context_ref(); - let ty = this - .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS) - .ty(*this.tcx, ty::ParamEnv::reveal_all()); - this.layout_of(ty).unwrap() + path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name]) } /// Project to the given *named* field (which must be a struct or union type). diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fee6ab068175..02bfd6ec8150 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -643,10 +643,8 @@ impl<'tcx> MiriMachine<'tcx> { let threads = ThreadManager::default(); let mut thread_cpu_affinity = FxHashMap::default(); if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") { - thread_cpu_affinity.insert( - threads.active_thread(), - CpuAffinityMask::new(&tcx.sess.target, config.num_cpus), - ); + thread_cpu_affinity + .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus)); } MiriMachine { tcx, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f5d3e0b536be..f1bae8646d31 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -594,11 +594,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"), }; - // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either - // - // - [u32; 32] on 32-bit platforms - // - [u64; 16] everywhere else - let chunk_size = CpuAffinityMask::chunk_size(&this.tcx.sess.target); + // The mask is stored in chunks, and the size must be a whole number of chunks. + let chunk_size = CpuAffinityMask::chunk_size(this); if this.ptr_is_null(mask)? { let einval = this.eval_libc("EFAULT"); @@ -643,7 +640,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"), }; - #[allow(clippy::map_entry)] if this.ptr_is_null(mask)? { let einval = this.eval_libc("EFAULT"); this.set_last_error(einval)?; @@ -652,9 +648,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES` let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES` - let bits_array: [u8;CpuAffinityMask::CPU_MASK_BYTES] = + let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] = std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0)); - match CpuAffinityMask::from_array(&this.tcx.sess.target, this.machine.num_cpus, bits_array) { + match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) { Some(cpuset) => { this.machine.thread_cpu_affinity.insert(thread_id, cpuset); this.write_scalar(Scalar::from_i32(0), dest)?; From 46019523e8bc5096ae452a39073aed06a6c45e1f Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 6 Jul 2024 12:02:17 +0200 Subject: [PATCH 111/361] `sched_setaffinity`: test `cpusetsize == 0` --- .../miri/src/shims/unix/foreign_items.rs | 4 +++- .../miri/tests/pass-dep/libc/libc-affinity.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f1bae8646d31..3a18d6220333 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -645,7 +645,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.set_last_error(einval)?; this.write_scalar(Scalar::from_i32(-1), dest)?; } else { - // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES` + // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. + // Any unspecified bytes are treated as zero here (none of the CPUs are configured). + // This is not exactly documented, so we assume that this is the behavior in practice. let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES` let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] = diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index d360864b97c3..ac3001745db8 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -105,6 +105,24 @@ fn get_small_cpu_mask() { } } +fn set_small_cpu_mask() { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // setting a mask of size 0 is invalid + let err = unsafe { sched_setaffinity(PID, 0, &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + + // any other number of bytes (at least up to `size_of()` will work + for i in 1..24 { + let err = unsafe { sched_setaffinity(PID, i, &cpuset) }; + assert_eq!(err, 0, "fail for {i}"); + } +} + fn set_custom_cpu_mask() { let cpu_count = std::thread::available_parallelism().unwrap().get(); @@ -189,6 +207,7 @@ fn main() { configure_unavailable_cpu(); large_set(); get_small_cpu_mask(); + set_small_cpu_mask(); set_custom_cpu_mask(); parent_child(); } From 585ca16e0bfa14e4f1d4b9235926034385bf9d7b Mon Sep 17 00:00:00 2001 From: Greaka Date: Sat, 6 Jul 2024 13:49:02 +0200 Subject: [PATCH 112/361] as_simd: fix comment to be in line with 507583a (#121201) --- library/core/src/slice/mod.rs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 521c32482044..68508e85f8e1 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3959,17 +3959,8 @@ impl [T] { /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix. /// - /// This is a safe wrapper around [`slice::align_to`], so has the same weak - /// postconditions as that method. You're only assured that - /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`. - /// - /// Notably, all of the following are possible: - /// - `prefix.len() >= LANES`. - /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`. - /// - `suffix.len() >= LANES`. - /// - /// That said, this is a safe method, so if you're only writing safe code, - /// then this can at most cause incorrect logic, not unsoundness. + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. /// /// # Panics /// @@ -4033,17 +4024,8 @@ impl [T] { /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types, /// and a mutable suffix. /// - /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak - /// postconditions as that method. You're only assured that - /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`. - /// - /// Notably, all of the following are possible: - /// - `prefix.len() >= LANES`. - /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`. - /// - `suffix.len() >= LANES`. - /// - /// That said, this is a safe method, so if you're only writing safe code, - /// then this can at most cause incorrect logic, not unsoundness. + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. /// /// This is the mutable version of [`slice::as_simd`]; see that for examples. /// From d65e3688df6a282667aed91cea2c7ecfeb636313 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 6 Jul 2024 14:06:07 +0200 Subject: [PATCH 113/361] `sched_setaffinity`: adjust test on BE systems --- src/tools/miri/tests/pass-dep/libc/libc-affinity.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index ac3001745db8..0e482ab26010 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -116,8 +116,13 @@ fn set_small_cpu_mask() { assert_eq!(err, -1); assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); - // any other number of bytes (at least up to `size_of()` will work - for i in 1..24 { + // on LE systems, any other number of bytes (at least up to `size_of()`) will work. + // on BE systems the CPUs 0..8 are stored in the right-most byte of the first chunk. If that + // byte is not included, no valid CPUs are configured. We skip those cases. + let cpu_zero_included_length = + if cfg!(target_endian = "little") { 1 } else { core::mem::size_of::() }; + + for i in cpu_zero_included_length..24 { let err = unsafe { sched_setaffinity(PID, i, &cpuset) }; assert_eq!(err, 0, "fail for {i}"); } From e0f32e09de8697ffb3fde577ce8730da6cb1367a Mon Sep 17 00:00:00 2001 From: lukas Date: Thu, 4 Jul 2024 16:47:20 +0200 Subject: [PATCH 114/361] Mark format! with must_use hint --- tests/ui/or_fun_call.fixed | 2 +- tests/ui/or_fun_call.stderr | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 7657ef470c58..c76f7a81843b 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -98,7 +98,7 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; - let _ = opt.ok_or(format!("{} world.", hello)); + let _ = opt.ok_or_else(|| format!("{} world.", hello)); // index let map = HashMap::::new(); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index b5a30f299231..3070db22fc5a 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -100,6 +100,12 @@ error: use of `unwrap_or` to construct default value LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` +error: use of `ok_or` followed by a function call + --> tests/ui/or_fun_call.rs:101:17 + | +LL | let _ = opt.ok_or(format!("{} world.", hello)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))` + error: use of `unwrap_or` followed by a function call --> tests/ui/or_fun_call.rs:105:21 | @@ -190,5 +196,5 @@ error: use of `unwrap_or_else` to construct default value LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: aborting due to 31 previous errors +error: aborting due to 32 previous errors From 335bdd4eec418f3572ef532e111979681e14602c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 4 Jul 2024 17:04:16 +0300 Subject: [PATCH 115/361] handle ci-rustc incompatible options during config parse This change ensures that `config.toml` does not use CI rustc incompatible options when CI rustc is enabled. This is necessary because some options can change compiler's behavior in certain scenarios. The list may not be complete, but should be a good first step as it's better than nothing! Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 125 ++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 948f97e746f4..29bdb3be2ada 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -33,7 +33,7 @@ macro_rules! check_ci_llvm { assert!( $name.is_none(), "setting {} is incompatible with download-ci-llvm.", - stringify!($name) + stringify!($name).replace("_", "-") ); }; } @@ -1547,7 +1547,15 @@ impl Config { let mut lld_enabled = None; let mut is_user_configured_rust_channel = false; + if let Some(rust) = toml.rust { + config.download_rustc_commit = + config.download_ci_rustc_commit(rust.download_rustc.clone()); + + if config.download_rustc_commit.is_some() { + check_incompatible_options_for_ci_rustc(&rust); + } + let Rust { optimize: optimize_toml, debug: debug_toml, @@ -1595,7 +1603,7 @@ impl Config { new_symbol_mangling, profile_generate, profile_use, - download_rustc, + download_rustc: _, lto, validate_mir_opts, frame_pointers, @@ -1605,11 +1613,7 @@ impl Config { } = rust; is_user_configured_rust_channel = channel.is_some(); - set(&mut config.channel, channel); - - config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc); - - // FIXME: handle download-rustc incompatible options. + set(&mut config.channel, channel.clone()); debug = debug_toml; debug_assertions = debug_assertions_toml; @@ -2591,6 +2595,113 @@ impl Config { } } +/// Checks the CI rustc incompatible options by destructuring the `Rust` instance +/// and makes sure that no rust options from config.toml are missed. +fn check_incompatible_options_for_ci_rustc(rust: &Rust) { + macro_rules! err { + ($name:expr) => { + assert!( + $name.is_none(), + "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`.", + stringify!($name).replace("_", "-") + ); + }; + } + + macro_rules! warn { + ($name:expr) => { + if $name.is_some() { + println!( + "WARNING: `rust.{}` has no effect with `rust.download-rustc`.", + stringify!($name).replace("_", "-") + ); + } + }; + } + + let Rust { + // Following options are the CI rustc incompatible ones. + optimize, + debug_logging, + debuginfo_level_rustc, + llvm_tools, + llvm_bitcode_linker, + lto, + stack_protector, + strip, + lld_mode, + jemalloc, + rpath, + channel, + description, + incremental, + default_linker, + + // Rest of the options can simply be ignored. + debug: _, + codegen_units: _, + codegen_units_std: _, + debug_assertions: _, + debug_assertions_std: _, + overflow_checks: _, + overflow_checks_std: _, + debuginfo_level: _, + debuginfo_level_std: _, + debuginfo_level_tools: _, + debuginfo_level_tests: _, + split_debuginfo: _, + backtrace: _, + parallel_compiler: _, + musl_root: _, + verbose_tests: _, + optimize_tests: _, + codegen_tests: _, + omit_git_hash: _, + dist_src: _, + save_toolstates: _, + codegen_backends: _, + lld: _, + deny_warnings: _, + backtrace_on_ice: _, + verify_llvm_ir: _, + thin_lto_import_instr_limit: _, + remap_debuginfo: _, + test_compare_mode: _, + llvm_libunwind: _, + control_flow_guard: _, + ehcont_guard: _, + new_symbol_mangling: _, + profile_generate: _, + profile_use: _, + download_rustc: _, + validate_mir_opts: _, + frame_pointers: _, + } = rust; + + // There are two kinds of checks for CI rustc incompatible options: + // 1. Checking an option that may change the compiler behaviour/output. + // 2. Checking an option that have no effect on the compiler behaviour/output. + // + // If the option belongs to the first category, we call `err` macro for a hard error; + // otherwise, we just print a warning with `warn` macro. + err!(optimize); + err!(debug_logging); + err!(debuginfo_level_rustc); + err!(default_linker); + err!(rpath); + err!(strip); + err!(stack_protector); + err!(lld_mode); + err!(llvm_tools); + err!(llvm_bitcode_linker); + err!(jemalloc); + err!(lto); + + warn!(channel); + warn!(description); + warn!(incremental); +} + fn set(field: &mut T, val: Option) { if let Some(v) = val { *field = v; From f6c377c350d7946881449daac2039a09b1734b46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 May 2024 12:52:38 +0200 Subject: [PATCH 116/361] offset_from intrinsic: always allow pointers to point to the same address --- .../src/interpret/intrinsics.rs | 33 ++++++++++--------- library/core/src/ptr/const_ptr.rs | 12 +++---- library/core/src/ptr/mut_ptr.rs | 12 +++---- library/core/src/ptr/non_null.rs | 13 ++++---- .../pass/zero-sized-accesses-and-offsets.rs | 3 -- tests/ui/consts/offset_from_ub.rs | 33 +++++++++++-------- tests/ui/consts/offset_from_ub.stderr | 22 ++++++------- 7 files changed, 67 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d86f1a7a34f2..b227565f8f91 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -20,7 +20,7 @@ use super::{ err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom, throw_ub_format, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, - Scalar, + Provenance, Scalar, }; use crate::fluent_generated as fluent; @@ -259,25 +259,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // This will always return 0. (a, b) } - (Err(_), _) | (_, Err(_)) => { - // We managed to find a valid allocation for one pointer, but not the other. - // That means they are definitely not pointing to the same allocation. + _ if M::Provenance::OFFSET_IS_ADDR && a.addr() == b.addr() => { + // At least one of the pointers has provenance, but they also point to + // the same address so it doesn't matter; this is fine. `(0, 0)` means + // we pass all the checks below and return 0. + (0, 0) + } + // From here onwards, the pointers are definitely for different addresses + // (or we can't determine their absolute address). + (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) + if a_alloc_id == b_alloc_id => + { + // Found allocation for both, and it's the same. + // Use these offsets for distance calculation. + (a_offset.bytes(), b_offset.bytes()) + } + _ => { + // Not into the same allocation -- this is UB. throw_ub_custom!( fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ); } - (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => { - // Found allocation for both. They must be into the same allocation. - if a_alloc_id != b_alloc_id { - throw_ub_custom!( - fluent::const_eval_offset_from_different_allocations, - name = intrinsic_name, - ); - } - // Use these offsets for distance calculation. - (a_offset.bytes(), b_offset.bytes()) - } }; // Compute distance. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 68cf82034334..3e7933e9eec8 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -604,9 +604,9 @@ impl *const T { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -653,14 +653,14 @@ impl *const T { /// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8; /// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8; /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff).wrapping_offset(1); /// assert_eq!(ptr2 as usize, ptr2_other as usize); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// unsafe { - /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️ /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 0dc910db5b9b..904d6c62dcf1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -829,9 +829,9 @@ impl *mut T { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -878,14 +878,14 @@ impl *mut T { /// let ptr1 = Box::into_raw(Box::new(0u8)); /// let ptr2 = Box::into_raw(Box::new(1u8)); /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff).wrapping_offset(1); /// assert_eq!(ptr2 as usize, ptr2_other as usize); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// unsafe { - /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️ /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 75a99e14fdad..07e4df1f02d8 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -735,9 +735,9 @@ impl NonNull { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -789,14 +789,15 @@ impl NonNull { /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap(); /// let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap(); /// let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff)).unwrap(); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let diff_plus_1 = diff.wrapping_add(1); + /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff_plus_1)).unwrap(); /// assert_eq!(ptr2.addr(), ptr2_other.addr()); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// - /// let zero = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior + /// let one = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior! ⚠️ /// ``` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs index 2d142bef73c4..a3356b682a6a 100644 --- a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs +++ b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs @@ -39,8 +39,6 @@ fn test_ptr(ptr: *mut ()) { // Distance. let ptr = ptr.cast::(); ptr.offset_from(ptr); - /* - FIXME: this is disabled for now as these cases are not yet allowed. // Distance from other "bad" pointers that have the same address, but different provenance. Some // of this is library UB, but we don't want it to be language UB since that would violate // provenance monotonicity: if we allow computing the distance between two ptrs with no @@ -54,6 +52,5 @@ fn test_ptr(ptr: *mut ()) { // - Distance from use-after-free pointer drop(b); ptr.offset_from(other_ptr.with_addr(ptr.addr())); - */ } } diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index e71f88b8d5fa..1506c212fbae 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -32,12 +32,6 @@ pub const NOT_MULTIPLE_OF_SIZE: isize = { //~| 1_isize cannot be divided by 2_isize without remainder }; -pub const OFFSET_FROM_NULL: isize = { - let ptr = 0 as *const u8; - // Null isn't special for zero-sized "accesses" (i.e., the range between the two pointers) - unsafe { ptr_offset_from(ptr, ptr) } -}; - pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; @@ -63,14 +57,6 @@ const OUT_OF_BOUNDS_2: isize = { //~| pointer to 10 bytes starting at offset 0 is out-of-bounds }; -const OUT_OF_BOUNDS_SAME: isize = { - let start_ptr = &4 as *const _ as *const u8; - let length = 10; - let end_ptr = (start_ptr).wrapping_add(length); - // Out-of-bounds is fine as long as the range between the pointers is empty. - unsafe { ptr_offset_from(end_ptr, end_ptr) } -}; - pub const DIFFERENT_ALLOC_UNSIGNED: usize = { let uninit = std::mem::MaybeUninit::::uninit(); let base_ptr: *const Struct = &uninit as *const _ as *const Struct; @@ -130,4 +116,23 @@ pub const OFFSET_VERY_FAR2: isize = { //~^ inside }; +// If the pointers are the same, OOB/null/UAF is fine. +pub const OFFSET_FROM_NULL_SAME: isize = { + let ptr = 0 as *const u8; + unsafe { ptr_offset_from(ptr, ptr) } +}; +const OUT_OF_BOUNDS_SAME: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + unsafe { ptr_offset_from(end_ptr, end_ptr) } +}; +const UAF_SAME: isize = { + let uaf_ptr = { + let x = 0; + &x as *const i32 + }; + unsafe { ptr_offset_from(uaf_ptr, uaf_ptr) } +}; + fn main() {} diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 7caf6247b9e9..7b623126d54f 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -24,55 +24,55 @@ LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:44:14 + --> $DIR/offset_from_ub.rs:38:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:53:14 + --> $DIR/offset_from_ub.rs:47:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC0 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:62:14 + --> $DIR/offset_from_ub.rs:56:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:79:14 + --> $DIR/offset_from_ub.rs:65:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:86:14 + --> $DIR/offset_from_ub.rs:72:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:92:14 + --> $DIR/offset_from_ub.rs:78:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:100:14 + --> $DIR/offset_from_ub.rs:86:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:107:14 + --> $DIR/offset_from_ub.rs:93:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:114:14 + --> $DIR/offset_from_ub.rs:100:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second @@ -85,7 +85,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` - --> $DIR/offset_from_ub.rs:123:14 + --> $DIR/offset_from_ub.rs:109:14 | LL | unsafe { ptr2.offset_from(ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` - --> $DIR/offset_from_ub.rs:129:14 + --> $DIR/offset_from_ub.rs:115:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 53d3e6217bd2cc2f0a6949afe4f5cf12abef83b4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 13:43:42 -0700 Subject: [PATCH 117/361] Stabilize const_cstr_from_ptr (CStr::from_ptr, CStr::count_bytes) --- library/core/src/ffi/c_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d2a408485d16..f845dfc1fc41 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -263,8 +263,6 @@ impl CStr { /// ``` /// /// ``` - /// #![feature(const_cstr_from_ptr)] - /// /// use std::ffi::{c_char, CStr}; /// /// const HELLO_PTR: *const c_char = { @@ -280,7 +278,7 @@ impl CStr { #[inline] // inline is necessary for codegen to see strlen. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] + #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C // string with a NUL terminator less than `isize::MAX` from `ptr`. @@ -542,7 +540,7 @@ impl CStr { #[must_use] #[doc(alias("len", "strlen"))] #[stable(feature = "cstr_count_bytes", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] + #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const fn count_bytes(&self) -> usize { self.inner.len() - 1 } @@ -742,6 +740,8 @@ impl AsRef for CStr { /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be /// located within `isize::MAX` from `ptr`. #[inline] +#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] +#[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn const_strlen(ptr: *const c_char) -> usize { const fn strlen_ct(s: *const c_char) -> usize { let mut len = 0; From 48192701e0385e2f045da79d34bd5e856cf32496 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 7 Jul 2024 00:07:08 +0300 Subject: [PATCH 118/361] use "bootstrap" instead of "rustbuild" in comments and docs Signed-off-by: onur-ozkan --- INSTALL.md | 2 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_session/src/config.rs | 2 +- config.example.toml | 8 ++++---- src/bootstrap/README.md | 18 +++++++++--------- src/bootstrap/bootstrap.py | 2 +- src/bootstrap/mk/Makefile.in | 2 +- src/bootstrap/src/bin/main.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 6 +++--- src/bootstrap/src/core/build_steps/doc.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/builder.rs | 8 ++++---- src/bootstrap/src/core/builder/tests.rs | 2 +- src/bootstrap/src/core/config/config.rs | 5 ++--- src/bootstrap/src/core/config/flags.rs | 2 +- src/bootstrap/src/core/sanity.rs | 2 +- src/bootstrap/src/lib.rs | 4 ++-- src/bootstrap/src/utils/helpers.rs | 2 +- src/ci/scripts/install-clang.sh | 2 +- .../x86_64-fortanix-unknown-sgx.md | 2 +- src/tools/build_helper/src/ci.rs | 2 +- src/tools/lint-docs/src/groups.rs | 2 +- src/tools/lint-docs/src/lib.rs | 2 +- .../crates/rust-analyzer/src/version.rs | 2 +- src/tools/rust-installer/src/combiner.rs | 2 +- src/tools/rust-installer/test.sh | 2 +- 26 files changed, 44 insertions(+), 45 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 9619ec2ce5cf..f660cfb0d7c3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -215,7 +215,7 @@ python x.py build Right now, building Rust only works with some known versions of Visual Studio. If you have a more recent version installed and the build system doesn't -understand, you may need to force rustbuild to use an older version. +understand, you may need to force bootstrap to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 2bd5dfdce83e..dd134ebbe6b1 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -398,7 +398,7 @@ impl<'a> GccLinker<'a> { self.link_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more + // purely to support bootstrap right now, we should get a more // principled solution at some point to force the compiler to pass // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 41c99f7edeef..e748d1ff47b6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2620,7 +2620,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // This is the location used by the `rust-src` `rustup` component. let mut candidate = sysroot.join("lib/rustlib/src/rust"); if let Ok(metadata) = candidate.symlink_metadata() { - // Replace the symlink rustbuild creates, with its destination. + // Replace the symlink bootstrap creates, with its destination. // We could try to use `fs::canonicalize` instead, but that might // produce unnecessarily verbose path. if metadata.file_type().is_symlink() { diff --git a/config.example.toml b/config.example.toml index 679abcdc7771..68c632d91cde 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,6 +1,6 @@ # Sample TOML configuration file for building Rust. # -# To configure rustbuild, run `./configure` or `./x.py setup`. +# To configure bootstrap, run `./configure` or `./x.py setup`. # See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information. # # All options are commented out by default in this file, and they're commented @@ -109,7 +109,7 @@ # increases the size of binaries and consequently the memory required by # each linker process. # If set to 0, linker invocations are treated like any other job and -# controlled by rustbuild's -j parameter. +# controlled by bootstrap's -j parameter. #link-jobs = 0 # Whether to build LLVM as a dynamically linked library (as opposed to statically linked). @@ -371,11 +371,11 @@ # Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time. #local-rebuild = false -# Print out how long each rustbuild step took (mostly intended for CI and +# Print out how long each bootstrap step took (mostly intended for CI and # tracking over time) #print-step-timings = false -# Print out resource usage data for each rustbuild step, as defined by the Unix +# Print out resource usage data for each bootstrap step, as defined by the Unix # struct rusage. (Note that this setting is completely unstable: the data it # captures, what platforms it supports, the format of its associated output, and # this setting's very existence, are all subject to change.) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index fb3c86270430..0ac58645d2df 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -1,7 +1,7 @@ -# rustbuild - Bootstrapping Rust +# Bootstrapping Rust This README is aimed at helping to explain how Rust is bootstrapped, -and some of the technical details of the build system. +and some of the technical details of the bootstrap build system. Note that this README only covers internal information, not how to use the tool. Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information. @@ -12,17 +12,17 @@ Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further info The build system defers most of the complicated logic of managing invocations of rustc and rustdoc to Cargo itself. However, moving through various stages -and copying artifacts is still necessary for it to do. Each time rustbuild +and copying artifacts is still necessary for it to do. Each time bootstrap is invoked, it will iterate through the list of predefined steps and execute each serially in turn if it matches the paths passed or is a default rule. -For each step, rustbuild relies on the step internally being incremental and -parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded +For each step, bootstrap relies on the step internally being incremental and +parallel. Note, though, that the `-j` parameter to bootstrap gets forwarded to appropriate test harnesses and such. ## Build phases -The rustbuild build system goes through a few phases to actually build the -compiler. What actually happens when you invoke rustbuild is: +Bootstrap build system goes through a few phases to actually build the +compiler. What actually happens when you invoke bootstrap is: 1. The entry point script (`x` for unix like systems, `x.ps1` for windows systems, `x.py` cross-platform) is run. This script is responsible for downloading the stage0 @@ -151,9 +151,9 @@ build/ stage3/ ``` -## Extending rustbuild +## Extending bootstrap -When you use the bootstrap system, you'll call it through the entry point script +When you use bootstrap, you'll call it through the entry point script (`x`, `x.ps1`, or `x.py`). However, most of the code lives in `src/bootstrap`. `bootstrap` has a difficult problem: it is written in Rust, but yet it is run before the Rust compiler is built! To work around this, there are two components diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7e47b373ff9d..4e8e0fd2532f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1038,7 +1038,7 @@ class RustBuild(object): def check_vendored_status(self): """Check that vendoring is configured properly""" - # keep this consistent with the equivalent check in rustbuild: + # keep this consistent with the equivalent check in bootstrap: # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405 if 'SUDO_USER' in os.environ and not self.use_vendored_sources: if os.getuid() == 0: diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index cab37e0da473..f85aefcb268d 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -20,7 +20,7 @@ all: $(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS) help: - $(Q)echo 'Welcome to the rustbuild build system!' + $(Q)echo 'Welcome to bootstrap, the Rust build system!' $(Q)echo $(Q)echo This makefile is a thin veneer over the ./x.py script located $(Q)echo in this directory. To get the full power of the build system diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 44fb1911fc6d..a7d21ba6ae12 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -1,4 +1,4 @@ -//! rustbuild, the Rust build system +//! bootstrap, the Rust build system //! //! This is the entry point for the build system used to compile the `rustc` //! compiler. Lots of documentation can be found in the `README.md` file in the diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 01b25224de4c..9d79baf45e5c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1,7 +1,7 @@ //! Implementation of compiling various phases of the compiler and standard //! library. //! -//! This module contains some of the real meat in the rustbuild build system +//! This module contains some of the real meat in the bootstrap build system //! which is where Cargo is used to compile the standard library, libtest, and //! the compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. @@ -819,8 +819,8 @@ pub struct Rustc { pub compiler: Compiler, /// Whether to build a subset of crates, rather than the whole compiler. /// - /// This should only be requested by the user, not used within rustbuild itself. - /// Using it within rustbuild can lead to confusing situation where lints are replayed + /// This should only be requested by the user, not used within bootstrap itself. + /// Using it within bootstrap can lead to confusing situation where lints are replayed /// in two different steps. crates: Vec, } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 823e842693e9..38d4f0bed4cc 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1,4 +1,4 @@ -//! Documentation generation for rustbuilder. +//! Documentation generation for bootstrap. //! //! This module implements generation for all bits and pieces of documentation //! for the Rust project. This notably includes suites like the rust book, the diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index dc53bd3cfa78..5ea711ebcd60 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2993,7 +2993,7 @@ impl Step for Bootstrap { // https://github.com/rust-lang/rust/issues/49215 cmd.env("RUSTFLAGS", flags); } - // rustbuild tests are racy on directory creation so just run them one at a time. + // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder); } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 4da912994c3e..0ea28728e0d4 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1627,11 +1627,11 @@ impl<'a> Builder<'a> { } // This tells Cargo (and in turn, rustc) to output more complete - // dependency information. Most importantly for rustbuild, this + // dependency information. Most importantly for bootstrap, this // includes sysroot artifacts, like libstd, which means that we don't - // need to track those in rustbuild (an error prone process!). This + // need to track those in bootstrap (an error prone process!). This // feature is currently unstable as there may be some bugs and such, but - // it represents a big improvement in rustbuild's reliability on + // it represents a big improvement in bootstrap's reliability on // rebuilds, so we're using it here. // // For some additional context, see #63470 (the PR originally adding @@ -1643,7 +1643,7 @@ impl<'a> Builder<'a> { // Restrict the allowed features so we don't depend on nightly // accidentally. // - // binary-dep-depinfo is used by rustbuild itself for all + // binary-dep-depinfo is used by bootstrap itself for all // compilations. // // Lots of tools depend on proc_macro2 and proc-macro-error. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index aa119b8c6991..97c9ece0036e 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -266,7 +266,7 @@ mod defaults { // rustdoc/rustcc/std here (the user only requested a host=B build, so // there's not really a need for us to build for target A in this case // (since we're producing stage 1 libraries/binaries). But currently - // rustbuild is just a bit buggy here; this should be fixed though. + // bootstrap is just a bit buggy here; this should be fixed though. assert_eq!( first(cache.all::()), &[ diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 10ac6c93e9a4..508f7350b51c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -658,8 +658,7 @@ impl Merge for TomlConfig { } } -// We are using a decl macro instead of a derive proc macro here to reduce the compile time of -// rustbuild. +// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. macro_rules! define_config { ($(#[$attr:meta])* struct $name:ident { $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* @@ -704,7 +703,7 @@ macro_rules! define_config { // The following is a trimmed version of what serde_derive generates. All parts not relevant // for toml deserialization have been removed. This reduces the binary size and improves - // compile time of rustbuild. + // compile time of bootstrap. impl<'de> Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index aeb608a9ea26..19f752da81c1 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -1,4 +1,4 @@ -//! Command-line interface of the rustbuild build system. +//! Command-line interface of the bootstrap build system. //! //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 78862ccb8cd6..c70f879568d1 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -1,4 +1,4 @@ -//! Sanity checking performed by rustbuild before actually executing anything. +//! Sanity checking performed by bootstrap before actually executing anything. //! //! This module contains the implementation of ensuring that the build //! environment looks reasonable before progressing. This will verify that diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ffdd9bc885a6..e08eb4e62bb9 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1,9 +1,9 @@ -//! Implementation of rustbuild, the Rust build system. +//! Implementation of bootstrap, the Rust build system. //! //! This module, and its descendants, are the implementation of the Rust build //! system. Most of this build system is backed by Cargo but the outer layer //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo -//! builds, building artifacts like LLVM, etc. The goals of rustbuild are: +//! builds, building artifacts like LLVM, etc. The goals of bootstrap are: //! //! * To be an easily understandable, easily extensible, and maintainable build //! system. diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 2575b7939b44..a52b4bbf9886 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -1,4 +1,4 @@ -//! Various utility functions used throughout rustbuild. +//! Various utility functions used throughout bootstrap. //! //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index 24b9904d65c2..6103aa61248a 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -40,7 +40,7 @@ if isMacOS; then # our own clang can figure out the correct include path on its own. ciCommandSetEnv SDKROOT "$(xcrun --sdk macosx --show-sdk-path)" - # Configure `AR` specifically so rustbuild doesn't try to infer it as + # Configure `AR` specifically so bootstrap doesn't try to infer it as # `clang-ar` by accident. ciCommandSetEnv AR "ar" elif isWindows && ! isKnownToBeMingwBuild; then diff --git a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md index 97b5827c1443..33e1c44e6d35 100644 --- a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md +++ b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md @@ -46,7 +46,7 @@ on how to setup a development and runtime environment. As a tier 2 target, the target is built by the Rust project. -You can configure rustbuild like so: +You can configure bootstrap like so: ```toml [build] diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 09489b0d9b7d..233fed4151c1 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -25,7 +25,7 @@ impl CiEnv { /// If in a CI environment, forces the command to run with colors. pub fn force_coloring_in_ci(self, cmd: &mut Command) { if self != CiEnv::None { - // Due to use of stamp/docker, the output stream of rustbuild is not + // Due to use of stamp/docker, the output stream of bootstrap is not // a TTY in CI, so coloring is by-default turned off. // The explicit `TERM=xterm` environment is needed for // `--color always` to actually work. This env var was lost when diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index f246d71d499b..9eaa234bfaf3 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -37,7 +37,7 @@ impl<'a> LintExtractor<'a> { .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; let new_contents = contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?); - // Delete the output because rustbuild uses hard links in its copies. + // Delete the output because bootstrap uses hard links in its copies. let _ = fs::remove_file(&groups_path); fs::write(&groups_path, new_contents) .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 72d6a495e7e7..48e2dd098769 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -532,7 +532,7 @@ impl<'a> LintExtractor<'a> { } add_rename_redirect(level, &mut result); let out_path = self.out_path.join("listing").join(level.doc_filename()); - // Delete the output because rustbuild uses hard links in its copies. + // Delete the output because bootstrap uses hard links in its copies. let _ = fs::remove_file(&out_path); fs::write(&out_path, result) .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs index 1e829299e6f3..2ff967416c00 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs @@ -15,7 +15,7 @@ pub struct VersionInfo { pub version: &'static str, /// The release channel we were built for (stable/beta/nightly/dev). /// - /// `None` if not built via rustbuild. + /// `None` if not built via bootstrap. pub release_channel: Option<&'static str>, /// Information about the Git repository we may have been built from. /// diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index c211b34850a0..e7020980dc3d 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -109,7 +109,7 @@ impl Combiner { .with_context(|| format!("failed to read components in '{}'", input_tarball))?; for component in pkg_components.split_whitespace() { // All we need to do is copy the component directory. We could - // move it, but rustbuild wants to reuse the unpacked package + // move it, but bootstrap wants to reuse the unpacked package // dir for OS-specific installers on macOS and Windows. let component_dir = package_dir.join(component); create_dir(&component_dir)?; diff --git a/src/tools/rust-installer/test.sh b/src/tools/rust-installer/test.sh index 16b05c66197c..7b3e74560062 100755 --- a/src/tools/rust-installer/test.sh +++ b/src/tools/rust-installer/test.sh @@ -974,7 +974,7 @@ combined_remains() { --package-name=rust \ --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" for component in rustc cargo rust-docs; do - # rustbuild wants the original extracted package intact too + # bootstrap wants the original extracted package intact too try test -d "$WORK_DIR/$component/$component" try test -d "$WORK_DIR/rust/$component" done From 93e3c00670a8362ce384ed7911e547f87982af77 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 6 Jul 2024 22:24:00 -0500 Subject: [PATCH 119/361] Remove non-focused memory leaks in `alloc` doctests for Miri. --- library/alloc/src/rc.rs | 6 ++++++ library/alloc/src/sync.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 3745ecb48c18..9f2bff984490 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1287,6 +1287,8 @@ impl Rc { /// /// let five = Rc::from_raw(ptr); /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count(ptr); /// } /// ``` #[inline] @@ -1344,6 +1346,8 @@ impl Rc { /// let x = Rc::new("hello".to_owned()); /// let x_ptr = Rc::into_raw(x); /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] @@ -1571,6 +1575,8 @@ impl Rc { /// /// let five = Rc::from_raw_in(ptr, System); /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count_in(ptr, System); /// } /// ``` #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 90672164cb93..6a591d24065c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1428,6 +1428,8 @@ impl Arc { /// // the `Arc` between threads. /// let five = Arc::from_raw(ptr); /// assert_eq!(2, Arc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Arc::decrement_strong_count(ptr); /// } /// ``` #[inline] @@ -1487,6 +1489,8 @@ impl Arc { /// let x = Arc::new("hello".to_owned()); /// let x_ptr = Arc::into_raw(x); /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Arc::from_raw(x_ptr) }); /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] @@ -1769,6 +1773,8 @@ impl Arc { /// // the `Arc` between threads. /// let five = Arc::from_raw_in(ptr, System); /// assert_eq!(2, Arc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Arc::decrement_strong_count_in(ptr, System); /// } /// ``` #[inline] From e0ed696d2f1ce49b28be12879570dd402a354e2e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 6 Jul 2024 22:30:37 -0500 Subject: [PATCH 120/361] Mitigate focused memory leaks in `alloc` doctests for Miri. If/when `-Zmiri-disable-leak-check` is able to be used at test-granularity, it should applied to these tests instead of unleaking. --- library/alloc/src/boxed.rs | 6 ++++++ library/alloc/src/string.rs | 3 +++ library/alloc/src/vec/into_iter.rs | 7 ++++++- library/alloc/src/vec/mod.rs | 6 ++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1ec095a46f70..ba157dc1a379 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1213,6 +1213,9 @@ impl Box { /// let static_ref: &'static mut usize = Box::leak(x); /// *static_ref += 1; /// assert_eq!(*static_ref, 42); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` /// /// Unsized data: @@ -1222,6 +1225,9 @@ impl Box { /// let static_ref = Box::leak(x); /// static_ref[0] = 4; /// assert_eq!(*static_ref, [4, 2, 3]); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] #[inline] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 36078da7c35a..07ffd3e15191 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1984,6 +1984,9 @@ impl String { /// let x = String::from("bucket"); /// let static_ref: &'static mut str = x.leak(); /// assert_eq!(static_ref, "bucket"); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "string_leak", since = "1.72.0")] #[inline] diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 3bd89eaa6cb5..10f62e4bb62d 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -120,10 +120,15 @@ impl IntoIter { /// This is roughly equivalent to the following, but more efficient /// /// ``` - /// # let mut into_iter = Vec::::with_capacity(10).into_iter(); + /// # let mut vec = Vec::::with_capacity(10); + /// # let ptr = vec.as_mut_ptr(); + /// # let mut into_iter = vec.into_iter(); /// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter()); /// (&mut into_iter).for_each(drop); /// std::mem::forget(into_iter); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Vec::::from_raw_parts(ptr, 0, 10) }); /// ``` /// /// This method is used by in-place iteration, refer to the vec::in_place_collect diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f1706e31bb80..0b91151c3861 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1473,6 +1473,9 @@ impl Vec { /// // 2. `0 <= capacity` always holds whatever `capacity` is. /// unsafe { /// vec.set_len(0); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # vec.set_len(3); /// } /// ``` /// @@ -2391,6 +2394,9 @@ impl Vec { /// let static_ref: &'static mut [usize] = x.leak(); /// static_ref[0] += 1; /// assert_eq!(static_ref, &[2, 2, 3]); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "vec_leak", since = "1.47.0")] #[inline] From e4c064d81316a7041c50ac2cfd836247ce02ed37 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 6 Jul 2024 22:53:31 -0500 Subject: [PATCH 121/361] Remove non-focused memory leaks in `core` doctests for Miri. --- library/core/src/mem/maybe_uninit.rs | 12 ++++++++++++ library/core/src/ptr/non_null.rs | 2 ++ 2 files changed, 14 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 24ebe33bb2c1..a8d03ef2611a 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -274,6 +274,8 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let v: MaybeUninit> = MaybeUninit::new(vec![42]); + /// # // Prevent leaks for Miri + /// # unsafe { let _ = MaybeUninit::assume_init(v); } /// ``` /// /// [`assume_init`]: MaybeUninit::assume_init @@ -506,6 +508,8 @@ impl MaybeUninit { /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; /// assert_eq!(x_vec.len(), 3); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// ``` /// /// *Incorrect* usage of this method: @@ -545,6 +549,8 @@ impl MaybeUninit { /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; /// x_vec.push(3); /// assert_eq!(x_vec.len(), 4); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// ``` /// /// *Incorrect* usage of this method: @@ -746,6 +752,8 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); + /// # let mut x_mu = x; + /// # let mut x = &mut x_mu; /// // Initialize `x`: /// x.write(vec![1, 2, 3]); /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to @@ -755,6 +763,8 @@ impl MaybeUninit { /// x.assume_init_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x_mu); } /// ``` /// /// ### *Incorrect* usages of this method: @@ -1088,6 +1098,8 @@ impl MaybeUninit { /// let init = MaybeUninit::clone_from_slice(&mut dst, &src); /// /// assert_eq!(init, src); + /// # // Prevent leaks for Miri + /// # unsafe { std::ptr::drop_in_place(init); } /// ``` /// /// ``` diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 75a99e14fdad..1238061d68d5 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1663,6 +1663,8 @@ impl NonNull<[T]> { /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] /// let slice: &mut [MaybeUninit] = unsafe { memory.as_uninit_slice_mut() }; + /// # // Prevent leaks for Miri. + /// # unsafe { Global.deallocate(memory.cast(), Layout::new::<[u8; 32]>()); } /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] From 36258ed947c4013094b23029fb716f0ff715622c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 6 Jul 2024 22:53:51 -0500 Subject: [PATCH 122/361] Mitigate focused memory leaks in `core` doctests for Miri. If/when `-Zmiri-disable-leak-check` is able to be used at test-granularity, it should applied to these tests instead of unleaking. --- library/core/src/mem/manually_drop.rs | 3 +++ library/core/src/mem/maybe_uninit.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index e0c3b9f3b51d..997f088c6d68 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -62,6 +62,9 @@ impl ManuallyDrop { /// x.truncate(5); // You can still safely operate on the value /// assert_eq!(*x, "Hello"); /// // But `Drop` will not be run here + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # let _ = ManuallyDrop::into_inner(x); /// ``` #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] #[stable(feature = "manually_drop", since = "1.20.0")] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index a8d03ef2611a..dd40f57dc870 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -448,6 +448,9 @@ impl MaybeUninit { /// let mut x = MaybeUninit::::uninit(); /// /// x.write("Hello".to_string()); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// // This leaks the contained string: /// x.write("hello".to_string()); /// // x is initialized now: From 7ce4a499119c2a816a40af73b6b4cc39b5278400 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Jul 2024 11:54:22 -0400 Subject: [PATCH 123/361] iter_identity is a better name --- clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e5d205641968..acaeb93f44a6 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -99,7 +99,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' for (predicate, _span) in cx .tcx .explicit_item_super_predicates(def_id) - .instantiate_identity_iter_copied() + .iter_identity_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through From a10c7a4b9b88606bf94348733f903d21276d8134 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 6 Jul 2024 23:35:31 -0500 Subject: [PATCH 124/361] Remove non-focused memory leak in `std` doctest for Miri. --- library/std/src/sync/condvar.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index f9f83fb4f63c..08d46f356d9f 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -35,6 +35,7 @@ impl WaitTimeoutResult { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// + /// # let handle = /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// @@ -58,6 +59,8 @@ impl WaitTimeoutResult { /// break /// } /// } + /// # // Prevent leaks for Miri. + /// # let _ = handle.join(); /// ``` #[must_use] #[stable(feature = "wait_timeout", since = "1.5.0")] From 6e754fee717abb1884f216123935532908c60613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Jul 2024 09:35:07 +0200 Subject: [PATCH 125/361] Stacked Borrows: fix PartialEq for Stack We have to compare unknown_bottom as well, it is semantically relevant! --- .../miri/src/borrow_tracker/stacked_borrows/stack.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index f65f49a75ddd..774b36919fe3 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -136,8 +136,16 @@ impl StackCache { impl PartialEq for Stack { fn eq(&self, other: &Self) -> bool { - // All the semantics of Stack are in self.borrows, everything else is caching - self.borrows == other.borrows + let Stack { + borrows, + unknown_bottom, + // The cache is ignored for comparison. + #[cfg(feature = "stack-cache")] + cache: _, + #[cfg(feature = "stack-cache")] + unique_range: _, + } = self; + *borrows == other.borrows && *unknown_bottom == other.unknown_bottom } } From f7050b0c784559a0eacbbfac9f7be95cb81dba66 Mon Sep 17 00:00:00 2001 From: John Arundel Date: Sun, 7 Jul 2024 10:44:27 +0100 Subject: [PATCH 126/361] resolve code review comments --- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/casts/mod.rs | 12 ++--- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/methods/mod.rs | 3 +- tests/ui/crashes/ice-12616.stderr | 2 +- tests/ui/ptr_as_ptr.stderr | 66 +++++++++++------------ 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index dac1f4ed404a..1a4dc38e7e9c 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in [`std::sync`] and + /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are /// not designed to operate in an async context across await points. /// diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d8bae3b48bf4..7eaa802ecc28 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -244,9 +244,9 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Casting a function pointer to anything other than `usize`/`isize` is - /// not portable across architectures. It either loses bits if the target - /// type is too small, or creates extra bits that waste space and bloat the - /// resulting binary. + /// not portable across architectures. If the target type is too small the + /// address would be truncated, and target types larger than `usize` are + /// unnecessary. /// /// Casting to `isize` also doesn't make sense, since addresses are never /// signed. @@ -373,7 +373,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts on a raw pointer that don't change its + /// Checks for `as` casts between raw pointers that don't change their /// mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? @@ -398,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` on a raw pointer that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts on a raw pointer that change its constness, namely `*const T` to + /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 2c168405ee26..86c5f6b9f0ba 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { cx, PTR_AS_PTR, expr.span, - "`as` casting between raw pointers without changing its mutability", + "`as` casting between raw pointers without changing their constness", help, final_suggestion, app, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b8b24fe92ee3..c29f81bf0fb4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -632,8 +632,7 @@ declare_clippy_lint! { /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| - /// y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example /// ```no_run diff --git a/tests/ui/crashes/ice-12616.stderr b/tests/ui/crashes/ice-12616.stderr index c7cf5cf5483f..a84a945a429f 100644 --- a/tests/ui/crashes/ice-12616.stderr +++ b/tests/ui/crashes/ice-12616.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/crashes/ice-12616.rs:6:5 | LL | s() as *const (); diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e162f35baf55..18462620b0a3 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } @@ -7,37 +7,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); @@ -45,157 +45,157 @@ LL | let _ = inline!($ptr as *const i32); | = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ From 5a9e5e4acf537bca80dc505c48148c952b85a264 Mon Sep 17 00:00:00 2001 From: John Arundel Date: Sun, 7 Jul 2024 10:49:26 +0100 Subject: [PATCH 127/361] resolve code review comments --- clippy_lints/src/casts/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 7eaa802ecc28..14f9f991d3be 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -374,7 +374,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for `as` casts between raw pointers that don't change their - /// mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? /// Though `as` casts between raw pointers are not terrible, From aa371c37c2989e2c505865630179250ec528c19b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 16 Jun 2024 01:34:25 -0400 Subject: [PATCH 128/361] Rewrite `overflow_check_conditional` --- .../src/overflow_check_conditional.rs | 70 +++++++++---------- tests/ui/overflow_check_conditional.rs | 21 ++---- tests/ui/overflow_check_conditional.stderr | 28 +++----- 3 files changed, 47 insertions(+), 72 deletions(-) diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index de7898793310..6909c1f6f671 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::SpanlessEq; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; +use clippy_utils::eq_expr_value; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -26,45 +28,39 @@ declare_clippy_lint! { declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); -const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; -const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; - impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r); - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() + if let ExprKind::Binary(op, lhs, rhs) = expr.kind + && let (lt, gt) = match op.node { + BinOpKind::Lt => (lhs, rhs), + BinOpKind::Gt => (rhs, lhs), + _ => return, + } + && let ctxt = expr.span.ctxt() + && let (op_lhs, op_rhs, other, commutative) = match (<.kind, >.kind) { + (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => { + (lhs, rhs, gt, true) + }, + (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => { + (lhs, rhs, lt, false) + }, + _ => return, + } + && let typeck = cx.typeck_results() + && let ty = typeck.expr_ty(op_lhs) + && matches!(ty.kind(), ty::Uint(_)) + && ty == typeck.expr_ty(op_rhs) + && ty == typeck.expr_ty(other) + && !in_external_macro(cx.tcx.sess, expr.span) + && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other))) { - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } - } - - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() - { - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } + span_lint( + cx, + OVERFLOW_CHECK_CONDITIONAL, + expr.span, + "you are trying to use classic C overflow conditions that will fail in Rust", + ); } } } diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index a70bb3bc47bf..acabe9a37e00 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -2,23 +2,14 @@ #![allow(clippy::needless_if)] fn test(a: u32, b: u32, c: u32) { - if a + b < a {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - //~| NOTE: `-D clippy::overflow-check-conditional` implied by `-D warnings` - if a > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if a + b < b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if b > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust + if a + b < a {} //~ overflow_check_conditional + if a > a + b {} //~ overflow_check_conditional + if a + b < b {} //~ overflow_check_conditional + if b > a + b {} //~ overflow_check_conditional if a - b > b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus if b < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a - b > a {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus + if a - b > a {} //~ overflow_check_conditional + if a < a - b {} //~ overflow_check_conditional if a + b < c {} if c > a + b {} if a - b < c {} diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index c14532bad5ab..e71768d3745e 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -8,46 +8,34 @@ LL | if a + b < a {} = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]` error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:8:8 + --> tests/ui/overflow_check_conditional.rs:6:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:10:8 + --> tests/ui/overflow_check_conditional.rs:7:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:12:8 + --> tests/ui/overflow_check_conditional.rs:8:8 | LL | if b > a + b {} | ^^^^^^^^^ -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:14:8 - | -LL | if a - b > b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:16:8 - | -LL | if b < a - b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:18:8 +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/overflow_check_conditional.rs:11:8 | LL | if a - b > a {} | ^^^^^^^^^ -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:20:8 +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/overflow_check_conditional.rs:12:8 | LL | if a < a - b {} | ^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors From 23d96f65e42c3451dae2b70abfe0a0f709225021 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 16 Jun 2024 20:37:47 -0400 Subject: [PATCH 129/361] Rename `overflow_check_conditional` to `panicking_overflow_checks`. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 4 +- ...tional.rs => panicking_overflow_checks.rs} | 8 +- clippy_lints/src/renamed_lints.rs | 1 + tests/ui/overflow_check_conditional.rs | 27 ---- tests/ui/panicking_overflow_checks.rs | 27 ++++ ...tderr => panicking_overflow_checks.stderr} | 16 +-- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 126 +++++++++--------- 11 files changed, 114 insertions(+), 102 deletions(-) rename clippy_lints/src/{overflow_check_conditional.rs => panicking_overflow_checks.rs} (91%) delete mode 100644 tests/ui/overflow_check_conditional.rs create mode 100644 tests/ui/panicking_overflow_checks.rs rename tests/ui/{overflow_check_conditional.stderr => panicking_overflow_checks.stderr} (65%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62fc5e2c5d42..55281f3cbec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5705,6 +5705,7 @@ Released 2018-09-13 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params +[`panicking_overflow_checks`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_overflow_checks [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 593f59cff423..0c75bcbb00b0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -589,12 +589,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::VERBOSE_BIT_MASK_INFO, crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO, crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO, - crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO, crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO, crate::panic_unimplemented::PANIC_INFO, crate::panic_unimplemented::TODO_INFO, crate::panic_unimplemented::UNIMPLEMENTED_INFO, crate::panic_unimplemented::UNREACHABLE_INFO, + crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO, crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO, crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO, crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fbe895fa50e8..4b159417942d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -278,9 +278,9 @@ mod only_used_in_recursion; mod operators; mod option_env_unwrap; mod option_if_let_else; -mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; +mod panicking_overflow_checks; mod partial_pub_fields; mod partialeq_ne_impl; mod partialeq_to_none; @@ -791,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone()))); store.register_late_pass(|_| Box::new(swap::Swap)); - store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); + store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names))); store.register_late_pass(move |_| { diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/panicking_overflow_checks.rs similarity index 91% rename from clippy_lints/src/overflow_check_conditional.rs rename to clippy_lints/src/panicking_overflow_checks.rs index 6909c1f6f671..c9c2935b3ae4 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/panicking_overflow_checks.rs @@ -21,14 +21,14 @@ declare_clippy_lint! { /// a + b < a; /// ``` #[clippy::version = "pre 1.29.0"] - pub OVERFLOW_CHECK_CONDITIONAL, + pub PANICKING_OVERFLOW_CHECKS, complexity, "overflow checks inspired by C which are likely to panic" } -declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); +declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]); -impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { +impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(op, lhs, rhs) = expr.kind @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { { span_lint( cx, - OVERFLOW_CHECK_CONDITIONAL, + PANICKING_OVERFLOW_CHECKS, expr.span, "you are trying to use classic C overflow conditions that will fail in Rust", ); diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index e0e1279873e6..8e999f3e89af 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -26,6 +26,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"), ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"), ("clippy::option_unwrap_used", "clippy::unwrap_used"), + ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), ("clippy::ref_in_deref", "clippy::needless_borrow"), ("clippy::result_expect_used", "clippy::expect_used"), ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"), diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs deleted file mode 100644 index acabe9a37e00..000000000000 --- a/tests/ui/overflow_check_conditional.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![warn(clippy::overflow_check_conditional)] -#![allow(clippy::needless_if)] - -fn test(a: u32, b: u32, c: u32) { - if a + b < a {} //~ overflow_check_conditional - if a > a + b {} //~ overflow_check_conditional - if a + b < b {} //~ overflow_check_conditional - if b > a + b {} //~ overflow_check_conditional - if a - b > b {} - if b < a - b {} - if a - b > a {} //~ overflow_check_conditional - if a < a - b {} //~ overflow_check_conditional - if a + b < c {} - if c > a + b {} - if a - b < c {} - if c > a - b {} - let i = 1.1; - let j = 2.2; - if i + j < i {} - if i - j < i {} - if i > i + j {} - if i - j < i {} -} - -fn main() { - test(1, 2, 3) -} diff --git a/tests/ui/panicking_overflow_checks.rs b/tests/ui/panicking_overflow_checks.rs new file mode 100644 index 000000000000..dc2ddeada1e9 --- /dev/null +++ b/tests/ui/panicking_overflow_checks.rs @@ -0,0 +1,27 @@ +#![warn(clippy::panicking_overflow_checks)] +#![allow(clippy::needless_if)] + +fn test(a: u32, b: u32, c: u32) { + if a + b < a {} //~ panicking_overflow_checks + if a > a + b {} //~ panicking_overflow_checks + if a + b < b {} //~ panicking_overflow_checks + if b > a + b {} //~ panicking_overflow_checks + if a - b > b {} + if b < a - b {} + if a - b > a {} //~ panicking_overflow_checks + if a < a - b {} //~ panicking_overflow_checks + if a + b < c {} + if c > a + b {} + if a - b < c {} + if c > a - b {} + let i = 1.1; + let j = 2.2; + if i + j < i {} + if i - j < i {} + if i > i + j {} + if i - j < i {} +} + +fn main() { + test(1, 2, 3) +} diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/panicking_overflow_checks.stderr similarity index 65% rename from tests/ui/overflow_check_conditional.stderr rename to tests/ui/panicking_overflow_checks.stderr index e71768d3745e..1fae04578899 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/panicking_overflow_checks.stderr @@ -1,38 +1,38 @@ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:5:8 + --> tests/ui/panicking_overflow_checks.rs:5:8 | LL | if a + b < a {} | ^^^^^^^^^ | - = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]` + = note: `-D clippy::panicking-overflow-checks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]` error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:6:8 + --> tests/ui/panicking_overflow_checks.rs:6:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:7:8 + --> tests/ui/panicking_overflow_checks.rs:7:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:8:8 + --> tests/ui/panicking_overflow_checks.rs:8:8 | LL | if b > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:11:8 + --> tests/ui/panicking_overflow_checks.rs:11:8 | LL | if a - b > a {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:12:8 + --> tests/ui/panicking_overflow_checks.rs:12:8 | LL | if a < a - b {} | ^^^^^^^^^ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index df39afcc1ad6..d70c9f8d06c0 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -24,6 +24,7 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] @@ -78,6 +79,7 @@ #![warn(clippy::map_unwrap_or)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::unwrap_used)] +#![warn(clippy::panicking_overflow_checks)] #![warn(clippy::needless_borrow)] #![warn(clippy::expect_used)] #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index c57a4e1bde26..8d0ac3c8f955 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -24,6 +24,7 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] @@ -78,6 +79,7 @@ #![warn(clippy::option_map_unwrap_or)] #![warn(clippy::option_map_unwrap_or_else)] #![warn(clippy::option_unwrap_used)] +#![warn(clippy::overflow_check_conditional)] #![warn(clippy::ref_in_deref)] #![warn(clippy::result_expect_used)] #![warn(clippy::result_map_unwrap_or_else)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 3abab593a6ba..d6637324a030 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:57:9 + --> tests/ui/rename.rs:58:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,352 +8,358 @@ 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:58:9 + --> tests/ui/rename.rs:59: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:59:9 + --> tests/ui/rename.rs:60: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:60:9 + --> tests/ui/rename.rs:61: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:61:9 + --> tests/ui/rename.rs:62: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:62:9 + --> tests/ui/rename.rs:63: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:63:9 + --> tests/ui/rename.rs:64: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:64:9 + --> tests/ui/rename.rs:65: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:65:9 + --> tests/ui/rename.rs:66: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:66:9 + --> tests/ui/rename.rs:67: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:67:9 + --> tests/ui/rename.rs:68: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:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:71: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:71:9 + --> tests/ui/rename.rs:72: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:72:9 + --> tests/ui/rename.rs:73: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:73:9 + --> tests/ui/rename.rs:74: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:74:9 + --> tests/ui/rename.rs:75: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:75:9 + --> tests/ui/rename.rs:76: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:76:9 + --> tests/ui/rename.rs:77: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:77:9 + --> tests/ui/rename.rs:78: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:78:9 + --> tests/ui/rename.rs:79: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:79:9 + --> tests/ui/rename.rs:80: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:80:9 + --> tests/ui/rename.rs:81: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:82: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:81:9 + --> tests/ui/rename.rs:83: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:82:9 + --> tests/ui/rename.rs:84: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:83:9 + --> tests/ui/rename.rs:85: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:84:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:87: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:86:9 + --> tests/ui/rename.rs:88: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:87:9 + --> tests/ui/rename.rs:89: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:88:9 + --> tests/ui/rename.rs:90: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:89:9 + --> tests/ui/rename.rs:91: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:90:9 + --> tests/ui/rename.rs:92: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:91:9 + --> tests/ui/rename.rs:93: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:92:9 + --> tests/ui/rename.rs:94: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:93:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:96: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:95:9 + --> tests/ui/rename.rs:97: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:96:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:99: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:98:9 + --> tests/ui/rename.rs:100: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:99:9 + --> tests/ui/rename.rs:101: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:100:9 + --> tests/ui/rename.rs:102: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:101:9 + --> tests/ui/rename.rs:103: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:102:9 + --> tests/ui/rename.rs:104: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:103:9 + --> tests/ui/rename.rs:105: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:104:9 + --> tests/ui/rename.rs:106: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:105:9 + --> tests/ui/rename.rs:107: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:106:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:114:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:115:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 59 previous errors +error: aborting due to 60 previous errors From d2ff2b98507d0abaa2c878f74035774f9d9bcd95 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 16 Jun 2024 20:53:10 -0400 Subject: [PATCH 130/361] Move `panicking_overflow_checks` into `correctness` and clean up docs. --- clippy_lints/src/panicking_overflow_checks.rs | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/panicking_overflow_checks.rs b/clippy_lints/src/panicking_overflow_checks.rs index c9c2935b3ae4..7f100a746d5e 100644 --- a/clippy_lints/src/panicking_overflow_checks.rs +++ b/clippy_lints/src/panicking_overflow_checks.rs @@ -8,22 +8,42 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Detects classic underflow/overflow checks. + /// Detects C-style underflow/overflow checks. /// /// ### Why is this bad? - /// Most classic C underflow/overflow checks will fail in - /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. + /// These checks will, by default, panic in debug builds rather than check + /// whether the operation caused an overflow. /// /// ### Example /// ```no_run - /// # let a = 1; - /// # let b = 2; - /// a + b < a; + /// # let a = 1i32; + /// # let b = 2i32; + /// if a + b < a { + /// // handle overflow + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.checked_add(b).is_none() { + /// // handle overflow + /// } + /// ``` + /// + /// Or: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.overflowing_add(b).1 { + /// // handle overflow + /// } /// ``` #[clippy::version = "pre 1.29.0"] pub PANICKING_OVERFLOW_CHECKS, - complexity, - "overflow checks inspired by C which are likely to panic" + correctness, + "overflow checks which will panic in debug mode" } declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]); From 9978261a6e38ca3583cdf3eb2956cb4d14cd5a6f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 15 Feb 2024 19:54:37 +0000 Subject: [PATCH 131/361] Support tail calls in mir via `TerminatorKind::TailCall` --- src/base.rs | 5 +++++ src/constant.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/base.rs b/src/base.rs index c5b4277015a9..5adbbb09ac85 100644 --- a/src/base.rs +++ b/src/base.rs @@ -491,6 +491,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ) }); } + // FIXME(explicit_tail_calls): add support for tail calls to the cranelift backend, once cranelift supports tail calls + TerminatorKind::TailCall { fn_span, .. } => span_bug!( + *fn_span, + "tail calls are not yet supported in `rustc_codegen_cranelift` backend" + ), TerminatorKind::InlineAsm { template, operands, diff --git a/src/constant.rs b/src/constant.rs index 87c5da3b7c3e..fc12f0ff738b 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -565,6 +565,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( { return None; } + TerminatorKind::TailCall { .. } => return None, TerminatorKind::Call { .. } => {} } } From 791ff403373c36822c062a1b05e5898fdc44ef4a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 9 May 2023 21:30:28 +0000 Subject: [PATCH 132/361] Add support for `mir::TerminatorKind::TailCall` in clippy --- clippy_utils/src/qualify_min_const_fn.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 42b10f69c0cd..f206b2ceebcb 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -330,7 +330,8 @@ fn check_terminator<'tcx>( target: _, unwind: _, fn_span: _, - } => { + } + | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { if !is_const_fn(tcx, fn_def_id, msrv) { From d8717cf780e795b12193934b16ebcd47021d4925 Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Sun, 7 Jul 2024 10:42:11 -0500 Subject: [PATCH 133/361] Re-enable Miri leak checking in CI. --- src/bootstrap/mk/Makefile.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index cab37e0da473..6267156e8e25 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -58,9 +58,8 @@ check-aux: library/core \ library/alloc \ --no-doc - # Some doctests have intentional memory leaks. # Some use file system operations to demonstrate dealing with `Result`. - $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ library/alloc \ @@ -70,7 +69,7 @@ check-aux: $(BOOTSTRAP) miri --stage 2 library/std \ --no-doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: - $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ --doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: From 98010765f949307bf53ebb692e45e428ba318aa1 Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Sun, 7 Jul 2024 10:44:47 -0500 Subject: [PATCH 134/361] Move/change declaration of `mod exit_guard;` --- library/std/src/sys/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 22ebc979bf7e..4092e6080d54 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -3,11 +3,11 @@ /// descriptors. mod pal; -pub(crate) mod exit_guard; mod personality; pub mod backtrace; pub mod cmath; +pub mod exit_guard; pub mod os_str; pub mod path; pub mod sync; From 51727bae4bb4650d7fa297b983fdc13608ae6e17 Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Sun, 7 Jul 2024 11:23:13 -0500 Subject: [PATCH 135/361] Update src/bootstrap/mk/Makefile.in Co-authored-by: Ralf Jung --- src/bootstrap/mk/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 6267156e8e25..3d977bf30586 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -58,7 +58,7 @@ check-aux: library/core \ library/alloc \ --no-doc - # Some use file system operations to demonstrate dealing with `Result`. + # Some doctests use file system operations to demonstrate dealing with `Result`. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ From 32294aa5f57394800a201e5e6ee4b1ca04899d8b Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 7 Jul 2024 00:26:41 +0300 Subject: [PATCH 136/361] Add tests for #112905 --- .../ui/implied-bounds/dyn-erasure-no-tait.rs | 53 +++++++++++++++++++ tests/ui/implied-bounds/dyn-erasure-tait.rs | 39 ++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 tests/ui/implied-bounds/dyn-erasure-no-tait.rs create mode 100644 tests/ui/implied-bounds/dyn-erasure-tait.rs diff --git a/tests/ui/implied-bounds/dyn-erasure-no-tait.rs b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs new file mode 100644 index 000000000000..b5a8f421d3d6 --- /dev/null +++ b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs @@ -0,0 +1,53 @@ +//@ known-bug: #112905 +//@ check-pass + +// Classified as an issue with implied bounds: +// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 + +/// Note: this is sound! It's the "type witness" pattern (here, lt witness). +mod some_lib { + use super::T; + + /// Invariant in `'a` and `'b` for soundness. + pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>); + + impl<'a, 'b> LtEq<'a, 'b> { + pub fn new() -> LtEq<'a, 'a> { + LtEq(<_>::default()) + } + + pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> { + |a| unsafe { ::std::mem::transmute::, T<'b>>(a) } + } + } +} + +use some_lib::LtEq; +use std::{any::Any, cell::Cell}; + +/// Feel free to choose whatever you want, here. +type T<'lt> = Cell<&'lt str>; + +fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { + let f = LtEq::<'a, 'a>::new().eq(); + let any = Box::new(f) as Box; + + let new_f = None.map(LtEq::<'a, 'b>::eq); + + fn downcast_a_to_type_of_new_f(any: Box, _: Option) -> F { + *any.downcast().unwrap_or_else(|_| unreachable!()) + } + + let f = downcast_a_to_type_of_new_f(any, new_f); + + f(a) +} + +fn main() { + let r: T<'static> = { + let local = String::from("…"); + let a: T<'_> = Cell::new(&local[..]); + exploit(a) + }; + dbg!(r.get()); +} diff --git a/tests/ui/implied-bounds/dyn-erasure-tait.rs b/tests/ui/implied-bounds/dyn-erasure-tait.rs new file mode 100644 index 000000000000..4766d221d67c --- /dev/null +++ b/tests/ui/implied-bounds/dyn-erasure-tait.rs @@ -0,0 +1,39 @@ +//@ known-bug: #112905 +//@ check-pass + +// Classified as an issue with implied bounds: +// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 + +#![forbid(unsafe_code)] // No `unsafe!` +#![feature(type_alias_impl_trait)] + +use std::any::Any; + +/// Anything covariant will do, for this demo. +type T<'lt> = &'lt str; + +type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>; + +fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> { + |x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static` +} + +fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { + let f: F<'a, 'a> = helper([]); + let any = Box::new(f) as Box; + + let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!()); + + f(a) +} + +fn main() { + let r: T<'static> = { + let local = String::from("..."); + exploit(&local) + }; + // Since `r` now dangles, we can easily make the use-after-free + // point to newly allocated memory! + let _unrelated = String::from("UAF"); + dbg!(r); // may print `UAF`! Run with `miri` to see the UB. +} From 93e74a4187688d4948b57fcf44e44d192c5d6357 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 7 Jul 2024 18:40:44 +0200 Subject: [PATCH 137/361] Lintcheck: Update lintcheck documentation --- lintcheck/README.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lintcheck/README.md b/lintcheck/README.md index 2d6039caeef0..47a96e0a03c9 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -7,13 +7,13 @@ repo. We can then check the diff and spot new or disappearing warnings. From the repo root, run: ``` -cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml +cargo lintcheck ``` or ``` -cargo lintcheck +cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml ``` By default, the logs will be saved into @@ -33,6 +33,8 @@ the 200 recently most downloaded crates: cargo lintcheck popular -n 200 custom.toml ``` +> Note: Lintcheck isn't sandboxed. Only use it to check crates that you trust or +> sandbox it manually. ### Configuring the Crate Sources @@ -65,17 +67,11 @@ sources. #### Command Line Options (optional) ```toml -bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']} +clap = {name = "clap", versions = ['4.5.8'], options = ['-Fderive']} ``` It is possible to specify command line options for each crate. This makes it -possible to only check a crate for certain lint groups. If no options are -specified, the lint groups `clippy::all`, `clippy::pedantic`, and -`clippy::cargo` are checked. If an empty array is specified only `clippy::all` -is checked. - -**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all` -is explicitly specified in the options. +possible to enable or disable features. ### Fix mode You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and From 8e2ddc800b2e89d3a5df1dd9373ddea6e8d9fe42 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 13:01:12 -0400 Subject: [PATCH 138/361] `inherent_to_string`: Check HIR tree before checking for macros. --- clippy_lints/src/inherent_to_string.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 9aedf5ec7e85..ec6174bc0301 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S impl<'tcx> LateLintPass<'tcx> for InherentToString { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if impl_item.span.from_expansion() { - return; - } - // Check if item is a method called `to_string` and has a parameter 'self' if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // #11201 @@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { && decl.implicit_self.has_implicit_self() && decl.inputs.len() == 1 && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + && !impl_item.span.from_expansion() // Check if return type is String && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String) // Filters instances of to_string which are required by a trait From dc8403f0f5fe3c3fab63766c70e5a2640baa1243 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 13:27:16 -0400 Subject: [PATCH 139/361] `inline_fn_without_body`: inline into a single function --- clippy_lints/src/inline_fn_without_body.rs | 41 ++++++++++------------ 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 860258fd030e..5657c58bb0a4 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; -use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - check_attrs(cx, item.ident.name, attrs); + if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind + && let Some(attr) = cx + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .find(|a| a.has_name(sym::inline)) + { + span_lint_and_then( + cx, + INLINE_FN_WITHOUT_BODY, + attr.span, + format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), + |diag| { + diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); + }, + ); } } } - -fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { - for attr in attrs { - if !attr.has_name(sym::inline) { - continue; - } - - span_lint_and_then( - cx, - INLINE_FN_WITHOUT_BODY, - attr.span, - format!("use of `#[inline]` on trait method `{name}` which has no body"), - |diag| { - diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); - }, - ); - } -} From aef07100544f44c6813fc811e9f0440551ce418d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 13:33:02 -0400 Subject: [PATCH 140/361] `instant_subtraction`: Reduce redundant work. --- clippy_lints/src/instant_subtraction.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 10b00f632bb0..5fe152d1e301 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction { lhs, rhs, ) = expr.kind + && let typeck = cx.typeck_results() + && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant) { + let rhs_ty = typeck.expr_ty(rhs); + if is_instant_now_call(cx, lhs) - && is_an_instant(cx, rhs) + && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant) && let Some(sugg) = Sugg::hir_opt(cx, rhs) { print_manual_instant_elapsed_sugg(cx, expr, sugg); - } else if !expr.span.from_expansion() + } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration) + && !expr.span.from_expansion() && self.msrv.meets(msrvs::TRY_FROM) - && is_an_instant(cx, lhs) - && is_a_duration(cx, rhs) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } @@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { } } -fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) -} - -fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration) -} - fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { span_lint_and_sugg( cx, From ca5c2813eb7e988c4d2a25312f5749cf6686230e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 20:14:50 -0400 Subject: [PATCH 141/361] `items_after_statements`: Do less work in the default case. --- clippy_lints/src/items_after_statements.rs | 59 +++++++++++----------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 39223c20470b..a88d8e24fda8 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl LateLintPass<'_> for ItemsAfterStatements { fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { - if in_external_macro(cx.sess(), block.span) { - return; - } - - // skip initial items - let stmts = block - .stmts - .iter() - .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))); - - // lint on all further items - for stmt in stmts { - if let StmtKind::Item(item_id) = stmt.kind { - let item = cx.tcx.hir().item(item_id); - if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) { - return; - } - if let ItemKind::Macro(..) = item.kind { - // do not lint `macro_rules`, but continue processing further statements - continue; - } - span_lint_hir( - cx, - ITEMS_AFTER_STATEMENTS, - item.hir_id(), - item.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope", - ); - } + if block.stmts.len() > 1 { + let ctxt = block.span.ctxt(); + let mut in_external = None; + block + .stmts + .iter() + .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))) + .filter_map(|stmt| match stmt.kind { + StmtKind::Item(id) => Some(cx.tcx.hir().item(id)), + _ => None, + }) + // Ignore macros since they can only see previously defined locals. + .filter(|item| !matches!(item.kind, ItemKind::Macro(..))) + // Stop linting if macros define items. + .take_while(|item| item.span.ctxt() == ctxt) + // Don't use `next` due to the complex filter chain. + .for_each(|item| { + // Only do the macro check once, but delay it until it's needed. + if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) { + span_lint_hir( + cx, + ITEMS_AFTER_STATEMENTS, + item.hir_id(), + item.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope", + ); + } + }); } } } From fa1a690b23ea772f1ca5893f80a46ee7ae48b6a1 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 20:23:52 -0400 Subject: [PATCH 142/361] `iter_not_returning_iterator`: * Check HIR tree first. * Check name by symbol. --- .../src/iter_not_returning_iterator.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 1b5f1b499475..ba0cd5d6eb35 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// ### What it does @@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") { - if let TraitItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + if let TraitItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) + { + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") + if let ImplItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) && !matches!( cx.tcx.parent_hir_node(item.hir_id()), Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some() ) { - if let ImplItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } } -fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { +fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) { if sig.decl.implicit_self.has_implicit_self() { let ret_ty = cx .tcx From 6b10b4360cbecf11131228d174e6922505b215a1 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 20:25:45 -0400 Subject: [PATCH 143/361] `iter_without_into_iter`: Delay macro check --- clippy_lints/src/iter_without_into_iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 6b03f2597b08..1e6404190d3c 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { - if !in_external_macro(cx.sess(), item.span) - && let ItemKind::Impl(imp) = item.kind + if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait && trait_ref .trait_def_id() .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && !in_external_macro(cx.sess(), item.span) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, From 3092c8a5fd4d715dd58bd8f6843330c3aa8de768 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 22:14:08 -0400 Subject: [PATCH 144/361] `large_const_arrays`: Check HIR tree first. --- clippy_lints/src/large_const_arrays.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 7f8197c0cc01..b18ab625e609 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !item.span.from_expansion() - && let ItemKind::Const(_, generics, _) = &item.kind + if let ItemKind::Const(_, generics, _) = &item.kind // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. && generics.params.is_empty() && !generics.has_where_clause_predicates + && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() From 430c02cbd0f45d50fd1c4bbefad4d19b5d464984 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 22:16:47 -0400 Subject: [PATCH 145/361] `large_enum_variant`: Delay macro check --- clippy_lints/src/large_enum_variant.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0bf7389ef9cc..85daadcc5373 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if in_external_macro(cx.tcx.sess, item.span) { - return; - } - if let ItemKind::Enum(ref def, _) = item.kind { - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - let ty::Adt(adt, subst) = ty.kind() else { - panic!("already checked whether this is an enum") - }; - if adt.variants().len() <= 1 { - return; - } + if let ItemKind::Enum(ref def, _) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let ty::Adt(adt, subst) = ty.kind() + && adt.variants().len() > 1 + && !in_external_macro(cx.tcx.sess, item.span) + { let variants_size = AdtVariantInfo::new(cx, *adt, subst); let mut difference = variants_size[0].size - variants_size[1].size; From c3dd028d3e304e59da3ac32dca1190672cbe705f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 22:42:27 -0400 Subject: [PATCH 146/361] `large_futures`: Delay macro check --- clippy_lints/src/large_futures.rs | 43 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 07488a512a37..602227e42490 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); impl<'tcx> LateLintPass<'tcx> for LargeFuture { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) { - return; - } - if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind { - if let ExprKind::Call(func, [expr, ..]) = expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind - && let ty = cx.typeck_results().expr_ty(expr) - && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) - && let size = layout.layout.size() - && size >= Size::from_bytes(self.future_size_threshold) - { - span_lint_and_sugg( - cx, - LARGE_FUTURES, - expr.span, - format!("large future with a size of {} bytes", size.bytes()), - "consider `Box::pin` on it", - format!("Box::pin({})", snippet(cx, expr.span, "..")), - Applicability::Unspecified, - ); - } + if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind + && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind + && !expr.span.from_expansion() + && let ty = cx.typeck_results().expr_ty(arg) + && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let size = layout.layout.size() + && size >= Size::from_bytes(self.future_size_threshold) + { + span_lint_and_sugg( + cx, + LARGE_FUTURES, + arg.span, + format!("large future with a size of {} bytes", size.bytes()), + "consider `Box::pin` on it", + format!("Box::pin({})", snippet(cx, arg.span, "..")), + Applicability::Unspecified, + ); } } } From 03036c11b3390dc216f59b014d0837b591460821 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 22:46:27 -0400 Subject: [PATCH 147/361] `large_include_file`: Check HIR tree first. --- clippy_lints/src/large_include_file.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 07efee159aab..2688283a6ce8 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(cx, expr) - && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id) - && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) - && let ExprKind::Lit(lit) = &expr.kind - { - let len = match &lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let len = match &lit.node { // include_bytes LitKind::ByteStr(bstr, _) => bstr.len(), // include_str LitKind::Str(sym, _) => sym.as_str().len(), _ => return, - }; - - if len as u64 <= self.max_file_size { - return; } - + && len as u64 > self.max_file_size + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) + || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + { span_lint_and_note( cx, LARGE_INCLUDE_FILE, From 5ae33c76994cf67952034c814c0df7719b4db585 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 22:50:13 -0400 Subject: [PATCH 148/361] `legacy_numeric_constants`: Check HIR tree first. --- clippy_lints/src/legacy_numeric_constants.rs | 46 ++++++++------------ 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index eadfeb6e3418..a08b40bef372 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) { - return; - } - // Integer modules are "TBD" deprecated, and the contents are too, // so lint on the `use` statement directly. if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), item.span) && let Some(def_id) = path.res[0].opt_def_id() { let module = if is_integer_module(cx, def_id) { @@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { - return; - } - let ExprKind::Path(qpath) = expr.kind else { + let ExprKind::Path(qpath) = &expr.kind else { return; }; @@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { ) // `::xxx_value` check } else if let QPath::TypeRelative(_, last_segment) = qpath - && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() - && is_integer_method(cx, def_id) + && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() && let Some(par_expr) = get_parent_expr(cx, expr) - && let ExprKind::Call(_, _) = par_expr.kind + && let ExprKind::Call(_, []) = par_expr.kind + && is_integer_method(cx, def_id) { let name = last_segment.ident.name.as_str(); @@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { return; }; - if is_from_proc_macro(cx, expr) { - return; + if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + diag.span_suggestion_with_style( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + }); } - - span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_with_style( - span, - "use the associated constant instead", - sugg, - Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, - ); - }); } extract_msrv_attr!(LateContext); From eac1aab1ff6900ba7aabb365eee0aaaad96be57f Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 7 Jul 2024 20:14:21 +0000 Subject: [PATCH 149/361] Reduce the size of lintcheck JSON output --- lintcheck/Cargo.toml | 1 + lintcheck/src/driver.rs | 2 - lintcheck/src/json.rs | 101 ++++++++++++++++++------------------- lintcheck/src/main.rs | 31 +++++------- lintcheck/src/recursive.rs | 4 +- 5 files changed, 62 insertions(+), 77 deletions(-) diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml index ae9e77b8eed0..3c86dfe324f4 100644 --- a/lintcheck/Cargo.toml +++ b/lintcheck/Cargo.toml @@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive", "env"] } crossbeam-channel = "0.5.6" diff = "0.1.13" flate2 = "1.0" +itertools = "0.12" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.85" diff --git a/lintcheck/src/driver.rs b/lintcheck/src/driver.rs index 47724a2fedb0..041be5081f28 100644 --- a/lintcheck/src/driver.rs +++ b/lintcheck/src/driver.rs @@ -11,8 +11,6 @@ use std::{env, mem}; fn run_clippy(addr: &str) -> Option { let driver_info = DriverInfo { package_name: env::var("CARGO_PKG_NAME").ok()?, - crate_name: env::var("CARGO_CRATE_NAME").ok()?, - version: env::var("CARGO_PKG_VERSION").ok()?, }; let mut stream = BufReader::new(TcpStream::connect(addr).unwrap()); diff --git a/lintcheck/src/json.rs b/lintcheck/src/json.rs index 43d0413c7cee..1a652927988e 100644 --- a/lintcheck/src/json.rs +++ b/lintcheck/src/json.rs @@ -1,37 +1,50 @@ -use std::collections::HashMap; -use std::fmt::Write; use std::fs; -use std::hash::Hash; use std::path::Path; +use itertools::EitherOrBoth; +use serde::{Deserialize, Serialize}; + use crate::ClippyWarning; -/// Creates the log file output for [`crate::config::OutputFormat::Json`] -pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String { - serde_json::to_string(&clippy_warnings).unwrap() +#[derive(Deserialize, Serialize)] +struct LintJson { + lint: String, + file_name: String, + byte_pos: (u32, u32), + rendered: String, } -fn load_warnings(path: &Path) -> Vec { +impl LintJson { + fn key(&self) -> impl Ord + '_ { + (self.file_name.as_str(), self.byte_pos, self.lint.as_str()) + } +} + +/// Creates the log file output for [`crate::config::OutputFormat::Json`] +pub(crate) fn output(clippy_warnings: Vec) -> String { + let mut lints: Vec = clippy_warnings + .into_iter() + .map(|warning| { + let span = warning.span(); + LintJson { + file_name: span.file_name.clone(), + byte_pos: (span.byte_start, span.byte_end), + lint: warning.lint, + rendered: warning.diag.rendered.unwrap(), + } + }) + .collect(); + lints.sort_by(|a, b| a.key().cmp(&b.key())); + serde_json::to_string(&lints).unwrap() +} + +fn load_warnings(path: &Path) -> Vec { let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display())); serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display())) } -/// Group warnings by their primary span location + lint name -fn create_map(warnings: &[ClippyWarning]) -> HashMap> { - let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len()); - - for warning in warnings { - let span = warning.span(); - let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end); - - map.entry(key).or_default().push(warning); - } - - map -} - -fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { +fn print_warnings(title: &str, warnings: &[LintJson]) { if warnings.is_empty() { return; } @@ -39,31 +52,20 @@ fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { println!("### {title}"); println!("```"); for warning in warnings { - print!("{}", warning.diag); + print!("{}", warning.rendered); } println!("```"); } -fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) { - fn render(warnings: &[&ClippyWarning]) -> String { - let mut rendered = String::new(); - for warning in warnings { - write!(&mut rendered, "{}", warning.diag).unwrap(); - } - rendered - } - +fn print_changed_diff(changed: &[(LintJson, LintJson)]) { if changed.is_empty() { return; } println!("### Changed"); println!("```diff"); - for &(old, new) in changed { - let old_rendered = render(old); - let new_rendered = render(new); - - for change in diff::lines(&old_rendered, &new_rendered) { + for (old, new) in changed { + for change in diff::lines(&old.rendered, &new.rendered) { use diff::Result::{Both, Left, Right}; match change { @@ -86,26 +88,19 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) { let old_warnings = load_warnings(old_path); let new_warnings = load_warnings(new_path); - let old_map = create_map(&old_warnings); - let new_map = create_map(&new_warnings); - let mut added = Vec::new(); let mut removed = Vec::new(); let mut changed = Vec::new(); - for (key, new) in &new_map { - if let Some(old) = old_map.get(key) { - if old != new { - changed.push((old.as_slice(), new.as_slice())); - } - } else { - added.extend(new); - } - } - - for (key, old) in &old_map { - if !new_map.contains_key(key) { - removed.extend(old); + for change in itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) { + match change { + EitherOrBoth::Both(old, new) => { + if old.rendered != new.rendered { + changed.push((old, new)); + } + }, + EitherOrBoth::Left(old) => removed.push(old), + EitherOrBoth::Right(new) => added.push(new), } } diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 70b8af0fdb95..26a67beb4427 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -38,7 +38,7 @@ use std::{env, fs, thread}; use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; use rayon::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use walkdir::{DirEntry, WalkDir}; const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; @@ -142,19 +142,17 @@ impl RustcIce { } /// A single warning that clippy issued while checking a `Crate` -#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug)] struct ClippyWarning { - crate_name: String, - crate_version: String, - lint_type: String, + lint: String, diag: Diagnostic, } #[allow(unused)] impl ClippyWarning { - fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { - let lint_type = diag.code.clone()?.code; - if !(lint_type.contains("clippy") || diag.message.contains("clippy")) + fn new(mut diag: Diagnostic) -> Option { + let lint = diag.code.clone()?.code; + if !(lint.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") { return None; @@ -164,12 +162,7 @@ impl ClippyWarning { let rendered = diag.rendered.as_mut().unwrap(); *rendered = strip_ansi_escapes::strip_str(&rendered); - Some(Self { - crate_name: crate_name.to_owned(), - crate_version: crate_version.to_owned(), - lint_type, - diag, - }) + Some(Self { lint, diag }) } fn span(&self) -> &DiagnosticSpan { @@ -181,7 +174,7 @@ impl ClippyWarning { let mut file = span.file_name.clone(); let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message), + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), OutputFormat::Markdown => { if file.starts_with("target") { file.insert_str(0, "../"); @@ -189,7 +182,7 @@ impl ClippyWarning { let mut output = String::from("| "); write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); output.push('\n'); output }, @@ -473,7 +466,7 @@ impl Crate { // get all clippy warnings and ICEs let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { - Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), + Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message), _ => None, }) .map(ClippyCheckOutput::ClippyWarning) @@ -572,7 +565,7 @@ fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) let mut counter: HashMap<&String, usize> = HashMap::new(); warnings .iter() - .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); + .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); // collect into a tupled list for sorting let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); @@ -754,7 +747,7 @@ fn lintcheck(config: LintcheckConfig) { panic!("Some crates ICEd"); } - json::output(&warnings) + json::output(warnings) }, }; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 994fa3c3b239..24dddfe65636 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -19,8 +19,6 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)] pub(crate) struct DriverInfo { pub package_name: String, - pub crate_name: String, - pub version: String, } pub(crate) fn serialize_line(value: &T, writer: &mut W) @@ -65,7 +63,7 @@ fn process_stream( let messages = stderr .lines() .filter_map(|json_msg| serde_json::from_str::(json_msg).ok()) - .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version)); + .filter_map(ClippyWarning::new); for message in messages { sender.send(message).unwrap(); From ff4e62d3ec08e7243f8085e60d72f296f8373812 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:05:21 -0400 Subject: [PATCH 150/361] `len_zero`: Check HIR tree first --- clippy_lints/src/len_zero.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 57e0a7aa2c7e..4c737371bd23 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.span.from_expansion() { - return; - } - - if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind { + if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind + && !item.span.from_expansion() + { check_trait_items(cx, item, trait_items); } } @@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Let(lt) = expr.kind - && has_is_empty(cx, lt.init) && match lt.pat.kind { PatKind::Slice([], None, []) => true, PatKind::Lit(lit) if is_empty_string(lit) => true, _ => false, } + && !expr.span.from_expansion() + && has_is_empty(cx, lt.init) { let mut applicability = Applicability::MachineApplicable; @@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } - if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind + && !expr.span.from_expansion() + { // expr.span might contains parenthesis, see issue #10529 let actual_span = span_without_enclosing_paren(cx, expr.span); match cmp { From fed75b3895397a72dfd881e44f432dd9624a76ce Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:17:08 -0400 Subject: [PATCH 151/361] `let_if_seq`: use `array_windows`. --- clippy_lints/src/let_if_seq.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index a65cb3f4dfb4..0e488cee6b74 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]); impl<'tcx> LateLintPass<'tcx> for LetIfSeq { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let mut it = block.stmts.iter().peekable(); - while let Some(stmt) = it.next() { - if let Some(expr) = it.peek() - && let hir::StmtKind::Let(local) = stmt.kind + for [stmt, next] in block.stmts.array_windows::<2>() { + if let hir::StmtKind::Let(local) = stmt.kind && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind - && let hir::StmtKind::Expr(if_) = expr.kind + && let hir::StmtKind::Expr(if_) = next.kind && let hir::ExprKind::If( hir::Expr { kind: hir::ExprKind::DropTemps(cond), From 5332def0fdf4a6aecc7c06bedcbb97d8f77d2607 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:18:51 -0400 Subject: [PATCH 152/361] `let_underscore`: Delay macro check. --- clippy_lints/src/let_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 9fd4f509aa47..8fa63f3e8fde 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if matches!(local.source, LocalSource::Normal) - && !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init + && !in_external_macro(cx.tcx.sess, local.span) { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { From 15f640a7cbc7c30bc04010e843ff58f3d6ea0ddd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:20:54 -0400 Subject: [PATCH 153/361] `let_with_type_underscore`: * Delay macro check. * Use `is_from_proc_macro --- clippy_lints/src/let_with_type_underscore.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 593b29154b42..5a11702d7ce5 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet; +use clippy_utils::is_from_proc_macro; use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -25,19 +25,14 @@ declare_clippy_lint! { } declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); -impl LateLintPass<'_> for UnderscoreTyped { - fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { - if !in_external_macro(cx.tcx.sess, local.span) - && let Some(ty) = local.ty // Ensure that it has a type defined +impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { + if let Some(ty) = local.ty // Ensure that it has a type defined && let TyKind::Infer = &ty.kind // that type is '_' && local.span.eq_ctxt(ty.span) + && !in_external_macro(cx.tcx.sess, local.span) + && !is_from_proc_macro(cx, ty) { - // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, - // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` - if snippet(cx, ty.span, "_").trim() != "_" { - return; - } - span_lint_and_help( cx, LET_WITH_TYPE_UNDERSCORE, From c0fa6a92f0a4a217bddb088090b12fffa9a29f72 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:28:30 -0400 Subject: [PATCH 154/361] `literal_representation`: Delay macro check. --- clippy_lints/src/literal_representation.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index d2a140a36a83..7481543941a6 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -233,11 +233,9 @@ impl_lint_pass!(LiteralDigitGrouping => [ impl EarlyLintPass for LiteralDigitGrouping { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } @@ -448,11 +446,9 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION] impl EarlyLintPass for DecimalLiteralRepresentation { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } From b9ba340db65d70d8f36444888b140a63e05b2c71 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:34:59 -0400 Subject: [PATCH 155/361] `manual_bits`: Delay msrv check --- clippy_lints/src/manual_bits.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 24fc2b4faeac..d9f6be6dc2b5 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]); impl<'tcx> LateLintPass<'tcx> for ManualBits { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::MANUAL_BITS) { - return; - } - if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind && let BinOpKind::Mul = &bin_op.node && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::MANUAL_BITS) && let ctxt = expr.span.ctxt() && left_expr.span.ctxt() == ctxt && right_expr.span.ctxt() == ctxt From 95348adcb9c4f44a8f4828e6137b9ee6d42a7dbe Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 23:47:56 -0400 Subject: [PATCH 156/361] `manual_float_methods`: * Check HIR tree first. * Use `partition_in_place`. --- clippy_lints/src/lib.rs | 1 + clippy_lints/src/manual_float_methods.rs | 29 +++++++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fbe895fa50e8..0084fea4d6b3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,6 +5,7 @@ #![feature(f16)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_partition_in_place)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_private)] diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 89eea0b4456d..03416ba96de7 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -82,29 +82,26 @@ impl Variant { impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !in_external_macro(cx.sess(), expr.span) - && ( - matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().declared(sym!(const_float_classify)) - ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind + if let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind // Checking all possible scenarios using a function would be a hopeless task, as we have // 16 possible alignments of constants/operands. For now, let's use `partition`. - && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] - .into_iter() - .partition::>, _>(|i| path_to_local(i).is_some()) - && let [first, second] = &*operands - && let Some([const_1, const_2]) = constants - .into_iter() - .map(|i| constant(cx, cx.typeck_results(), i)) - .collect::>>() - .as_deref() + && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] + && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2 + && !in_external_macro(cx.sess(), expr.span) + && ( + matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) + || cx.tcx.features().declared(sym!(const_float_classify)) + ) + && let [first, second, const_1, const_2] = exprs + && let Some(const_1) = constant(cx, cx.typeck_results(), const_1) + && let Some(const_2) = constant(cx, cx.typeck_results(), const_2) && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s)) // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in // case somebody does that for some reason - && (is_infinity(const_1) && is_neg_infinity(const_2) - || is_neg_infinity(const_1) && is_infinity(const_2)) + && (is_infinity(&const_1) && is_neg_infinity(&const_2) + || is_neg_infinity(&const_1) && is_infinity(&const_2)) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { From 2d9e67ea8a74f5c25f2735a7dadd94e0f6d9e79d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 00:02:42 -0400 Subject: [PATCH 157/361] `manual_let_else`: Delay msrv and macro checks. --- clippy_lints/src/manual_let_else.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 03e4d668dd8f..ebebdf679a86 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -49,16 +49,14 @@ declare_clippy_lint! { impl<'tcx> QuestionMark { pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { - if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { - return; - } - if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + && self.msrv.meets(msrvs::LET_ELSE) + && !in_external_macro(cx.sess(), stmt.span) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { From f46c981f3f93c59d9fd8c81aea9b03e9bce40997 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 00:05:01 -0400 Subject: [PATCH 158/361] `manual_main_separator_str`: Check HIR tree first. --- clippy_lints/src/manual_main_separator_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 5732bdda7f2c..8e8cdc3fb076 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) - && let (target, _) = peel_hir_expr_refs(expr) - && is_trait_method(cx, target, sym::ToString) - && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + let (target, _) = peel_hir_expr_refs(expr); + if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && path.ident.name == sym::to_string && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && is_trait_method(cx, target, sym::ToString) + && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && ty.is_str() From 2309f8e4a12021913809b8ed4b60ff41d9c586f0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 02:27:52 -0400 Subject: [PATCH 159/361] `manual_non_exhaustive`: Delay msrv check. --- clippy_lints/src/manual_non_exhaustive.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index d2ac0ad8363e..73a505fd73ff 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustiveStruct { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { - return; - } - - if let ast::ItemKind::Struct(variant_data, _) = &item.kind { - let (fields, delimiter) = match variant_data { + if let ast::ItemKind::Struct(variant_data, _) = &item.kind + && let (fields, delimiter) = match variant_data { ast::VariantData::Struct { fields, .. } => (&**fields, '{'), ast::VariantData::Tuple(fields, _) => (&**fields, '('), ast::VariantData::Unit(_) => return, - }; - if fields.len() <= 1 { - return; } + && fields.len() > 1 + && self.msrv.meets(msrvs::NON_EXHAUSTIVE) + { let mut iter = fields.iter().filter_map(|f| match f.vis.kind { VisibilityKind::Public => None, VisibilityKind::Inherited => Some(Ok(f)), From 44f87e8cc1bc1f95a3d942fc2ff7d47663261566 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 02:32:04 -0400 Subject: [PATCH 160/361] `manual_range_patterns`: Delay macro check. --- clippy_lints/src/manual_range_patterns.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index ec60de92c4ba..07d4abbf5cd1 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -76,14 +76,11 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { - if in_external_macro(cx.sess(), pat.span) { - return; - } - // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives // or at least one range if let PatKind::Or(pats) = pat.kind && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); let mut max = Num::dummy(i128::MIN); From 0f4cd13f666fff504ea07c7e1ab3858942878dd5 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 02:45:37 -0400 Subject: [PATCH 161/361] `manual_rem_euclid`: Check HIR tree first. --- clippy_lints/src/manual_rem_euclid.rs | 49 ++++++++++++--------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index ab9bca170cf7..b518dc26937c 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]); impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::REM_EUCLID) { - return; - } - - if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) { - return; - } - - if in_external_macro(cx.sess(), expr.span) { - return; - } - // (x % c + c) % c - if let ExprKind::Binary(op1, expr1, right) = expr.kind - && op1.node == BinOpKind::Rem + if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind + && rem_op.node == BinOpKind::Rem + && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind + && add_op.node == BinOpKind::Add && let ctxt = expr.span.ctxt() - && expr1.span.ctxt() == ctxt - && let Some(const1) = check_for_unsigned_int_constant(cx, right) - && let ExprKind::Binary(op2, left, right) = expr1.kind - && op2.node == BinOpKind::Add - && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right) - && expr2.span.ctxt() == ctxt - && let ExprKind::Binary(op3, expr3, right) = expr2.kind - && op3.node == BinOpKind::Rem - && let Some(const3) = check_for_unsigned_int_constant(cx, right) + && rem_lhs.span.ctxt() == ctxt + && rem_rhs.span.ctxt() == ctxt + && add_lhs.span.ctxt() == ctxt + && add_rhs.span.ctxt() == ctxt + && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::REM_EUCLID) + && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id)) + && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs) + && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs) + && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind + && rem2_op.node == BinOpKind::Rem + && const1 == const2 + && let Some(hir_id) = path_to_local(rem2_lhs) + && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs) // Also ensures the const is nonzero since zero can't be a divisor - && const1 == const2 && const2 == const3 - && let Some(hir_id) = path_to_local(expr3) - && let Node::Pat(_) = cx.tcx.hir_node(hir_id) + && const2 == const3 + && rem2_lhs.span.ctxt() == ctxt + && rem2_rhs.span.ctxt() == ctxt { // Apply only to params or locals with annotated types match cx.tcx.parent_hir_node(hir_id) { @@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { }; let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0; span_lint_and_sugg( cx, MANUAL_REM_EUCLID, From 03117026aedde8e26d14b856caae84e76a799831 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 02:46:58 -0400 Subject: [PATCH 162/361] `manual_retain`: Remove redundant match. --- clippy_lints/src/manual_retain.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 3ddb06a1e08a..8f7b8abd0c38 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]); impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Assign(left_expr, collect_expr, _) = &expr.kind - && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind + && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind && seg.args.is_none() - && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) { From c0068ba5acad7c74111006e90ca2d310d111129c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 02:48:08 -0400 Subject: [PATCH 163/361] `manual_slice_size_calculation`: Delay constant check. --- clippy_lints/src/manual_slice_size_calculation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 1de686dbcb51..429ee2637c2f 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION] impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Does not apply inside const because size_of_val is not cost in stable. - if !in_constant(cx, expr.hir_id) - && let ExprKind::Binary(ref op, left, right) = expr.kind + if let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node && !expr.span.from_expansion() + // Does not apply inside const because size_of_val is not cost in stable. + && !in_constant(cx, expr.hir_id) && let Some(receiver) = simplify(cx, left, right) { let ctxt = expr.span.ctxt(); From 5d333e862b5a2df69333952c331cdb06b4fd12e4 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 18:26:38 -0400 Subject: [PATCH 164/361] `manual_strip`: Delay msrv check. --- clippy_lints/src/manual_strip.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 45af9f07718d..6a523ad15647 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -66,14 +66,11 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { - return; - } - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind - && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) && let ExprKind::Path(target_path) = &target_arg.kind + && self.msrv.meets(msrvs::STR_STRIP_PREFIX) + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { StripKind::Prefix From 7a942a5c993233700a217dae629915bba456d698 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 18:34:25 -0400 Subject: [PATCH 165/361] `manual_unwrap_or_default`: Check HIR tree first. --- clippy_lints/src/manual_unwrap_or_default.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 58b2ebebbf08..f1acc4b21748 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { - return; - } - // Call handle only if the expression is `if let` or `match` - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) { + if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { handle(cx, if_let_or_match, expr); } } From 488a545a50a8b1300f1a543f1de0238905352b57 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 18:35:47 -0400 Subject: [PATCH 166/361] `map_unit_fn`: Delay macro check --- clippy_lints/src/map_unit_fn.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 9db04b615be7..2db71b1f7a38 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -253,14 +253,11 @@ fn lint_map_unit_fn( impl<'tcx> LateLintPass<'tcx> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { - if stmt.span.from_expansion() { - return; - } - - if let hir::StmtKind::Semi(expr) = stmt.kind { - if let Some(arglists) = method_chain_args(expr, &["map"]) { - lint_map_unit_fn(cx, stmt, expr, arglists[0]); - } + if let hir::StmtKind::Semi(expr) = stmt.kind + && !stmt.span.from_expansion() + && let Some(arglists) = method_chain_args(expr, &["map"]) + { + lint_map_unit_fn(cx, stmt, expr, arglists[0]); } } } From eda45aaba1124907b9551589cd5e9b97f1972313 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 18:46:45 -0400 Subject: [PATCH 167/361] `minmax`: use let chain --- clippy_lints/src/minmax.rs | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index fca626fa5c35..c3fbca1d560e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; -use std::cmp::Ordering; +use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { /// ### What it does @@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]); impl<'tcx> LateLintPass<'tcx> for MinMaxPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) { - if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) { - if outer_max == inner_max { - return; - } - match ( - outer_max, - Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c), - ) { - (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), - _ => { - span_lint( - cx, - MIN_MAX, - expr.span, - "this `min`/`max` combination leads to constant result", - ); - }, - } - } + if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) + && let Some((inner_max, inner_c, ie)) = min_max(cx, oe) + && outer_max != inner_max + && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c) + && matches!( + (outer_max, ord), + (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less) + ) + { + span_lint( + cx, + MIN_MAX, + expr.span, + "this `min`/`max` combination leads to constant result", + ); } } } From 5b7ffa1a63a4553e2946d70068629a6e7c9b7fdd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 13:21:09 -0400 Subject: [PATCH 168/361] Rework `init_numbered_fields`: * Only check the name of a single field * Don't lint in macros * Check for side effects * Don't use a binary heap --- clippy_lints/src/init_numbered_fields.rs | 87 +++++++++++-------- clippy_lints/src/lib.rs | 1 + ...ields.fixed => init_numbered_fields.fixed} | 9 ++ ...ered_fields.rs => init_numbered_fields.rs} | 9 ++ ...lds.stderr => init_numbered_fields.stderr} | 12 +-- 5 files changed, 77 insertions(+), 41 deletions(-) rename tests/ui/{numbered_fields.fixed => init_numbered_fields.fixed} (82%) rename tests/ui/{numbered_fields.rs => init_numbered_fields.rs} (84%) rename tests/ui/{numbered_fields.stderr => init_numbered_fields.stderr} (63%) diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 1c8fd0a27f98..7f183bb601eb 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -1,13 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::SyntaxContext; use std::borrow::Cow; -use std::cmp::Reverse; -use std::collections::BinaryHeap; declare_clippy_lint! { /// ### What it does @@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); impl<'tcx> LateLintPass<'tcx> for NumberedFields { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Struct(path, fields, None) = e.kind { - if !fields.is_empty() - && !e.span.from_expansion() - && fields - .iter() - .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) - && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..)) - { - let expr_spans = fields - .iter() - .map(|f| (Reverse(f.ident.as_str().parse::().unwrap()), f.expr.span)) - .collect::>(); - let mut appl = Applicability::MachineApplicable; - let snippet = format!( - "{}({})", - snippet_with_applicability(cx, path.span(), "..", &mut appl), - expr_spans - .into_iter_sorted() - .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0) - .intersperse(Cow::Borrowed(", ")) - .collect::() - ); - span_lint_and_sugg( - cx, - INIT_NUMBERED_FIELDS, - e.span, - "used a field initializer for a tuple struct", - "try", - snippet, - appl, - ); - } + if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind + // If the first character of any field is a digit it has to be a tuple. + && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit) + // Type aliases can't be used as functions. + && !matches!( + cx.qpath_res(path, e.hir_id), + Res::Def(DefKind::TyAlias | DefKind::AssocTy, _) + ) + // This is the only syntax macros can use that works for all struct types. + && !e.span.from_expansion() + && let mut has_side_effects = false + && let Ok(mut expr_spans) = fields + .iter() + .map(|f| { + has_side_effects |= f.expr.can_have_side_effects(); + f.ident.as_str().parse::().map(|x| (x, f.expr.span)) + }) + .collect::, _>>() + // We can only reorder the expressions if there are no side effects. + && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx)) + { + span_lint_and_then( + cx, + INIT_NUMBERED_FIELDS, + e.span, + "used a field initializer for a tuple struct", + |diag| { + if !has_side_effects { + // We already checked the order if there are side effects. + expr_spans.sort_by_key(|&(idx, _)| idx); + } + let mut app = Applicability::MachineApplicable; + diag.span_suggestion( + e.span, + "use tuple initialization", + format!( + "{}({})", + snippet_with_applicability(cx, path.span(), "..", &mut app), + expr_spans + .into_iter() + .map( + |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0 + ) + .intersperse(Cow::Borrowed(", ")) + .collect::() + ), + app, + ); + }, + ); } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fbe895fa50e8..54e19c1aa7f9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -4,6 +4,7 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/init_numbered_fields.fixed similarity index 82% rename from tests/ui/numbered_fields.fixed rename to tests/ui/init_numbered_fields.fixed index 108520eed38d..dca4e8da4d2f 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/init_numbered_fields.fixed @@ -39,4 +39,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec(vec![0, 1, 2, 3]); + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/tests/ui/numbered_fields.rs b/tests/ui/init_numbered_fields.rs similarity index 84% rename from tests/ui/numbered_fields.rs rename to tests/ui/init_numbered_fields.rs index c718661a6826..8cb34705b4f6 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/init_numbered_fields.rs @@ -47,4 +47,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/init_numbered_fields.stderr similarity index 63% rename from tests/ui/numbered_fields.stderr rename to tests/ui/init_numbered_fields.stderr index 9d3f59cd3769..f176e0c2ff30 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/init_numbered_fields.stderr @@ -1,5 +1,5 @@ error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:17:13 + --> tests/ui/init_numbered_fields.rs:17:13 | LL | let _ = TupleStruct { | _____________^ @@ -7,13 +7,13 @@ LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:24:13 + --> tests/ui/init_numbered_fields.rs:24:13 | LL | let _ = TupleStruct { | _____________^ @@ -21,13 +21,13 @@ LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:49:13 + --> tests/ui/init_numbered_fields.rs:49:13 | LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])` error: aborting due to 3 previous errors From 99721c84691b3ee7339d307c92a762414527143d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jul 2024 16:53:10 +1000 Subject: [PATCH 169/361] Clear `inner_attr_ranges` regularly. There's a comment saying we don't do it for performance reasons, but it doesn't actually affect performance. The commit also tweaks the control flow, to make clearer that two code paths are mutually exclusive. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 38f18022e3c5..e9aece13b2e6 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -352,15 +352,10 @@ impl<'a> Parser<'a> { let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); - } - - // Only clear our `replace_ranges` when we're finished capturing entirely. - if matches!(self.capture_state.capturing, Capturing::No) { + } else if matches!(self.capture_state.capturing, Capturing::No) { + // Only clear the ranges once we've finished capturing entirely. self.capture_state.replace_ranges.clear(); - // We don't clear `inner_attr_ranges`, as doing so repeatedly - // had a measurable performance impact. Most inner attributes that - // we insert will get removed - when we drop the parser, we'll free - // up the memory used by any attributes that we didn't remove from the map. + self.capture_state.inner_attr_ranges.clear(); } Ok(ret) } From a47ae57a187eb9537fe22a50692088cc655f357f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jul 2024 14:47:12 +1000 Subject: [PATCH 170/361] Use an `@` pattern to shorten some code. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 38f18022e3c5..a627bc89aa02 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -325,12 +325,9 @@ impl<'a> Parser<'a> { replace_ranges, }); - // If we support tokens at all - if let Some(target_tokens) = ret.tokens_mut() { - if target_tokens.is_none() { - // Store our newly captured tokens into the AST node. - *target_tokens = Some(tokens.clone()); - } + // If we support tokens and don't already have them, store the newly captured tokens. + if let Some(target_tokens @ None) = ret.tokens_mut() { + *target_tokens = Some(tokens.clone()); } let final_attrs = ret.attrs(); From b16201317eefa9054d545dc5237b1bc830448258 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jul 2024 17:41:05 +1000 Subject: [PATCH 171/361] Use iterator normally in `make_attr_token_stream`. In a `for` loop, instead of a `while` loop. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index a627bc89aa02..16261feca91d 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -367,7 +367,7 @@ impl<'a> Parser<'a> { /// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and /// close delims. fn make_attr_token_stream( - mut iter: impl Iterator, + iter: impl Iterator, break_last_token: bool, ) -> AttrTokenStream { #[derive(Debug)] @@ -377,8 +377,7 @@ fn make_attr_token_stream( inner: Vec, } let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; - let mut token_and_spacing = iter.next(); - while let Some((token, spacing)) = token_and_spacing { + for (token, spacing) in iter { match token { FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { stack @@ -416,7 +415,6 @@ fn make_attr_token_stream( .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } - token_and_spacing = iter.next(); } let mut final_buf = stack.pop().expect("Missing final buf!"); if break_last_token { From a88c4d67d9ea8a9f450638f207be867fa984bfce Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jul 2024 18:05:18 +1000 Subject: [PATCH 172/361] Split the stack in `make_attr_token_stream`. It makes for shorter code, and fewer allocations. --- .../rustc_parse/src/parser/attr_wrapper.rs | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 16261feca91d..5a4259eb1e76 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -376,18 +376,19 @@ fn make_attr_token_stream( open_delim_sp: Option<(Delimiter, Span, Spacing)>, inner: Vec, } - let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; + // The stack always has at least one element. Storing it separately makes for shorter code. + let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] }; + let mut stack_rest = vec![]; for (token, spacing) in iter { match token { FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { - stack - .push(FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }); + stack_rest.push(mem::replace( + &mut stack_top, + FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, + )); } FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => { - let frame_data = stack - .pop() - .unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}")); - + let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); assert_eq!( open_delim, delim, @@ -397,28 +398,18 @@ fn make_attr_token_stream( let dspacing = DelimSpacing::new(open_spacing, spacing); let stream = AttrTokenStream::new(frame_data.inner); let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); - stack - .last_mut() - .unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}")) - .inner - .push(delimited); + stack_top.inner.push(delimited); + } + FlatToken::Token(token) => stack_top.inner.push(AttrTokenTree::Token(token, spacing)), + FlatToken::AttrsTarget(target) => { + stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) } - FlatToken::Token(token) => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push(AttrTokenTree::Token(token, spacing)), - FlatToken::AttrsTarget(target) => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } } - let mut final_buf = stack.pop().expect("Missing final buf!"); + if break_last_token { - let last_token = final_buf.inner.pop().unwrap(); + let last_token = stack_top.inner.pop().unwrap(); if let AttrTokenTree::Token(last_token, spacing) = last_token { let unglued_first = last_token.kind.break_two_token_op().unwrap().0; @@ -426,14 +417,14 @@ fn make_attr_token_stream( let mut first_span = last_token.span.shrink_to_lo(); first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1)); - final_buf + stack_top .inner .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing)); } else { panic!("Unexpected last token {last_token:?}") } } - AttrTokenStream::new(final_buf.inner) + AttrTokenStream::new(stack_top.inner) } // Some types are used a lot. Make sure they don't unintentionally get bigger. From 08992d03728015e7305d496540a494c4325196fa Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Mon, 8 Jul 2024 18:09:49 +0800 Subject: [PATCH 173/361] [`missing_const_for_fn`]: fix FP when arg ty is impl trait alias ty --- clippy_lints/src/missing_const_for_fn.rs | 17 +++++++++++++++++ tests/ui/missing_const_for_fn/cant_be_const.rs | 9 +++++++++ .../missing_const_for_fn/could_be_const.fixed | 15 +++++++++++++++ tests/ui/missing_const_for_fn/could_be_const.rs | 15 +++++++++++++++ .../missing_const_for_fn/could_be_const.stderr | 13 ++++++++++++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 44ec1bd08cf3..ed5f46ddc8d2 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -8,6 +8,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; @@ -131,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } + if fn_inputs_has_impl_trait_ty(cx, def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); // Const fns are not allowed as methods in a trait. @@ -185,3 +190,15 @@ fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool _ => cx.tcx.features().const_extern_fn, } } + +/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of +/// its parameter types. +fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(); + 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() + ) + }) +} diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 952ff8283632..2c6e1e92da02 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -7,6 +7,7 @@ #![warn(clippy::missing_const_for_fn)] #![feature(start)] +#![feature(type_alias_impl_trait)] extern crate helper; extern crate proc_macros; @@ -190,3 +191,11 @@ mod with_extern { extern "system" fn system() {} extern "system-unwind" fn system_unwind() {} } + +mod with_ty_alias { + type Foo = impl std::fmt::Debug; + + fn foo(_: Foo) { + let _: Foo = 1; + } +} 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 572ca52439a6..2311bd0acda9 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -186,3 +186,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} 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 4d19c4d7a48e..cb7733ed382a 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -186,3 +186,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} 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 ab36e0a281a7..3cae5bcbc4ab 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -261,5 +261,16 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 19 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:202:5 + | +LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | +++++ + +error: aborting due to 20 previous errors From 8bcbab5dd1c6449c2acd3ea6a94b245c0936722d Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Mon, 8 Jul 2024 09:19:25 -0500 Subject: [PATCH 174/361] Attempt to fix CI --- library/std/src/sys/exit_guard.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index ad6246cc8318..5a090f506661 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -1,5 +1,14 @@ 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. @@ -23,7 +32,7 @@ cfg_if::cfg_if! { 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); + 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 { @@ -31,9 +40,9 @@ cfg_if::cfg_if! { // 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(this_thread_id); + *exiting_thread_id = Some(PThread(this_thread_id)); }, - Some(exiting_thread_id) if exiting_thread_id == this_thread_id => { + Some(exiting_thread_id) if exiting_thread_id.0 == 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. From d23df7471298610f7afc68635fbc005e07a16f6b Mon Sep 17 00:00:00 2001 From: John Arundel Date: Mon, 8 Jul 2024 19:05:35 +0100 Subject: [PATCH 175/361] resolve code review comments --- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 1a4dc38e7e9c..d4a1e2780d08 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// type. Many asynchronous foundation crates provide such a `Mutex` type. /// The other solution is to ensure the mutex is unlocked before calling /// `await`, either by introducing a scope or an explicit call to - /// [`Drop::drop`]. + /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html). /// /// ### Known problems /// Will report false positive for explicitly dropped guards diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 14f9f991d3be..54f0c7c46871 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -219,7 +219,7 @@ declare_clippy_lint! { /// Dereferencing the resulting pointer may be undefined behavior. /// /// ### Known problems - /// Using [`std::ptr::read_unaligned`] and [`std::ptr::write_unaligned`] or + /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or /// similar on the resulting pointer is fine. Is over-zealous: casts with /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be /// fine. Miri is able to do a more in-depth analysis. From 920cbcdd456504acb6999fc647490fed0fe6eece Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 15:36:57 -0400 Subject: [PATCH 176/361] Move trait selection error reporting to its own top-level module --- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/unconditional_recursion.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 42ec2c00823c..d2a34c755832 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index cb1d0de1edff..1fd8faf3ea88 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; -use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 5e41b3f4914f..6ba98a92423c 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, Ident}; use rustc_span::{sym, Span}; -use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; +use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; declare_clippy_lint! { /// ### What it does From 13c6476c906781e458c3877a5b05004d2d791b21 Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 7 Jul 2024 15:05:47 +0200 Subject: [PATCH 177/361] implement support for multiple TLS destructors on macOS --- src/tools/miri/src/shims/tls.rs | 65 ++++++++++--------- .../src/shims/unix/macos/foreign_items.rs | 2 +- .../miri/tests/pass/tls/macos_tlv_atexit.rs | 43 ++++++++++++ .../tests/pass/tls/macos_tlv_atexit.stdout | 7 ++ 4 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs create mode 100644 src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index c91386fa877f..870744687895 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -36,9 +36,9 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single per thread destructor of the thread local storage (that's how - /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap, Scalar)>, + /// On macOS, each thread holds a list of destructor functions with their + /// respective data arguments. + macos_thread_dtors: BTreeMap, Scalar)>>, } impl<'tcx> Default for TlsData<'tcx> { @@ -119,26 +119,15 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set the thread wide destructor of the thread local storage for the given - /// thread. This function is used to implement `_tlv_atexit` shim on MacOS. - /// - /// Thread wide dtors are available only on MacOS. There is one destructor - /// per thread as can be guessed from the following comment in the - /// [`_tlv_atexit` - /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): - /// - /// NOTE: this does not need locks because it only operates on current thread data - pub fn set_macos_thread_dtor( + /// Add a thread local storage destructor for the given thread. This function + /// is used to implement the `_tlv_atexit` shim on MacOS. + pub fn add_macos_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar, ) -> InterpResult<'tcx> { - if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!( - "setting more than one thread local storage destructor for the same thread is not supported" - ); - } + self.macos_thread_dtors.entry(thread).or_default().push((dtor, data)); Ok(()) } @@ -202,6 +191,10 @@ impl<'tcx> TlsData<'tcx> { for TlsEntry { data, .. } in self.keys.values_mut() { data.remove(&thread_id); } + + if let Some(dtors) = self.macos_thread_dtors.remove(&thread_id) { + assert!(dtors.is_empty(), "the destructors should have already been run"); + } } } @@ -212,7 +205,7 @@ impl VisitProvenance for TlsData<'_> { for scalar in keys.values().flat_map(|v| v.data.values()) { scalar.visit_provenance(visit); } - for (_, scalar) in macos_thread_dtors.values() { + for (_, scalar) in macos_thread_dtors.values().flatten() { scalar.visit_provenance(visit); } } @@ -225,6 +218,7 @@ pub struct TlsDtorsState<'tcx>(TlsDtorsStatePriv<'tcx>); enum TlsDtorsStatePriv<'tcx> { #[default] Init, + MacOsDtors, PthreadDtors(RunningDtorState), /// For Windows Dtors, we store the list of functions that we still have to call. /// These are functions from the magic `.CRT$XLB` linker section. @@ -243,11 +237,10 @@ impl<'tcx> TlsDtorsState<'tcx> { Init => { match this.tcx.sess.target.os.as_ref() { "macos" => { - // The macOS thread wide destructor runs "before any TLS slots get - // freed", so do that first. - this.schedule_macos_tls_dtor()?; - // When that destructor is done, go on with the pthread dtors. - break 'new_state PthreadDtors(Default::default()); + // macOS has a _tlv_atexit function that allows + // registering destructors without associated keys. + // These are run first. + break 'new_state MacOsDtors; } _ if this.target_os_is_unix() => { // All other Unixes directly jump to running the pthread dtors. @@ -266,6 +259,14 @@ impl<'tcx> TlsDtorsState<'tcx> { } } } + MacOsDtors => { + match this.schedule_macos_tls_dtor()? { + Poll::Pending => return Ok(Poll::Pending), + // After all macOS destructors are run, the system switches + // to destroying the pthread destructors. + Poll::Ready(()) => break 'new_state PthreadDtors(Default::default()), + } + } PthreadDtors(state) => { match this.schedule_next_pthread_tls_dtor(state)? { Poll::Pending => return Ok(Poll::Pending), // just keep going @@ -328,12 +329,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - /// Schedule the MacOS thread destructor of the thread local storage to be - /// executed. - fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { + /// Schedule the macOS thread local storage destructors to be executed. + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); let thread_id = this.active_thread(); - if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { + // macOS keeps track of TLS destructors in a stack. If a destructor + // registers another destructor, it will be run next. + // See https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/DyldRuntimeState.cpp#L2277 + let dtor = this.machine.tls.macos_thread_dtors.get_mut(&thread_id).and_then(Vec::pop); + if let Some((instance, data)) = dtor { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); this.call_function( @@ -343,8 +347,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None, StackPopCleanup::Root { cleanup: true }, )?; + + return Ok(Poll::Pending); } - Ok(()) + + Ok(Poll::Ready(())) } /// Schedule a pthread TLS destructor. Returns `true` if found diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 25002f0a611c..aefb5b2de56f 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; let active_thread = this.active_thread(); - this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; + this.machine.tls.add_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs new file mode 100644 index 000000000000..845f50c1ebaa --- /dev/null +++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs @@ -0,0 +1,43 @@ +//@only-target-darwin + +use std::thread; + +extern "C" { + fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8); +} + +fn register(f: F) +where + F: FnOnce() + 'static, +{ + // This will receive the pointer passed into `_tlv_atexit`, which is the + // original `f` but boxed up. + unsafe extern "C" fn run(ptr: *mut u8) + where + F: FnOnce() + 'static, + { + let f = unsafe { Box::from_raw(ptr as *mut F) }; + f() + } + + unsafe { + _tlv_atexit(run::, Box::into_raw(Box::new(f)) as *mut u8); + } +} + +fn main() { + thread::spawn(|| { + register(|| println!("dtor 2")); + register(|| println!("dtor 1")); + println!("exiting thread"); + }) + .join() + .unwrap(); + + println!("exiting main"); + register(|| println!("dtor 5")); + register(|| { + println!("registering dtor in dtor 3"); + register(|| println!("dtor 4")); + }); +} diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout new file mode 100644 index 000000000000..89d6ca259354 --- /dev/null +++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout @@ -0,0 +1,7 @@ +exiting thread +dtor 1 +dtor 2 +exiting main +registering dtor in dtor 3 +dtor 4 +dtor 5 From 87856c4461c29eb8c8ef7e3fb28ccfcbd41e4120 Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:37:44 +0000 Subject: [PATCH 178/361] add lint for inline asm labels that look like binary --- compiler/rustc_lint/messages.ftl | 17 +- compiler/rustc_lint/src/builtin.rs | 131 +++++++++++---- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_lint/src/lints.rs | 30 +++- tests/ui/asm/binary_asm_labels.rs | 17 ++ tests/ui/asm/binary_asm_labels.stderr | 43 +++++ tests/ui/asm/named-asm-labels.rs | 24 ++- tests/ui/asm/named-asm-labels.stderr | 224 ++++++++++++++++++++------ 8 files changed, 397 insertions(+), 91 deletions(-) create mode 100644 tests/ui/asm/binary_asm_labels.rs create mode 100644 tests/ui/asm/binary_asm_labels.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 3e952558d29d..9d8271a6acb3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -52,10 +52,6 @@ lint_builtin_allow_internal_unsafe = lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition .suggestion = try naming the parameter or explicitly ignoring it -lint_builtin_asm_labels = avoid using named labels in inline assembly - .help = only local labels of the form `:` should be used in inline asm - .note = see the asm section of Rust By Example for more information - lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration @@ -399,6 +395,19 @@ lint_incomplete_include = lint_inner_macro_attribute_unstable = inner macro attributes are unstable +lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly + .label = use a different label that doesn't start with `0` or `1` + .note = an LLVM bug makes these labels ambiguous with a binary literal number + .note = see for more information + +lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly + .help = only local labels of the form `:` should be used in inline asm + .note1 = format arguments may expand to a non-numeric value + .note2 = see the asm section of Rust By Example for more information +lint_invalid_asm_label_named = avoid using named labels in inline assembly + .help = only local labels of the form `:` should be used in inline asm + .note = see the asm section of Rust By Example for more information +lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro lint_invalid_crate_type_value = invalid `crate_type` value .suggestion = did you mean diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 79c8046f9b74..a661c74cf91d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -30,13 +30,13 @@ use crate::{ BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, - BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric, - BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, - BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion, - BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, + BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, + BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, - BuiltinWhileTrue, SuggestChangingAssocTypes, + BuiltinWhileTrue, InvalidAsmLabel, SuggestChangingAssocTypes, }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; @@ -45,7 +45,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; -use rustc_errors::{Applicability, LintDiagnostic, MultiSpan}; +use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -69,7 +69,6 @@ use rustc_target::abi::Abi; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; -use tracing::debug; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -2728,10 +2727,52 @@ declare_lint! { "named labels in inline assembly", } -declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]); +declare_lint! { + /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary + /// digits in the inline `asm!` macro. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![feature(asm_experimental_arch)] + /// use std::arch::asm; + /// + /// fn main() { + /// unsafe { + /// asm!("0: jmp 0b"); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary + /// literal instead of a reference to the previous local label `0`. Note that even though the + /// bug is marked as fixed, it only fixes a specific usage of intel syntax within standalone + /// files, not inline assembly. To work around this bug, don't use labels that could be + /// confused with a binary literal. + /// + /// See the explanation in [Rust By Example] for more details. + /// + /// [LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 + /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels + pub BINARY_ASM_LABELS, + Deny, + "labels in inline assembly containing only 0 or 1 digits", +} -impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { - #[allow(rustc::diagnostic_outside_of_impl)] +declare_lint_pass!(AsmLabels => [NAMED_ASM_LABELS, BINARY_ASM_LABELS]); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum AsmLabelKind { + Named, + FormatArg, + Binary, +} + +impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }), @@ -2759,7 +2800,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { None }; - let mut found_labels = Vec::new(); + // diagnostics are emitted per-template, so this is created here as opposed to the outer loop + let mut spans = Vec::new(); // A semicolon might not actually be specified as a separator for all targets, but // it seems like LLVM accepts it always. @@ -2782,16 +2824,21 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { // Whether a { bracket has been seen and its } hasn't been found yet. let mut in_bracket = false; + let mut label_kind = AsmLabelKind::Named; - // A label starts with an ASCII alphabetic character or . or _ // A label can also start with a format arg, if it's not a raw asm block. if !raw && start == '{' { in_bracket = true; + label_kind = AsmLabelKind::FormatArg; + } else if matches!(start, '0' | '1') { + // Binary labels have only the characters `0` or `1`. + label_kind = AsmLabelKind::Binary; } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) { + // Named labels start with ASCII letters, `.` or `_`. + // anything else is not a label break 'label_loop; } - // Labels continue with ASCII alphanumeric characters, _, or $ for c in chars { // Inside a template format arg, any character is permitted for the // puproses of label detection because we assume that it can be @@ -2812,8 +2859,18 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } else if !raw && c == '{' { // Start of a format arg. in_bracket = true; + label_kind = AsmLabelKind::FormatArg; } else { - if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) { + let can_continue = match label_kind { + // Format arg labels are considered to be named labels for the purposes + // of continuing outside of their {} pair. + AsmLabelKind::Named | AsmLabelKind::FormatArg => { + c.is_ascii_alphanumeric() || matches!(c, '_' | '$') + } + AsmLabelKind::Binary => matches!(c, '0' | '1'), + }; + + if !can_continue { // The potential label had an invalid character inside it, it // cannot be a label. break 'label_loop; @@ -2821,25 +2878,41 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } } - // If all characters passed the label checks, this is likely a label. - found_labels.push(possible_label); + // If all characters passed the label checks, this is a label. + spans.push((find_label_span(possible_label), label_kind)); start_idx = idx + 1; } } - debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels); - - if found_labels.len() > 0 { - let spans = found_labels - .into_iter() - .filter_map(|label| find_label_span(label)) - .collect::>(); - // If there were labels but we couldn't find a span, combine the warnings and - // use the template span. - let target_spans: MultiSpan = - if spans.len() > 0 { spans.into() } else { (*template_span).into() }; - - cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel); + for (span, label_kind) in spans { + let missing_precise_span = span.is_none(); + let span = span.unwrap_or(*template_span); + match label_kind { + AsmLabelKind::Named => { + cx.emit_span_lint( + NAMED_ASM_LABELS, + span, + InvalidAsmLabel::Named { missing_precise_span }, + ); + } + AsmLabelKind::FormatArg => { + cx.emit_span_lint( + NAMED_ASM_LABELS, + span, + InvalidAsmLabel::FormatArg { missing_precise_span }, + ); + } + AsmLabelKind::Binary => { + // the binary asm issue only occurs when using intel syntax + if !options.contains(InlineAsmOptions::ATT_SYNTAX) { + cx.emit_span_lint( + BINARY_ASM_LABELS, + span, + InvalidAsmLabel::Binary { missing_precise_span, span }, + ) + } + } + }; } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 17f9d4421aef..31b76b7c6ff8 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -220,7 +220,7 @@ late_lint_methods!( NoopMethodCall: NoopMethodCall, EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, InvalidAtomicOrdering: InvalidAtomicOrdering, - NamedAsmLabels: NamedAsmLabels, + AsmLabels: AsmLabels, OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7c5640f5959a..b3f715c21747 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2040,10 +2040,32 @@ pub struct UnitBindingsDiag { } #[derive(LintDiagnostic)] -#[diag(lint_builtin_asm_labels)] -#[help] -#[note] -pub struct BuiltinNamedAsmLabel; +pub enum InvalidAsmLabel { + #[diag(lint_invalid_asm_label_named)] + #[help] + #[note] + Named { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + }, + #[diag(lint_invalid_asm_label_format_arg)] + #[help] + #[note(lint_note1)] + #[note(lint_note2)] + FormatArg { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + }, + #[diag(lint_invalid_asm_label_binary)] + #[note] + Binary { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + // hack to get a label on the whole span, must match the emitted span + #[label] + span: Span, + }, +} #[derive(Subdiagnostic)] pub enum UnexpectedCfgCargoHelp { diff --git a/tests/ui/asm/binary_asm_labels.rs b/tests/ui/asm/binary_asm_labels.rs new file mode 100644 index 000000000000..3f545880254c --- /dev/null +++ b/tests/ui/asm/binary_asm_labels.rs @@ -0,0 +1,17 @@ +//@ needs-asm-support +//@ only-x86_64 + +// tests that labels containing only the digits 0 and 1 are rejected +// uses of such labels can sometimes be interpreted as a binary literal + +use std::arch::{asm, global_asm}; + +fn main() { + unsafe { + asm!("0: jmp 0b"); //~ ERROR avoid using labels containing only the digits + asm!("1: jmp 1b"); //~ ERROR avoid using labels containing only the digits + asm!("10: jmp 10b"); //~ ERROR avoid using labels containing only the digits + asm!("01: jmp 01b"); //~ ERROR avoid using labels containing only the digits + asm!("1001101: jmp 1001101b"); //~ ERROR avoid using labels containing only the digits + } +} diff --git a/tests/ui/asm/binary_asm_labels.stderr b/tests/ui/asm/binary_asm_labels.stderr new file mode 100644 index 000000000000..1f2943084f1e --- /dev/null +++ b/tests/ui/asm/binary_asm_labels.stderr @@ -0,0 +1,43 @@ +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:11:15 + | +LL | asm!("0: jmp 0b"); + | ^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + = note: `#[deny(binary_asm_labels)]` on by default + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:12:15 + | +LL | asm!("1: jmp 1b"); + | ^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:13:15 + | +LL | asm!("10: jmp 10b"); + | ^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:14:15 + | +LL | asm!("01: jmp 01b"); + | ^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:15:15 + | +LL | asm!("1001101: jmp 1001101b"); + | ^^^^^^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: aborting due to 5 previous errors + diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 96ccdef75b0c..d2ca6fe8808b 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -28,11 +28,13 @@ fn main() { // Multiple labels on one line asm!("foo: bar1: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Multiple lines asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels asm!("foo2: foo3: nop", "nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("nop", "foo4: nop"); //~ ERROR avoid using named labels asm!("foo5: nop", "foo6: nop"); //~^ ERROR avoid using named labels @@ -41,16 +43,19 @@ fn main() { // Statement separator asm!("foo7: nop; foo8: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("foo9: nop; nop"); //~ ERROR avoid using named labels asm!("nop; foo10: nop"); //~ ERROR avoid using named labels // Escaped newline asm!("bar2: nop\n bar3: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("bar4: nop\n nop"); //~ ERROR avoid using named labels asm!("nop\n bar5: nop"); //~ ERROR avoid using named labels asm!("nop\n bar6: bar7: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Raw strings asm!( @@ -60,6 +65,7 @@ fn main() { " ); //~^^^^ ERROR avoid using named labels + //~^^^^ ERROR avoid using named labels asm!( r###" @@ -81,9 +87,15 @@ fn main() { asm!("blah1: 2bar: nop"); //~ ERROR avoid using named labels // Duplicate labels - asm!("def: def: nop"); //~ ERROR avoid using named labels - asm!("def: nop\ndef: nop"); //~ ERROR avoid using named labels - asm!("def: nop; def: nop"); //~ ERROR avoid using named labels + asm!("def: def: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + asm!("def: nop\ndef: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + asm!("def: nop; def: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Trying to break parsing asm!(":"); @@ -141,7 +153,11 @@ fn main() { asm!("{1}: nop", "/* {0} */", const 10, const 20); //~ ERROR avoid using named labels // Test include_str in asm - asm!(include_str!("named-asm-labels.s")); //~ ERROR avoid using named labels + asm!(include_str!("named-asm-labels.s")); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + //~^^^ ERROR avoid using named labels + //~^^^^ ERROR avoid using named labels // Test allowing or warning on the lint instead #[allow(named_asm_labels)] diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index 36fd69839518..20b7d64f9e75 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -21,13 +21,22 @@ error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:29:15 | LL | asm!("foo: bar1: nop"); - | ^^^ ^^^^ + | ^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:15 + --> $DIR/named-asm-labels.rs:29:20 + | +LL | asm!("foo: bar1: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:34:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -36,16 +45,25 @@ LL | asm!("foo1: nop", "nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:34:15 + --> $DIR/named-asm-labels.rs:35:15 | LL | asm!("foo2: foo3: nop", "nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:36:22 + --> $DIR/named-asm-labels.rs:35:21 + | +LL | asm!("foo2: foo3: nop", "nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:38:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -54,7 +72,7 @@ LL | asm!("nop", "foo4: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:37:15 + --> $DIR/named-asm-labels.rs:39:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -63,7 +81,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:37:28 + --> $DIR/named-asm-labels.rs:39:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -72,16 +90,25 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:42:15 + --> $DIR/named-asm-labels.rs:44:15 | LL | asm!("foo7: nop; foo8: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:15 + --> $DIR/named-asm-labels.rs:44:26 + | +LL | asm!("foo7: nop; foo8: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:47:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -90,7 +117,7 @@ LL | asm!("foo9: nop; nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:45:20 + --> $DIR/named-asm-labels.rs:48:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -99,16 +126,25 @@ LL | asm!("nop; foo10: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:48:15 + --> $DIR/named-asm-labels.rs:51:15 | LL | asm!("bar2: nop\n bar3: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:50:15 + --> $DIR/named-asm-labels.rs:51:27 + | +LL | asm!("bar2: nop\n bar3: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:54:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -117,7 +153,7 @@ LL | asm!("bar4: nop\n nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:51:21 + --> $DIR/named-asm-labels.rs:55:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -126,19 +162,35 @@ LL | asm!("nop\n bar5: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:52:21 + --> $DIR/named-asm-labels.rs:56:21 | LL | asm!("nop\n bar6: bar7: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:58:13 + --> $DIR/named-asm-labels.rs:56:27 + | +LL | asm!("nop\n bar6: bar7: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:63:13 | LL | blah2: nop | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:64:13 + | LL | blah3: nop | ^^^^^ | @@ -146,7 +198,7 @@ LL | blah3: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:67:19 + --> $DIR/named-asm-labels.rs:73:19 | LL | nop ; blah4: nop | ^^^^^ @@ -155,7 +207,7 @@ LL | nop ; blah4: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:81:15 + --> $DIR/named-asm-labels.rs:87:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -164,7 +216,7 @@ LL | asm!("blah1: 2bar: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:84:15 + --> $DIR/named-asm-labels.rs:90:15 | LL | asm!("def: def: nop"); | ^^^ @@ -173,7 +225,17 @@ LL | asm!("def: def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:85:15 + --> $DIR/named-asm-labels.rs:90:15 + | +LL | asm!("def: def: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:93:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -182,7 +244,17 @@ LL | asm!("def: nop\ndef: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:86:15 + --> $DIR/named-asm-labels.rs:93:15 + | +LL | asm!("def: nop\ndef: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:96:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -191,7 +263,17 @@ LL | asm!("def: nop; def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:94:15 + --> $DIR/named-asm-labels.rs:96:15 + | +LL | asm!("def: nop; def: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:106:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -200,7 +282,7 @@ LL | asm!("fooo\u{003A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:95:15 + --> $DIR/named-asm-labels.rs:107:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -209,7 +291,7 @@ LL | asm!("foooo\x3A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:98:15 + --> $DIR/named-asm-labels.rs:110:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -218,7 +300,7 @@ LL | asm!("fooooo:\u{000A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:99:15 + --> $DIR/named-asm-labels.rs:111:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -227,16 +309,17 @@ LL | asm!("foooooo:\x0A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:103:14 + --> $DIR/named-asm-labels.rs:115:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:111:13 + --> $DIR/named-asm-labels.rs:123:13 | LL | ab: nop // ab: does foo | ^^ @@ -245,97 +328,140 @@ LL | ab: nop // ab: does foo = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:131:19 + --> $DIR/named-asm-labels.rs:143:19 | LL | asm!("test_{}: nop", in(reg) 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:133:15 + --> $DIR/named-asm-labels.rs:145:15 | LL | asm!("test_{}: nop", const 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:134:15 + --> $DIR/named-asm-labels.rs:146:15 | LL | asm!("test_{}: nop", sym main); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:135:15 + --> $DIR/named-asm-labels.rs:147:15 | LL | asm!("{}_test: nop", const 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:136:15 + --> $DIR/named-asm-labels.rs:148:15 | LL | asm!("test_{}_test: nop", const 10); | ^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:137:15 + --> $DIR/named-asm-labels.rs:149:15 | LL | asm!("{}: nop", const 10); | ^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:139:15 + --> $DIR/named-asm-labels.rs:151:15 | LL | asm!("{uwu}: nop", uwu = const 10); | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:140:15 + --> $DIR/named-asm-labels.rs:152:15 | LL | asm!("{0}: nop", const 10); | ^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:141:15 + --> $DIR/named-asm-labels.rs:153:15 | LL | asm!("{1}: nop", "/* {0} */", const 10, const 20); | ^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:144:14 + --> $DIR/named-asm-labels.rs:156:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:154:19 + --> $DIR/named-asm-labels.rs:170:19 | LL | asm!("warned: nop"); | ^^^^^^ @@ -343,13 +469,13 @@ LL | asm!("warned: nop"); = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information note: the lint level is defined here - --> $DIR/named-asm-labels.rs:152:16 + --> $DIR/named-asm-labels.rs:168:16 | LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:163:20 + --> $DIR/named-asm-labels.rs:179:20 | LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -358,7 +484,7 @@ LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:169:20 + --> $DIR/named-asm-labels.rs:185:20 | LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -367,7 +493,7 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:177:20 + --> $DIR/named-asm-labels.rs:193:20 | LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } | ^^^^^ @@ -376,7 +502,7 @@ LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:187:24 + --> $DIR/named-asm-labels.rs:203:24 | LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } | ^^^^^ @@ -385,7 +511,7 @@ LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:196:15 + --> $DIR/named-asm-labels.rs:212:15 | LL | asm!("closure1: nop"); | ^^^^^^^^ @@ -394,7 +520,7 @@ LL | asm!("closure1: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:200:15 + --> $DIR/named-asm-labels.rs:216:15 | LL | asm!("closure2: nop"); | ^^^^^^^^ @@ -403,7 +529,7 @@ LL | asm!("closure2: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:210:19 + --> $DIR/named-asm-labels.rs:226:19 | LL | asm!("closure3: nop"); | ^^^^^^^^ @@ -411,5 +537,5 @@ LL | asm!("closure3: nop"); = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information -error: aborting due to 44 previous errors; 1 warning emitted +error: aborting due to 56 previous errors; 1 warning emitted From f86f78932365ffdc7f8eaee0d0f30746652bd48b Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 9 Jul 2024 04:55:54 +0000 Subject: [PATCH 179/361] 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 25d559d789fd..e90d3732ca57 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -51917e2e69702e5752bce6a4f3bfd285d0f4ae39 +99b7134389e9766462601a2fc4013840b9d31745 From a067cd24ace399be139578aeb0b3137785a79eb7 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Tue, 9 Jul 2024 10:12:09 +0300 Subject: [PATCH 180/361] Replace incorrect suggested fix for `float_cmp` Using `f32::EPSILON` or `f64::EPSILON` as the floating-point equality comparison error margin is incorrect, yet `float_cmp` has until now recommended this be done. This change fixes the given guidance (both in docs and compiler hints) to not reference these unsuitable constants. Instead, the guidance now clarifies that the scenarios in which an absolute error margin is usable, provides a reference implementation of using a user-defined absolute error margin (as an absolute error margin can only be used-defined and may be different for different comparisons) and references the floating point guide for a reference implementation of relative error based equaltiy comparison for when absolute error margin cannot be used. changelog: Fix guidance of [`float_cmp`] and [`float_cmp_const`] to not incorrectly recommend `f64::EPSILON` as the error margin. Fixes #6816 --- clippy_lints/src/operators/float_cmp.rs | 1 - clippy_lints/src/operators/mod.rs | 118 ++++++++++++++++-------- tests/ui/float_cmp.rs | 6 -- tests/ui/float_cmp.stderr | 21 +---- tests/ui/float_cmp_const.rs | 8 -- tests/ui/float_cmp_const.stderr | 39 +++----- 6 files changed, 98 insertions(+), 95 deletions(-) diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index faab79de9d3c..0e5b440c50f2 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>( Applicability::HasPlaceholders, // snippet ); } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); }); } } diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 1079934934c5..32323f657b0e 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -574,69 +574,113 @@ declare_clippy_lint! { /// implement equality for a type involving floats). /// /// ### Why is this bad? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x = 1.2331f64; - /// let y = 1.2332f64; /// - /// if y == 1.23f64 { } - /// if y != x {} // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x = 1.2331f64; - /// # let y = 1.2332f64; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (y - 1.23f64).abs() < error_margin { } - /// if (y - x).abs() > error_margin { } + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP, pedantic, - "using `==` or `!=` on float values instead of comparing difference with an epsilon" + "using `==` or `!=` on float values instead of comparing difference with an allowed error" } declare_clippy_lint! { /// ### What it does - /// Checks for (in-)equality comparisons on floating-point - /// value and constant, except in functions called `*eq*` (which probably + /// Checks for (in-)equality comparisons on constant floating-point + /// values (apart from zero), except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// ### Why restrict this? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// ### Why is this bad? + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x: f64 = 1.0; - /// const ONE: f64 = 1.00; /// - /// if x == ONE { } // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x: f64 = 1.0; - /// # const ONE: f64 = 1.00; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (x - ONE).abs() < error_margin { } + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP_CONST, restriction, - "using `==` or `!=` on float constants instead of comparing difference with an epsilon" + "using `==` or `!=` on float constants instead of comparing difference with an allowed error" } declare_clippy_lint! { diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 1923ad7c677e..78dd2c6c01c3 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -71,19 +71,16 @@ fn main() { twice(ONE) != ONE; ONE as f64 != 2.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE as f64 != 0.0; // no error, comparison with zero is ok let x: f64 = 1.0; x == 1.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x != 0f64; // no error, comparison with zero is ok twice(x) != twice(ONE as f64); //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x < 0.0; // no errors, lower or greater comparisons need no fuzzyness x > 0.0; @@ -105,17 +102,14 @@ fn main() { ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let a1: [f32; 1] = [0.0]; let a2: [f32; 1] = [1.1]; a1 == a2; //~^ ERROR: strict comparison of `f32` or `f64` arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` a1[0] == a2[0]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors - comparing signums is ok let x32 = 3.21f32; diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index c8a0bde6e63a..d10da8a99a9d 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -4,49 +4,38 @@ error: strict comparison of `f32` or `f64` LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:79:5 + --> tests/ui/float_cmp.rs:78:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:84:5 + --> tests/ui/float_cmp.rs:82:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:106:5 + --> tests/ui/float_cmp.rs:103:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> tests/ui/float_cmp.rs:113:5 + --> tests/ui/float_cmp.rs:109:5 | LL | a1 == a2; | ^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:116:5 + --> tests/ui/float_cmp.rs:111:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 6 previous errors diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index 47ea0e19c68b..081805564373 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -15,28 +15,21 @@ fn main() { // has errors 1f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE + ONE == TWO; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let x = 1; x as f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let v = 0.9; v == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` v != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors, lower than or greater than comparisons v < ONE; @@ -70,5 +63,4 @@ fn main() { // has errors NON_ZERO_ARRAY == NON_ZERO_ARRAY2; //~^ ERROR: strict comparison of `f32` or `f64` constant arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` } diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index bffd2acc2e04..4f88746e958e 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -4,65 +4,50 @@ error: strict comparison of `f32` or `f64` constant LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:19:5 + --> tests/ui/float_cmp_const.rs:18:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` + +error: strict comparison of `f32` or `f64` constant + --> tests/ui/float_cmp_const.rs:20:5 | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | TWO != ONE; + | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:22:5 | -LL | TWO != ONE; - | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | ONE + ONE == TWO; + | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:25:5 | -LL | ONE + ONE == TWO; - | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | x as f32 == ONE; + | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:29:5 | -LL | x as f32 == ONE; - | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` - -error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:34:5 - | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:37:5 + --> tests/ui/float_cmp_const.rs:31:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant arrays - --> tests/ui/float_cmp_const.rs:71:5 + --> tests/ui/float_cmp_const.rs:64:5 | LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 8 previous errors From a04dbb0ab9fd79cba5faaa2cf8e03082b2831387 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Tue, 9 Jul 2024 10:28:11 +0300 Subject: [PATCH 181/361] Tidy the example code and ensure it builds as standalone snippets --- clippy_lints/src/operators/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 32323f657b0e..bf7a581c8486 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -606,6 +606,11 @@ declare_clippy_lint! { /// For the scenario where you can define a meaningful absolute error margin, consider using: /// /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; /// println!("{within_tolerance}"); // true @@ -647,7 +652,7 @@ declare_clippy_lint! { /// // Actual value: 1000.3000000000001 /// println!("{x}"); /// - /// let are_equal = x == y; + /// let are_equal = x == Y; /// println!("{are_equal}"); // false /// ``` /// @@ -664,6 +669,11 @@ declare_clippy_lint! { /// For the scenario where you can define a meaningful absolute error margin, consider using: /// /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; /// println!("{within_tolerance}"); // true From cf25d25de39c844f4d091f73b3cee581b4514102 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:16:04 +0000 Subject: [PATCH 182/361] Rustup to rustc 1.81.0-nightly (35b658fb1 2024-07-08) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index cfa91744a0e8..92ea4fc4b270 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-06-30" +channel = "nightly-2024-07-09" components = ["rust-src", "rustc-dev", "llvm-tools"] From 344e4ef7875c923fd435ef95306d436712af9d2d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:30:12 +0000 Subject: [PATCH 183/361] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index c1b7e4b0e076..9cd3f8e6cf54 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -56,6 +56,7 @@ rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported +rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes # requires LTO rm -r tests/run-make/cdylib @@ -109,6 +110,7 @@ rm -r tests/run-make/symbols-include-type-name rm -r tests/run-make/notify-all-emit-artifacts rm -r tests/run-make/reset-codegen-1 rm -r tests/run-make/inline-always-many-cgu +rm -r tests/run-make/intrinsic-unreachable # giving different but possibly correct results # ============================================= From 7292fa2a90da9e8b1a434677774f26ced868d0d8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:40:29 +0000 Subject: [PATCH 184/361] Update dependencies --- Cargo.lock | 94 +++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15c9e9d66fac..efec5db836bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -67,7 +67,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "log", "regalloc2", "rustc-hash", @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -203,9 +203,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", "indexmap", @@ -223,9 +223,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] @@ -237,20 +237,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets", @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "mach" @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "object" @@ -284,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "crc32fast", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "indexmap", "memchr", ] @@ -297,9 +297,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -382,9 +382,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.60" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -393,9 +393,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" [[package]] name = "unicode-ident" @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -470,66 +470,66 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", From 96fa075225cce2d7af090256c90c2d2bc5a0ccda Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:46:21 +0000 Subject: [PATCH 185/361] Fix rustc test suite --- scripts/test_rustc_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 9cd3f8e6cf54..ebe0b634e8b2 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -34,6 +34,7 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # vendor intrinsics rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic +rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps # exotic linkages rm tests/incremental/hashes/function_interfaces.rs From f5527949f2e819c056551a25d8fab7008facf6da Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jul 2024 19:32:21 +1000 Subject: [PATCH 186/361] Move `Spacing` into `FlatToken`. It's only needed for the `FlatToken::Token` variant. This makes things a little more concise. --- .../rustc_parse/src/parser/attr_wrapper.rs | 28 ++++++++----------- compiler/rustc_parse/src/parser/mod.rs | 2 +- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 5a4259eb1e76..67d2424bb48a 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -103,11 +103,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) - .chain(iter::repeat_with(|| { - let token = cursor_snapshot.next(); - (FlatToken::Token(token.0), token.1) - })) + let tokens = iter::once(FlatToken::Token(self.start_token.clone())) + .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) .take(self.num_calls as usize); if self.replace_ranges.is_empty() { @@ -156,11 +153,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { (range.start as usize)..(range.end as usize), target .into_iter() - .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) - .chain( - iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - target_len), - ), + .map(|target| FlatToken::AttrsTarget(target)) + .chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)), ); } make_attr_token_stream(tokens.into_iter(), self.break_last_token) @@ -367,7 +361,7 @@ impl<'a> Parser<'a> { /// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and /// close delims. fn make_attr_token_stream( - iter: impl Iterator, + iter: impl Iterator, break_last_token: bool, ) -> AttrTokenStream { #[derive(Debug)] @@ -379,15 +373,15 @@ fn make_attr_token_stream( // The stack always has at least one element. Storing it separately makes for shorter code. let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] }; let mut stack_rest = vec![]; - for (token, spacing) in iter { - match token { - FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { + for flat_token in iter { + match flat_token { + FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => { stack_rest.push(mem::replace( &mut stack_top, FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, )); } - FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => { + FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => { let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); assert_eq!( @@ -400,7 +394,9 @@ fn make_attr_token_stream( let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); stack_top.inner.push(delimited); } - FlatToken::Token(token) => stack_top.inner.push(AttrTokenTree::Token(token, spacing)), + FlatToken::Token((token, spacing)) => { + stack_top.inner.push(AttrTokenTree::Token(token, spacing)) + } FlatToken::AttrsTarget(target) => { stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 45ca267fe5d1..1482c665a16b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1607,7 +1607,7 @@ pub(crate) fn make_unclosed_delims_error( enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens - Token(Token), + Token((Token, Spacing)), /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted /// directly into the constructed `AttrTokenStream` as an /// `AttrTokenTree::AttrsTarget`. From ea7c1366b5c11e7da7cdd9b1ceb9e5b9c2912351 Mon Sep 17 00:00:00 2001 From: Askar Safin Date: Sat, 29 Jun 2024 04:18:51 +0300 Subject: [PATCH 187/361] Fix libc::read shim: make it write to a buffer correct amount of bytes. Add tests for the new behavior. libc::read shim had a bug: if underlying real call libc::read(fd, buf, N) returns M, then libc::read shim writes N bytes to buf instead of M. Remaining N - M bytes are filled with zeros. This commit fixes this bug and adds tests for new behavior --- src/tools/miri/src/shims/unix/fd.rs | 7 +++- .../libc-read-and-uninit-premature-eof.rs | 27 ++++++++++++++ .../libc-read-and-uninit-premature-eof.stderr | 15 ++++++++ src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 35 +++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 599f78e712a2..c144f1cdccb4 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -394,7 +394,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match result { Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.write_bytes_ptr(buf, bytes)?; + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + this.write_bytes_ptr( + buf, + bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(), + )?; Ok(read_bytes) } Err(e) => { diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs new file mode 100644 index 000000000000..98ef454c88b3 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs @@ -0,0 +1,27 @@ +//! We test that if we requested to read 4 bytes, but actually read 3 bytes, +//! then 3 bytes (not 4) will be initialized. +//@ignore-target-windows: no file system support on Windows +//@compile-flags: -Zmiri-disable-isolation + +use std::ffi::CString; +use std::fs::remove_file; +use std::mem::MaybeUninit; + +#[path = "../../utils/mod.rs"] +mod utils; + +fn main() { + let path = + utils::prepare_with_content("fail-libc-read-and-uninit-premature-eof.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit(); + // Read 4 bytes from a 3-byte file. + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 4), 3); + buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr new file mode 100644 index 000000000000..e4c7aba07e34 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + --> $DIR/libc-read-and-uninit-premature-eof.rs:LL:CC + | +LL | ... buf.assume_init(); + | ^^^^^^^^^^^^^^^^^ constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + | + = 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 $DIR/libc-read-and-uninit-premature-eof.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-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 80c9757e9c95..f35229a205fb 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -35,6 +35,7 @@ fn main() { #[cfg(target_os = "linux")] test_sync_file_range(); test_isatty(); + test_read_and_uninit(); } fn test_file_open_unix_allow_two_args() { @@ -362,3 +363,37 @@ fn test_isatty() { remove_file(&path).unwrap(); } } + +fn test_read_and_uninit() { + use std::mem::MaybeUninit; + { + // We test that libc::read initializes its buffer. + let path = utils::prepare_with_content("pass-libc-read-and-uninit.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf: MaybeUninit<[u8; 2]> = std::mem::MaybeUninit::uninit(); + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 2), 2); + let buf = buf.assume_init(); + assert_eq!(buf, [1, 2]); + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); + } + { + // We test that if we requested to read 4 bytes, but actually read 3 bytes, then + // 3 bytes (not 4) will be overwritten, and remaining byte will be left as-is. + let path = utils::prepare_with_content("pass-libc-read-and-uninit-2.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf = [42u8; 5]; + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 4), 3); + assert_eq!(buf, [1, 2, 3, 42, 42]); + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); + } +} From c3a240608b6600c8a5ccc89cdcb823836bea0530 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 8 Jul 2024 16:39:35 +0200 Subject: [PATCH 188/361] Lintcheck: Refactor structs and only take one version per crate --- lintcheck/lintcheck_crates.toml | 52 ++-- lintcheck/src/input.rs | 288 +++++++++++++++++ lintcheck/src/main.rs | 528 +------------------------------- lintcheck/src/output.rs | 235 ++++++++++++++ lintcheck/src/popular_crates.rs | 2 +- lintcheck/src/recursive.rs | 3 +- 6 files changed, 567 insertions(+), 541 deletions(-) create mode 100644 lintcheck/src/input.rs create mode 100644 lintcheck/src/output.rs diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml index 52f7fee47b61..ff608e6f9359 100644 --- a/lintcheck/lintcheck_crates.toml +++ b/lintcheck/lintcheck_crates.toml @@ -1,38 +1,38 @@ [crates] # some of these are from cargotest -cargo = {name = "cargo", versions = ['0.64.0']} -iron = {name = "iron", versions = ['0.6.1']} -ripgrep = {name = "ripgrep", versions = ['12.1.1']} -xsv = {name = "xsv", versions = ['0.13.0']} +cargo = {name = "cargo", version = '0.64.0'} +iron = {name = "iron", version = '0.6.1'} +ripgrep = {name = "ripgrep", version = '12.1.1'} +xsv = {name = "xsv", version = '0.13.0'} # commented out because of 173K clippy::match_same_arms msgs in language_type.rs -#tokei = { name = "tokei", versions = ['12.0.4']} -rayon = {name = "rayon", versions = ['1.5.0']} -serde = {name = "serde", versions = ['1.0.118']} +#tokei = { name = "tokei", version = '12.0.4'} +rayon = {name = "rayon", version = '1.5.0'} +serde = {name = "serde", version = '1.0.118'} # top 10 crates.io dls -bitflags = {name = "bitflags", versions = ['1.2.1']} +bitflags = {name = "bitflags", version = '1.2.1'} # crash = {name = "clippy_crash", path = "/tmp/clippy_crash"} -libc = {name = "libc", versions = ['0.2.81']} -log = {name = "log", versions = ['0.4.11']} -proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} -quote = {name = "quote", versions = ['1.0.7']} -rand = {name = "rand", versions = ['0.7.3']} -rand_core = {name = "rand_core", versions = ['0.6.0']} -regex = {name = "regex", versions = ['1.3.2']} -syn = {name = "syn", versions = ['1.0.54']} -unicode-xid = {name = "unicode-xid", versions = ['0.2.1']} +libc = {name = "libc", version = '0.2.81'} +log = {name = "log", version = '0.4.11'} +proc-macro2 = {name = "proc-macro2", version = '1.0.24'} +quote = {name = "quote", version = '1.0.7'} +rand = {name = "rand", version = '0.7.3'} +rand_core = {name = "rand_core", version = '0.6.0'} +regex = {name = "regex", version = '1.3.2'} +syn = {name = "syn", version = '1.0.54'} +unicode-xid = {name = "unicode-xid", version = '0.2.1'} # some more of dtolnays crates -anyhow = {name = "anyhow", versions = ['1.0.38']} -async-trait = {name = "async-trait", versions = ['0.1.42']} -cxx = {name = "cxx", versions = ['1.0.32']} -ryu = {name = "ryu", versions = ['1.0.5']} -serde_yaml = {name = "serde_yaml", versions = ['0.8.17']} -thiserror = {name = "thiserror", versions = ['1.0.24']} +anyhow = {name = "anyhow", version = '1.0.38'} +async-trait = {name = "async-trait", version = '0.1.42'} +cxx = {name = "cxx", version = '1.0.32'} +ryu = {name = "ryu", version = '1.0.5'} +serde_yaml = {name = "serde_yaml", version = '0.8.17'} +thiserror = {name = "thiserror", version = '1.0.24'} # some embark crates, there are other interesting crates but # unfortunately adding them increases lintcheck runtime drastically -cfg-expr = {name = "cfg-expr", versions = ['0.7.1']} +cfg-expr = {name = "cfg-expr", version = '0.7.1'} puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} -rpmalloc = {name = "rpmalloc", versions = ['0.2.0']} -tame-oidc = {name = "tame-oidc", versions = ['0.1.0']} +rpmalloc = {name = "rpmalloc", version = '0.2.0'} +tame-oidc = {name = "tame-oidc", version = '0.1.0'} [recursive] ignore = [ diff --git a/lintcheck/src/input.rs b/lintcheck/src/input.rs new file mode 100644 index 000000000000..3d034391c280 --- /dev/null +++ b/lintcheck/src/input.rs @@ -0,0 +1,288 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::{self}; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::Duration; + +use serde::Deserialize; +use walkdir::{DirEntry, WalkDir}; + +use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES}; + +/// List of sources to check, loaded from a .toml file +#[derive(Debug, Deserialize)] +pub struct SourceList { + crates: HashMap, + #[serde(default)] + recursive: RecursiveOptions, +} + +#[derive(Debug, Deserialize, Default)] +pub struct RecursiveOptions { + pub ignore: HashSet, +} + +/// A crate source stored inside the .toml +/// will be translated into on one of the `CrateSource` variants +#[derive(Debug, Deserialize)] +struct TomlCrate { + name: String, + version: Option, + git_url: Option, + git_hash: Option, + path: Option, + options: Option>, +} + +/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder +/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub enum CrateSource { + CratesIo { + name: String, + version: String, + options: Option>, + }, + Git { + name: String, + url: String, + commit: String, + options: Option>, + }, + Path { + name: String, + path: PathBuf, + options: Option>, + }, +} + +/// Read a `lintcheck_crates.toml` file +pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { + let toml_content: String = + fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); + let crate_list: SourceList = + toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); + // parse the hashmap of the toml file into a list of crates + let tomlcrates: Vec = crate_list.crates.into_values().collect(); + + // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => + // multiple Cratesources) + let mut crate_sources = Vec::new(); + for tk in tomlcrates { + if let Some(ref path) = tk.path { + crate_sources.push(CrateSource::Path { + name: tk.name.clone(), + path: PathBuf::from(path), + options: tk.options.clone(), + }); + } else if let Some(ref version) = tk.version { + crate_sources.push(CrateSource::CratesIo { + name: tk.name.clone(), + version: version.to_string(), + options: tk.options.clone(), + }); + } else if tk.git_url.is_some() && tk.git_hash.is_some() { + // otherwise, we should have a git source + crate_sources.push(CrateSource::Git { + name: tk.name.clone(), + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), + options: tk.options.clone(), + }); + } else { + panic!("Invalid crate source: {tk:?}"); + } + + // if we have a version as well as a git data OR only one git data, something is funky + if tk.version.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) + || tk.git_hash.is_some() != tk.git_url.is_some() + { + eprintln!("tomlkrate: {tk:?}"); + assert_eq!( + tk.git_hash.is_some(), + tk.git_url.is_some(), + "Error: Encountered TomlCrate with only one of git_hash and git_url!" + ); + assert!( + tk.path.is_none() || (tk.git_hash.is_none() && tk.version.is_none()), + "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" + ); + unreachable!("Failed to translate TomlCrate into CrateSource!"); + } + } + // sort the crates + crate_sources.sort(); + + (crate_sources, crate_list.recursive) +} + +impl CrateSource { + /// Makes the sources available on the disk for clippy to check. + /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or + /// copies a local folder + #[expect(clippy::too_many_lines)] + pub fn download_and_extract(&self) -> Crate { + #[allow(clippy::result_large_err)] + fn get(path: &str) -> Result { + const MAX_RETRIES: u8 = 4; + let mut retries = 0; + loop { + match ureq::get(path).call() { + Ok(res) => return Ok(res), + Err(e) if retries >= MAX_RETRIES => return Err(e), + Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), + Err(e) => return Err(e), + } + eprintln!("retrying in {retries} seconds..."); + std::thread::sleep(Duration::from_secs(u64::from(retries))); + retries += 1; + } + } + match self { + CrateSource::CratesIo { name, version, options } => { + let extract_dir = PathBuf::from(LINTCHECK_SOURCES); + let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); + + // url to download the crate from crates.io + let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); + println!("Downloading and extracting {name} {version} from {url}"); + create_dirs(&krate_download_dir, &extract_dir); + + let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); + // don't download/extract if we already have done so + if !krate_file_path.is_file() { + // create a file path to download and write the crate data into + let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); + let mut krate_req = get(&url).unwrap().into_reader(); + // copy the crate into the file + io::copy(&mut krate_req, &mut krate_dest).unwrap(); + + // unzip the tarball + let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); + // extract the tar archive + let mut archive = tar::Archive::new(ungz_tar); + archive.unpack(&extract_dir).expect("Failed to extract!"); + } + // crate is extracted, return a new Krate object which contains the path to the extracted + // sources that clippy can check + Crate { + version: version.clone(), + name: name.clone(), + path: extract_dir.join(format!("{name}-{version}/")), + options: options.clone(), + } + }, + CrateSource::Git { + name, + url, + commit, + options, + } => { + let repo_path = { + let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); + // add a -git suffix in case we have the same crate from crates.io and a git repo + repo_path.push(format!("{name}-git")); + repo_path + }; + // clone the repo if we have not done so + if !repo_path.is_dir() { + println!("Cloning {url} and checking out {commit}"); + if !Command::new("git") + .arg("clone") + .arg(url) + .arg(&repo_path) + .status() + .expect("Failed to clone git repo!") + .success() + { + eprintln!("Failed to clone {url} into {}", repo_path.display()); + } + } + // check out the commit/branch/whatever + if !Command::new("git") + .args(["-c", "advice.detachedHead=false"]) + .arg("checkout") + .arg(commit) + .current_dir(&repo_path) + .status() + .expect("Failed to check out commit") + .success() + { + eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); + } + + Crate { + version: commit.clone(), + name: name.clone(), + path: repo_path, + options: options.clone(), + } + }, + CrateSource::Path { name, path, options } => { + fn is_cache_dir(entry: &DirEntry) -> bool { + fs::read(entry.path().join("CACHEDIR.TAG")) + .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) + .unwrap_or(false) + } + + // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. + // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory + // as a result of this filter. + let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); + if dest_crate_root.exists() { + println!("Deleting existing directory at {dest_crate_root:?}"); + fs::remove_dir_all(&dest_crate_root).unwrap(); + } + + println!("Copying {path:?} to {dest_crate_root:?}"); + + for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { + let entry = entry.unwrap(); + let entry_path = entry.path(); + let relative_entry_path = entry_path.strip_prefix(path).unwrap(); + let dest_path = dest_crate_root.join(relative_entry_path); + let metadata = entry_path.symlink_metadata().unwrap(); + + if metadata.is_dir() { + fs::create_dir(dest_path).unwrap(); + } else if metadata.is_file() { + fs::copy(entry_path, dest_path).unwrap(); + } + } + + Crate { + version: String::from("local"), + name: name.clone(), + path: dest_crate_root, + options: options.clone(), + } + }, + } + } +} + +/// Create necessary directories to run the lintcheck tool. +/// +/// # Panics +/// +/// This function panics if creating one of the dirs fails. +fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { + fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create lintcheck target dir" + ); + }); + fs::create_dir(krate_download_dir).unwrap_or_else(|err| { + assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); + }); + fs::create_dir(extract_dir).unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create crate extraction dir" + ); + }); +} diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 26a67beb4427..e37ffab13ac8 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -13,84 +13,38 @@ unused_lifetimes, unused_qualifications )] -#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)] +#![allow( + clippy::collapsible_else_if, + clippy::needless_borrows_for_generic_args, + clippy::module_name_repetitions +)] mod config; mod driver; +mod input; mod json; +mod output; mod popular_crates; mod recursive; use crate::config::{Commands, LintcheckConfig, OutputFormat}; use crate::recursive::LintcheckServer; -use std::collections::{HashMap, HashSet}; use std::env::consts::EXE_SUFFIX; -use std::fmt::{self, Display, Write as _}; -use std::hash::Hash; -use std::io::{self, ErrorKind}; +use std::io::{self}; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus, Stdio}; +use std::process::{Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::time::Duration; -use std::{env, fs, thread}; +use std::{env, fs}; -use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; +use input::{read_crates, CrateSource}; +use output::{ClippyCheckOutput, ClippyWarning, RustcIce}; use rayon::prelude::*; -use serde::Deserialize; -use walkdir::{DirEntry, WalkDir}; const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; -/// List of sources to check, loaded from a .toml file -#[derive(Debug, Deserialize)] -struct SourceList { - crates: HashMap, - #[serde(default)] - recursive: RecursiveOptions, -} - -#[derive(Debug, Deserialize, Default)] -struct RecursiveOptions { - ignore: HashSet, -} - -/// A crate source stored inside the .toml -/// will be translated into on one of the `CrateSource` variants -#[derive(Debug, Deserialize)] -struct TomlCrate { - name: String, - versions: Option>, - git_url: Option, - git_hash: Option, - path: Option, - options: Option>, -} - -/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder -/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` -#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] -enum CrateSource { - CratesIo { - name: String, - version: String, - options: Option>, - }, - Git { - name: String, - url: String, - commit: String, - options: Option>, - }, - Path { - name: String, - path: PathBuf, - options: Option>, - }, -} - /// Represents the actual source code of a crate that we ran "cargo clippy" on #[derive(Debug)] struct Crate { @@ -101,241 +55,6 @@ struct Crate { options: Option>, } -/// A single emitted output from clippy being executed on a crate. It may either be a -/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many -/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). -#[derive(Debug)] -enum ClippyCheckOutput { - ClippyWarning(ClippyWarning), - RustcIce(RustcIce), -} - -#[derive(Debug)] -struct RustcIce { - pub crate_name: String, - pub ice_content: String, -} - -impl Display for RustcIce { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}:\n{}\n========================================\n", - self.crate_name, self.ice_content - ) - } -} - -impl RustcIce { - pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { - if status.code().unwrap_or(0) == 101 - /* ice exit status */ - { - Some(Self { - crate_name: crate_name.to_owned(), - ice_content: stderr.to_owned(), - }) - } else { - None - } - } -} - -/// A single warning that clippy issued while checking a `Crate` -#[derive(Debug)] -struct ClippyWarning { - lint: String, - diag: Diagnostic, -} - -#[allow(unused)] -impl ClippyWarning { - fn new(mut diag: Diagnostic) -> Option { - let lint = diag.code.clone()?.code; - if !(lint.contains("clippy") || diag.message.contains("clippy")) - || diag.message.contains("could not read cargo metadata") - { - return None; - } - - // --recursive bypasses cargo so we have to strip the rendered output ourselves - let rendered = diag.rendered.as_mut().unwrap(); - *rendered = strip_ansi_escapes::strip_str(&rendered); - - Some(Self { lint, diag }) - } - - fn span(&self) -> &DiagnosticSpan { - self.diag.spans.iter().find(|span| span.is_primary).unwrap() - } - - fn to_output(&self, format: OutputFormat) -> String { - let span = self.span(); - let mut file = span.file_name.clone(); - let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); - match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), - OutputFormat::Markdown => { - if file.starts_with("target") { - file.insert_str(0, "../"); - } - - let mut output = String::from("| "); - write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); - output.push('\n'); - output - }, - OutputFormat::Json => unreachable!("JSON output is handled via serde"), - } - } -} - -#[allow(clippy::result_large_err)] -fn get(path: &str) -> Result { - const MAX_RETRIES: u8 = 4; - let mut retries = 0; - loop { - match ureq::get(path).call() { - Ok(res) => return Ok(res), - Err(e) if retries >= MAX_RETRIES => return Err(e), - Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), - Err(e) => return Err(e), - } - eprintln!("retrying in {retries} seconds..."); - thread::sleep(Duration::from_secs(u64::from(retries))); - retries += 1; - } -} - -impl CrateSource { - /// Makes the sources available on the disk for clippy to check. - /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or - /// copies a local folder - fn download_and_extract(&self) -> Crate { - match self { - CrateSource::CratesIo { name, version, options } => { - let extract_dir = PathBuf::from(LINTCHECK_SOURCES); - let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); - - // url to download the crate from crates.io - let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); - println!("Downloading and extracting {name} {version} from {url}"); - create_dirs(&krate_download_dir, &extract_dir); - - let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); - // don't download/extract if we already have done so - if !krate_file_path.is_file() { - // create a file path to download and write the crate data into - let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); - let mut krate_req = get(&url).unwrap().into_reader(); - // copy the crate into the file - io::copy(&mut krate_req, &mut krate_dest).unwrap(); - - // unzip the tarball - let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); - // extract the tar archive - let mut archive = tar::Archive::new(ungz_tar); - archive.unpack(&extract_dir).expect("Failed to extract!"); - } - // crate is extracted, return a new Krate object which contains the path to the extracted - // sources that clippy can check - Crate { - version: version.clone(), - name: name.clone(), - path: extract_dir.join(format!("{name}-{version}/")), - options: options.clone(), - } - }, - CrateSource::Git { - name, - url, - commit, - options, - } => { - let repo_path = { - let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); - // add a -git suffix in case we have the same crate from crates.io and a git repo - repo_path.push(format!("{name}-git")); - repo_path - }; - // clone the repo if we have not done so - if !repo_path.is_dir() { - println!("Cloning {url} and checking out {commit}"); - if !Command::new("git") - .arg("clone") - .arg(url) - .arg(&repo_path) - .status() - .expect("Failed to clone git repo!") - .success() - { - eprintln!("Failed to clone {url} into {}", repo_path.display()); - } - } - // check out the commit/branch/whatever - if !Command::new("git") - .args(["-c", "advice.detachedHead=false"]) - .arg("checkout") - .arg(commit) - .current_dir(&repo_path) - .status() - .expect("Failed to check out commit") - .success() - { - eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); - } - - Crate { - version: commit.clone(), - name: name.clone(), - path: repo_path, - options: options.clone(), - } - }, - CrateSource::Path { name, path, options } => { - fn is_cache_dir(entry: &DirEntry) -> bool { - fs::read(entry.path().join("CACHEDIR.TAG")) - .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) - .unwrap_or(false) - } - - // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. - // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory - // as a result of this filter. - let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); - if dest_crate_root.exists() { - println!("Deleting existing directory at {dest_crate_root:?}"); - fs::remove_dir_all(&dest_crate_root).unwrap(); - } - - println!("Copying {path:?} to {dest_crate_root:?}"); - - for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { - let entry = entry.unwrap(); - let entry_path = entry.path(); - let relative_entry_path = entry_path.strip_prefix(path).unwrap(); - let dest_path = dest_crate_root.join(relative_entry_path); - let metadata = entry_path.symlink_metadata().unwrap(); - - if metadata.is_dir() { - fs::create_dir(dest_path).unwrap(); - } else if metadata.is_file() { - fs::copy(entry_path, dest_path).unwrap(); - } - } - - Crate { - version: String::from("local"), - name: name.clone(), - path: dest_crate_root, - options: options.clone(), - } - }, - } - } -} - impl Crate { /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy /// issued @@ -496,96 +215,6 @@ fn build_clippy() -> String { String::from_utf8_lossy(&output.stdout).into_owned() } -/// Read a `lintcheck_crates.toml` file -fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { - let toml_content: String = - fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); - let crate_list: SourceList = - toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); - // parse the hashmap of the toml file into a list of crates - let tomlcrates: Vec = crate_list.crates.into_values().collect(); - - // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => - // multiple Cratesources) - let mut crate_sources = Vec::new(); - for tk in tomlcrates { - if let Some(ref path) = tk.path { - crate_sources.push(CrateSource::Path { - name: tk.name.clone(), - path: PathBuf::from(path), - options: tk.options.clone(), - }); - } else if let Some(ref versions) = tk.versions { - // if we have multiple versions, save each one - for ver in versions { - crate_sources.push(CrateSource::CratesIo { - name: tk.name.clone(), - version: ver.to_string(), - options: tk.options.clone(), - }); - } - } else if tk.git_url.is_some() && tk.git_hash.is_some() { - // otherwise, we should have a git source - crate_sources.push(CrateSource::Git { - name: tk.name.clone(), - url: tk.git_url.clone().unwrap(), - commit: tk.git_hash.clone().unwrap(), - options: tk.options.clone(), - }); - } else { - panic!("Invalid crate source: {tk:?}"); - } - - // if we have a version as well as a git data OR only one git data, something is funky - if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) - || tk.git_hash.is_some() != tk.git_url.is_some() - { - eprintln!("tomlkrate: {tk:?}"); - assert_eq!( - tk.git_hash.is_some(), - tk.git_url.is_some(), - "Error: Encountered TomlCrate with only one of git_hash and git_url!" - ); - assert!( - tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()), - "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" - ); - unreachable!("Failed to translate TomlCrate into CrateSource!"); - } - } - // sort the crates - crate_sources.sort(); - - (crate_sources, crate_list.recursive) -} - -/// Generate a short list of occurring lints-types and their count -fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { - // count lint type occurrences - let mut counter: HashMap<&String, usize> = HashMap::new(); - warnings - .iter() - .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); - - // collect into a tupled list for sorting - let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); - // sort by "000{count} {clippy::lintname}" - // to not have a lint with 200 and 2 warnings take the same spot - stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); - - let mut header = String::from("| lint | count |\n"); - header.push_str("| -------------------------------------------------- | ----- |\n"); - let stats_string = stats - .iter() - .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) - .fold(header, |mut table, line| { - table.push_str(&line); - table - }); - - (stats_string, counter) -} - fn main() { // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` if let Ok(addr) = env::var("LINTCHECK_SERVER") { @@ -738,7 +367,9 @@ fn lintcheck(config: LintcheckConfig) { } let text = match config.format { - OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config), + OutputFormat::Text | OutputFormat::Markdown => { + output::summarize_and_print_changes(&warnings, &raw_ices, clippy_ver, &config) + }, OutputFormat::Json => { if !raw_ices.is_empty() { for ice in raw_ices { @@ -756,135 +387,6 @@ fn lintcheck(config: LintcheckConfig) { fs::write(&config.lintcheck_results_path, text).unwrap(); } -/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] -fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String { - // generate some stats - let (stats_formatted, new_stats) = gather_stats(warnings); - let old_stats = read_stats_from_file(&config.lintcheck_results_path); - - let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); - all_msgs.sort(); - all_msgs.push("\n\n### Stats:\n\n".into()); - all_msgs.push(stats_formatted); - - let mut text = clippy_ver; // clippy version number on top - text.push_str("\n### Reports\n\n"); - if config.format == OutputFormat::Markdown { - text.push_str("| file | lint | message |\n"); - text.push_str("| --- | --- | --- |\n"); - } - write!(text, "{}", all_msgs.join("")).unwrap(); - text.push_str("\n\n### ICEs:\n"); - for ice in ices { - writeln!(text, "{ice}").unwrap(); - } - - print_stats(old_stats, new_stats, &config.lint_filter); - - text -} - -/// read the previous stats from the lintcheck-log file -fn read_stats_from_file(file_path: &Path) -> HashMap { - let file_content: String = match fs::read_to_string(file_path).ok() { - Some(content) => content, - None => { - return HashMap::new(); - }, - }; - - let lines: Vec = file_content.lines().map(ToString::to_string).collect(); - - lines - .iter() - .skip_while(|line| line.as_str() != "### Stats:") - // Skipping the table header and the `Stats:` label - .skip(4) - .take_while(|line| line.starts_with("| ")) - .filter_map(|line| { - let mut spl = line.split('|'); - // Skip the first `|` symbol - spl.next(); - if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { - Some((lint.trim().to_string(), count.trim().parse::().unwrap())) - } else { - None - } - }) - .collect::>() -} - -/// print how lint counts changed between runs -fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { - let same_in_both_hashmaps = old_stats - .iter() - .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) - .map(|(k, v)| (k.to_string(), *v)) - .collect::>(); - - let mut old_stats_deduped = old_stats; - let mut new_stats_deduped = new_stats; - - // remove duplicates from both hashmaps - for (k, v) in &same_in_both_hashmaps { - assert!(old_stats_deduped.remove(k) == Some(*v)); - assert!(new_stats_deduped.remove(k) == Some(*v)); - } - - println!("\nStats:"); - - // list all new counts (key is in new stats but not in old stats) - new_stats_deduped - .iter() - .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_value)| { - println!("{new_key} 0 => {new_value}"); - }); - - // list all changed counts (key is in both maps but value differs) - new_stats_deduped - .iter() - .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_val)| { - let old_val = old_stats_deduped.get::(new_key).unwrap(); - println!("{new_key} {old_val} => {new_val}"); - }); - - // list all gone counts (key is in old status but not in new stats) - old_stats_deduped - .iter() - .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) - .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) - .for_each(|(old_key, old_value)| { - println!("{old_key} {old_value} => 0"); - }); -} - -/// Create necessary directories to run the lintcheck tool. -/// -/// # Panics -/// -/// This function panics if creating one of the dirs fails. -fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { - fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create lintcheck target dir" - ); - }); - fs::create_dir(krate_download_dir).unwrap_or_else(|err| { - assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); - }); - fs::create_dir(extract_dir).unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create crate extraction dir" - ); - }); -} - /// Returns the path to the Clippy project directory #[must_use] fn clippy_project_root() -> &'static Path { diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs new file mode 100644 index 000000000000..4bfc554ef9e6 --- /dev/null +++ b/lintcheck/src/output.rs @@ -0,0 +1,235 @@ +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt::{self, Write as _}; +use std::fs; +use std::path::Path; +use std::process::ExitStatus; + +use crate::config::{LintcheckConfig, OutputFormat}; + +/// A single emitted output from clippy being executed on a crate. It may either be a +/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many +/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). +#[derive(Debug)] +pub enum ClippyCheckOutput { + ClippyWarning(ClippyWarning), + RustcIce(RustcIce), +} + +#[derive(Debug)] +pub struct RustcIce { + pub crate_name: String, + pub ice_content: String, +} + +impl fmt::Display for RustcIce { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}:\n{}\n========================================\n", + self.crate_name, self.ice_content + ) + } +} + +impl RustcIce { + pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { + if status.code().unwrap_or(0) == 101 + /* ice exit status */ + { + Some(Self { + crate_name: crate_name.to_owned(), + ice_content: stderr.to_owned(), + }) + } else { + None + } + } +} + +/// A single warning that clippy issued while checking a `Crate` +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ClippyWarning { + pub lint: String, + pub diag: Diagnostic, +} + +#[allow(unused)] +impl ClippyWarning { + pub fn new(mut diag: Diagnostic) -> Option { + let lint = diag.code.clone()?.code; + if !(lint.contains("clippy") || diag.message.contains("clippy")) + || diag.message.contains("could not read cargo metadata") + { + return None; + } + + // --recursive bypasses cargo so we have to strip the rendered output ourselves + let rendered = diag.rendered.as_mut().unwrap(); + *rendered = strip_ansi_escapes::strip_str(&rendered); + + Some(Self { lint, diag }) + } + + pub fn span(&self) -> &DiagnosticSpan { + self.diag.spans.iter().find(|span| span.is_primary).unwrap() + } + + pub fn to_output(&self, format: OutputFormat) -> String { + let span = self.span(); + let mut file = span.file_name.clone(); + let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); + match format { + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), + OutputFormat::Markdown => { + if file.starts_with("target") { + file.insert_str(0, "../"); + } + + let mut output = String::from("| "); + write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); + output.push('\n'); + output + }, + OutputFormat::Json => unreachable!("JSON output is handled via serde"), + } + } +} + +/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] +pub fn summarize_and_print_changes( + warnings: &[ClippyWarning], + ices: &[RustcIce], + clippy_ver: String, + config: &LintcheckConfig, +) -> String { + // generate some stats + let (stats_formatted, new_stats) = gather_stats(warnings); + let old_stats = read_stats_from_file(&config.lintcheck_results_path); + + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); + all_msgs.sort(); + all_msgs.push("\n\n### Stats:\n\n".into()); + all_msgs.push(stats_formatted); + + let mut text = clippy_ver; // clippy version number on top + text.push_str("\n### Reports\n\n"); + if config.format == OutputFormat::Markdown { + text.push_str("| file | lint | message |\n"); + text.push_str("| --- | --- | --- |\n"); + } + write!(text, "{}", all_msgs.join("")).unwrap(); + text.push_str("\n\n### ICEs:\n"); + for ice in ices { + writeln!(text, "{ice}").unwrap(); + } + + print_stats(old_stats, new_stats, &config.lint_filter); + + text +} + +/// Generate a short list of occurring lints-types and their count +fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { + // count lint type occurrences + let mut counter: HashMap<&String, usize> = HashMap::new(); + warnings + .iter() + .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); + + // collect into a tupled list for sorting + let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); + // sort by "000{count} {clippy::lintname}" + // to not have a lint with 200 and 2 warnings take the same spot + stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); + + let mut header = String::from("| lint | count |\n"); + header.push_str("| -------------------------------------------------- | ----- |\n"); + let stats_string = stats + .iter() + .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) + .fold(header, |mut table, line| { + table.push_str(&line); + table + }); + + (stats_string, counter) +} + +/// read the previous stats from the lintcheck-log file +fn read_stats_from_file(file_path: &Path) -> HashMap { + let file_content: String = match fs::read_to_string(file_path).ok() { + Some(content) => content, + None => { + return HashMap::new(); + }, + }; + + let lines: Vec = file_content.lines().map(ToString::to_string).collect(); + + lines + .iter() + .skip_while(|line| line.as_str() != "### Stats:") + // Skipping the table header and the `Stats:` label + .skip(4) + .take_while(|line| line.starts_with("| ")) + .filter_map(|line| { + let mut spl = line.split('|'); + // Skip the first `|` symbol + spl.next(); + if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { + Some((lint.trim().to_string(), count.trim().parse::().unwrap())) + } else { + None + } + }) + .collect::>() +} + +/// print how lint counts changed between runs +fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { + let same_in_both_hashmaps = old_stats + .iter() + .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) + .map(|(k, v)| (k.to_string(), *v)) + .collect::>(); + + let mut old_stats_deduped = old_stats; + let mut new_stats_deduped = new_stats; + + // remove duplicates from both hashmaps + for (k, v) in &same_in_both_hashmaps { + assert!(old_stats_deduped.remove(k) == Some(*v)); + assert!(new_stats_deduped.remove(k) == Some(*v)); + } + + println!("\nStats:"); + + // list all new counts (key is in new stats but not in old stats) + new_stats_deduped + .iter() + .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_value)| { + println!("{new_key} 0 => {new_value}"); + }); + + // list all changed counts (key is in both maps but value differs) + new_stats_deduped + .iter() + .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_val)| { + let old_val = old_stats_deduped.get::(new_key).unwrap(); + println!("{new_key} {old_val} => {new_val}"); + }); + + // list all gone counts (key is in old status but not in new stats) + old_stats_deduped + .iter() + .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) + .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) + .for_each(|(old_key, old_value)| { + println!("{old_key} {old_value} => 0"); + }); +} diff --git a/lintcheck/src/popular_crates.rs b/lintcheck/src/popular_crates.rs index 880a8bd81f08..ad8fc440c424 100644 --- a/lintcheck/src/popular_crates.rs +++ b/lintcheck/src/popular_crates.rs @@ -44,7 +44,7 @@ pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box let mut out = "[crates]\n".to_string(); for Crate { name, max_version } in crates { - writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap(); + writeln!(out, "{name} = {{ name = '{name}', version = '{max_version}' }}").unwrap(); } fs::write(output, out)?; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 24dddfe65636..373ca6f99184 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -3,7 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::{ClippyWarning, RecursiveOptions}; +use crate::input::RecursiveOptions; +use crate::ClippyWarning; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; From a3ef94e80e0ec7bacd42a70bd8a2203c5cc3fab8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Jul 2024 17:35:51 -0300 Subject: [PATCH 189/361] Fire unsafe_code lint on unsafe extern blocks --- compiler/rustc_lint/messages.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 6 ++++++ compiler/rustc_lint/src/lints.rs | 2 ++ .../ui/lint/unsafe_code/unsafe-extern-blocks.rs | 14 ++++++++++++++ .../unsafe_code/unsafe-extern-blocks.stderr | 17 +++++++++++++++++ 5 files changed, 41 insertions(+) create mode 100644 tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs create mode 100644 tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 3e952558d29d..9d429d5131ec 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -163,6 +163,8 @@ lint_builtin_unreachable_pub = unreachable `pub` {$what} lint_builtin_unsafe_block = usage of an `unsafe` block +lint_builtin_unsafe_extern_block = usage of an `unsafe extern` block + lint_builtin_unsafe_impl = implementation of an `unsafe` trait lint_builtin_unsafe_trait = declaration of an `unsafe` trait diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 79c8046f9b74..2d596564d52c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -326,6 +326,12 @@ impl EarlyLintPass for UnsafeCode { self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm); } + ast::ItemKind::ForeignMod(ForeignMod { safety, .. }) => { + if let Safety::Unsafe(_) = safety { + self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeExternBlock); + } + } + _ => {} } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7c5640f5959a..eacc66b197aa 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -81,6 +81,8 @@ pub enum BuiltinUnsafe { AllowInternalUnsafe, #[diag(lint_builtin_unsafe_block)] UnsafeBlock, + #[diag(lint_builtin_unsafe_extern_block)] + UnsafeExternBlock, #[diag(lint_builtin_unsafe_trait)] UnsafeTrait, #[diag(lint_builtin_unsafe_impl)] diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs new file mode 100644 index 000000000000..6f2ead70db80 --- /dev/null +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs @@ -0,0 +1,14 @@ +#![feature(unsafe_extern_blocks)] +#![deny(unsafe_code)] + +#[allow(unsafe_code)] +unsafe extern "C" { + fn foo(); +} + +unsafe extern "C" { + //~^ ERROR usage of an `unsafe extern` block [unsafe_code] + fn bar(); +} + +fn main() {} diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr new file mode 100644 index 000000000000..5439a3112560 --- /dev/null +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr @@ -0,0 +1,17 @@ +error: usage of an `unsafe extern` block + --> $DIR/unsafe-extern-blocks.rs:9:1 + | +LL | / unsafe extern "C" { +LL | | +LL | | fn bar(); +LL | | } + | |_^ + | +note: the lint level is defined here + --> $DIR/unsafe-extern-blocks.rs:2:9 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 5bf50e66f9a7b1de3e074c276afc2e048afe65d1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 12:12:34 +0200 Subject: [PATCH 190/361] Move a function --- .../rustc_mir_build/src/build/matches/mod.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5695c881ecc2..cc46a5603c3d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1624,6 +1624,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block } + /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new + /// subcandidate. Any candidate that has been expanded that way should be passed to + /// `finalize_or_candidate` after its subcandidates have been processed. + fn create_or_subcandidates<'pat>( + &mut self, + candidate: &mut Candidate<'pat, 'tcx>, + match_pair: MatchPair<'pat, 'tcx>, + ) { + let TestCase::Or { pats } = match_pair.test_case else { bug!() }; + debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); + candidate.or_span = Some(match_pair.pattern.span); + candidate.subcandidates = pats + .into_vec() + .into_iter() + .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) + .collect(); + candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; + } + /// Simplify subcandidates and process any leftover match pairs. The candidate should have been /// expanded with `create_or_subcandidates`. /// @@ -1724,25 +1743,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new - /// subcandidate. Any candidate that has been expanded that way should be passed to - /// `finalize_or_candidate` after its subcandidates have been processed. - fn create_or_subcandidates<'pat>( - &mut self, - candidate: &mut Candidate<'pat, 'tcx>, - match_pair: MatchPair<'pat, 'tcx>, - ) { - let TestCase::Or { pats } = match_pair.test_case else { bug!() }; - debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); - candidate.or_span = Some(match_pair.pattern.span); - candidate.subcandidates = pats - .into_vec() - .into_iter() - .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) - .collect(); - candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; - } - /// Try to merge all of the subcandidates of the given candidate into one. This avoids /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been /// expanded with `create_or_subcandidates`. From bff4d213fac5ba32b51d320800700124205f6565 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 12:18:31 +0200 Subject: [PATCH 191/361] Factor out the special handling of or-patterns --- .../rustc_mir_build/src/build/matches/mod.rs | 185 ++++++++++-------- 1 file changed, 104 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cc46a5603c3d..47f4fd0d07b5 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1427,108 +1427,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller /// code size at the expense of non-optimal code paths. #[instrument(skip(self), level = "debug")] - fn match_candidates<'pat>( + fn match_candidates( &mut self, span: Span, scrutinee_span: Span, start_block: BasicBlock, otherwise_block: BasicBlock, - candidates: &mut [&mut Candidate<'pat, 'tcx>], + candidates: &mut [&mut Candidate<'_, 'tcx>], ) { - // We process or-patterns here. If any candidate starts with an or-pattern, we have to - // expand the or-pattern before we can proceed further. - // - // We can't expand them freely however. The rule is: if the candidate has an or-pattern as - // its only remaining match pair, we can expand it freely. If it has other match pairs, we - // can expand it but we can't process more candidates after it. - // - // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following, - // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2` - // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same - // set of candidates, when we reach the block that tests `false` we don't know whether we - // came from `1` or `2`, hence we can't know where to branch on failure. - // ```ignore(illustrative) - // match (1, true) { - // (1 | 2, false) => {}, - // (2, _) => {}, - // _ => {} - // } - // ``` - // - // We therefore split the `candidates` slice in two, expand or-patterns in the first half, - // and process both halves separately. - let mut expand_until = 0; - for (i, candidate) in candidates.iter().enumerate() { - if matches!( + // If any candidate starts with an or-pattern, we have to expand the or-pattern before we + // can proceed further. + let expand_ors = candidates.iter().any(|candidate| { + matches!( &*candidate.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] - ) { - expand_until = i + 1; - if candidate.match_pairs.len() > 1 { - break; - } - } - if expand_until != 0 { - expand_until = i + 1; - } - } - let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); - + ) + }); ensure_sufficient_stack(|| { - if candidates_to_expand.is_empty() { + if !expand_ors { // No candidates start with an or-pattern, we can continue. self.match_expanded_candidates( span, scrutinee_span, start_block, otherwise_block, - remaining_candidates, + candidates, ); } else { - // Expand one level of or-patterns for each candidate in `candidates_to_expand`. - let mut expanded_candidates = Vec::new(); - for candidate in candidates_to_expand.iter_mut() { - if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = - &*candidate.match_pairs - { - let or_match_pair = candidate.match_pairs.remove(0); - // Expand the or-pattern into subcandidates. - self.create_or_subcandidates(candidate, or_match_pair); - // Collect the newly created subcandidates. - for subcandidate in candidate.subcandidates.iter_mut() { - expanded_candidates.push(subcandidate); - } - } else { - expanded_candidates.push(candidate); - } - } - - // Process the expanded candidates. - let remainder_start = self.cfg.start_new_block(); - // There might be new or-patterns obtained from expanding the old ones, so we call - // `match_candidates` again. - self.match_candidates( + self.expand_and_match_or_candidates( span, scrutinee_span, start_block, - remainder_start, - expanded_candidates.as_mut_slice(), - ); - - // Simplify subcandidates and process any leftover match pairs. - for candidate in candidates_to_expand { - if !candidate.subcandidates.is_empty() { - self.finalize_or_candidate(span, scrutinee_span, candidate); - } - } - - // Process the remaining candidates. - self.match_candidates( - span, - scrutinee_span, - remainder_start, otherwise_block, - remaining_candidates, + candidates, ); } }); @@ -1624,6 +1555,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block } + /// Takes a list of candidates such that some of the candidates' first match pairs are + /// or-patterns, expands as many or-patterns as possible, and processes the resulting + /// candidates. + fn expand_and_match_or_candidates( + &mut self, + span: Span, + scrutinee_span: Span, + start_block: BasicBlock, + otherwise_block: BasicBlock, + candidates: &mut [&mut Candidate<'_, 'tcx>], + ) { + // We can't expand or-patterns freely. The rule is: if the candidate has an + // or-pattern as its only remaining match pair, we can expand it freely. If it has + // other match pairs, we can expand it but we can't process more candidates after + // it. + // + // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the + // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it + // so the `1` and `2` cases branch to a same block (which then tests `false`). If we + // took `(2, _)` in the same set of candidates, when we reach the block that tests + // `false` we don't know whether we came from `1` or `2`, hence we can't know where + // to branch on failure. + // + // ```ignore(illustrative) + // match (1, true) { + // (1 | 2, false) => {}, + // (2, _) => {}, + // _ => {} + // } + // ``` + // + // We therefore split the `candidates` slice in two, expand or-patterns in the first half, + // and process the rest separately. + let mut expand_until = 0; + for (i, candidate) in candidates.iter().enumerate() { + expand_until = i + 1; + if candidate.match_pairs.len() > 1 + && matches!(&candidate.match_pairs[0].test_case, TestCase::Or { .. }) + { + // The candidate has an or-pattern as well as more match pairs: we must + // split the candidates list here. + break; + } + } + let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); + + // Expand one level of or-patterns for each candidate in `candidates_to_expand`. + let mut expanded_candidates = Vec::new(); + for candidate in candidates_to_expand.iter_mut() { + if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = &*candidate.match_pairs + { + let or_match_pair = candidate.match_pairs.remove(0); + // Expand the or-pattern into subcandidates. + self.create_or_subcandidates(candidate, or_match_pair); + // Collect the newly created subcandidates. + for subcandidate in candidate.subcandidates.iter_mut() { + expanded_candidates.push(subcandidate); + } + } else { + expanded_candidates.push(candidate); + } + } + + // Process the expanded candidates. + let remainder_start = self.cfg.start_new_block(); + // There might be new or-patterns obtained from expanding the old ones, so we call + // `match_candidates` again. + self.match_candidates( + span, + scrutinee_span, + start_block, + remainder_start, + expanded_candidates.as_mut_slice(), + ); + + // Simplify subcandidates and process any leftover match pairs. + for candidate in candidates_to_expand { + if !candidate.subcandidates.is_empty() { + self.finalize_or_candidate(span, scrutinee_span, candidate); + } + } + + // Process the remaining candidates. + self.match_candidates( + span, + scrutinee_span, + remainder_start, + otherwise_block, + remaining_candidates, + ); + } + /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new /// subcandidate. Any candidate that has been expanded that way should be passed to /// `finalize_or_candidate` after its subcandidates have been processed. From c5062f73181778af278321827ceedf1682ee0a8b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 12:25:07 +0200 Subject: [PATCH 192/361] Move or-pattern expansion inside the main part of the algorithm --- .../rustc_mir_build/src/build/matches/mod.rs | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 47f4fd0d07b5..cc8a0e4b0382 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1119,6 +1119,11 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { } } + /// Returns whether the first match pair of this candidate is an or-pattern. + fn starts_with_or_pattern(&self) -> bool { + matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..]) + } + /// Visit the leaf candidates (those with no subcandidates) contained in /// this candidate. fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) { @@ -1435,39 +1440,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], ) { - // If any candidate starts with an or-pattern, we have to expand the or-pattern before we - // can proceed further. - let expand_ors = candidates.iter().any(|candidate| { - matches!( - &*candidate.match_pairs, - [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] - ) - }); ensure_sufficient_stack(|| { - if !expand_ors { - // No candidates start with an or-pattern, we can continue. - self.match_expanded_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - candidates, - ); - } else { - self.expand_and_match_or_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - candidates, - ); - } + self.match_candidates_with_enough_stack( + span, + scrutinee_span, + start_block, + otherwise_block, + candidates, + ) }); } - /// Construct the decision tree for `candidates`. Caller must ensure that no candidate in - /// `candidates` starts with an or-pattern. - fn match_expanded_candidates( + /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates` + /// instead to reserve sufficient stack space. + fn match_candidates_with_enough_stack( &mut self, span: Span, scrutinee_span: Span, @@ -1492,12 +1478,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The first candidate has satisfied all its match pairs; we link it up and continue // with the remaining candidates. start_block = self.select_matched_candidate(first, start_block); - self.match_expanded_candidates( + self.match_candidates(span, scrutinee_span, start_block, otherwise_block, remaining) + } + candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => { + // If any candidate starts with an or-pattern, we have to expand the or-pattern before we + // can proceed further. + self.expand_and_match_or_candidates( span, scrutinee_span, start_block, otherwise_block, - remaining, + candidates, ) } candidates => { @@ -1591,9 +1582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut expand_until = 0; for (i, candidate) in candidates.iter().enumerate() { expand_until = i + 1; - if candidate.match_pairs.len() > 1 - && matches!(&candidate.match_pairs[0].test_case, TestCase::Or { .. }) - { + if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() { // The candidate has an or-pattern as well as more match pairs: we must // split the candidates list here. break; @@ -1604,8 +1593,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Expand one level of or-patterns for each candidate in `candidates_to_expand`. let mut expanded_candidates = Vec::new(); for candidate in candidates_to_expand.iter_mut() { - if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = &*candidate.match_pairs - { + if candidate.starts_with_or_pattern() { let or_match_pair = candidate.match_pairs.remove(0); // Expand the or-pattern into subcandidates. self.create_or_subcandidates(candidate, or_match_pair); From 8a222ffd6bb37a79bf517b3552008d9695cc8ae1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 12:29:46 +0200 Subject: [PATCH 193/361] Don't try to save an extra block This is preparation for the next commit. --- .../rustc_mir_build/src/build/matches/mod.rs | 22 ++- .../issue_101867.main.built.after.mir | 22 +-- .../building/issue_49232.main.built.after.mir | 34 +++-- ...n_conditional.test_complex.built.after.mir | 128 ++++++++++-------- ...se_edges.full_tested_match.built.after.mir | 56 ++++---- ...e_edges.full_tested_match2.built.after.mir | 60 ++++---- .../match_false_edges.main.built.after.mir | 36 ++--- .../simple_match.match_bool.built.after.mir | 12 +- .../simple_match.match_enum.built.after.mir | 26 ++-- ....constant_eq.SimplifyCfg-initial.after.mir | 72 +++++----- ...mment_2.DeduplicateBlocks.panic-abort.diff | 64 ++++----- ...ment_2.DeduplicateBlocks.panic-unwind.diff | 64 ++++----- ...fg-initial.after-ElaborateDrops.after.diff | 26 ++-- ...fg-initial.after-ElaborateDrops.after.diff | 26 ++-- ...ut_second_or.SimplifyCfg-initial.after.mir | 8 +- 15 files changed, 336 insertions(+), 320 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cc8a0e4b0382..458e2c5c4069 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2021,19 +2021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The block that we should branch to if none of the // `target_candidates` match. - let remainder_start = if !remaining_candidates.is_empty() { - let remainder_start = self.cfg.start_new_block(); - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); - remainder_start - } else { - otherwise_block - }; + let remainder_start = self.cfg.start_new_block(); // For each outcome of test, process the candidates that still apply. let target_blocks: FxIndexMap<_, _> = target_candidates @@ -2061,6 +2049,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &test, target_blocks, ); + + self.match_candidates( + span, + scrutinee_span, + remainder_start, + otherwise_block, + remaining_candidates, + ); } } diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 5c50b3db5cad..728b5b23c6a6 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -27,13 +27,13 @@ fn main() -> () { StorageLive(_5); PlaceMention(_1); _6 = discriminant(_1); - switchInt(move _6) -> [1: bb4, otherwise: bb3]; + switchInt(move _6) -> [1: bb5, otherwise: bb4]; } bb1: { StorageLive(_3); StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb8; + _4 = begin_panic::<&str>(const "explicit panic") -> bb9; } bb2: { @@ -43,18 +43,22 @@ fn main() -> () { } bb3: { - goto -> bb7; + goto -> bb8; } bb4: { - falseEdge -> [real: bb6, imaginary: bb3]; - } - - bb5: { goto -> bb3; } + bb5: { + falseEdge -> [real: bb7, imaginary: bb3]; + } + bb6: { + goto -> bb4; + } + + bb7: { _5 = ((_1 as Some).0: u8); _0 = const (); StorageDead(_5); @@ -62,12 +66,12 @@ fn main() -> () { return; } - bb7: { + bb8: { StorageDead(_5); goto -> bb1; } - bb8 (cleanup): { + bb9 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/issue_49232.main.built.after.mir b/tests/mir-opt/building/issue_49232.main.built.after.mir index d09a1748a8b3..ac7e530520a3 100644 --- a/tests/mir-opt/building/issue_49232.main.built.after.mir +++ b/tests/mir-opt/building/issue_49232.main.built.after.mir @@ -17,7 +17,7 @@ fn main() -> () { } bb1: { - falseUnwind -> [real: bb2, unwind: bb14]; + falseUnwind -> [real: bb2, unwind: bb15]; } bb2: { @@ -25,7 +25,7 @@ fn main() -> () { StorageLive(_3); _3 = const true; PlaceMention(_3); - switchInt(_3) -> [0: bb4, otherwise: bb6]; + switchInt(_3) -> [0: bb5, otherwise: bb7]; } bb3: { @@ -34,45 +34,49 @@ fn main() -> () { } bb4: { - falseEdge -> [real: bb8, imaginary: bb6]; + goto -> bb3; } bb5: { - goto -> bb3; + falseEdge -> [real: bb9, imaginary: bb7]; } bb6: { - _0 = const (); - goto -> bb13; + goto -> bb4; } bb7: { - goto -> bb3; + _0 = const (); + goto -> bb14; } bb8: { - _2 = const 4_i32; - goto -> bb11; + goto -> bb4; } bb9: { - unreachable; + _2 = const 4_i32; + goto -> bb12; } bb10: { - goto -> bb11; + unreachable; } bb11: { + goto -> bb12; + } + + bb12: { FakeRead(ForLet(None), _2); StorageDead(_3); StorageLive(_5); StorageLive(_6); _6 = &_2; - _5 = std::mem::drop::<&i32>(move _6) -> [return: bb12, unwind: bb14]; + _5 = std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb15]; } - bb12: { + bb13: { StorageDead(_6); StorageDead(_5); _1 = const (); @@ -80,13 +84,13 @@ fn main() -> () { goto -> bb1; } - bb13: { + bb14: { StorageDead(_3); StorageDead(_2); return; } - bb14 (cleanup): { + bb15 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir index 3e16efe6980d..395b8b82bff4 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir +++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir @@ -19,180 +19,188 @@ fn test_complex() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = E::f() -> [return: bb1, unwind: bb34]; + _2 = E::f() -> [return: bb1, unwind: bb36]; } bb1: { PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb3, otherwise: bb2]; + switchInt(move _3) -> [0: bb4, otherwise: bb3]; } bb2: { - goto -> bb21; + goto -> bb22; } bb3: { - falseEdge -> [real: bb5, imaginary: bb2]; - } - - bb4: { goto -> bb2; } + bb4: { + falseEdge -> [real: bb6, imaginary: bb2]; + } + bb5: { - StorageLive(_4); - _4 = always_true() -> [return: bb6, unwind: bb34]; + goto -> bb3; } bb6: { - switchInt(move _4) -> [0: bb8, otherwise: bb7]; + StorageLive(_4); + _4 = always_true() -> [return: bb7, unwind: bb36]; } bb7: { + switchInt(move _4) -> [0: bb9, otherwise: bb8]; + } + + bb8: { StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = Droppy(const 0_u8); _6 = (_7.0: u8); _5 = Gt(move _6, const 0_u8); - switchInt(move _5) -> [0: bb10, otherwise: bb9]; - } - - bb8: { - goto -> bb14; + switchInt(move _5) -> [0: bb11, otherwise: bb10]; } bb9: { - drop(_7) -> [return: bb11, unwind: bb34]; + goto -> bb15; } bb10: { - goto -> bb12; + drop(_7) -> [return: bb12, unwind: bb36]; } bb11: { - StorageDead(_7); - StorageDead(_6); - goto -> bb18; + goto -> bb13; } bb12: { - drop(_7) -> [return: bb13, unwind: bb34]; + StorageDead(_7); + StorageDead(_6); + goto -> bb19; } bb13: { - StorageDead(_7); - StorageDead(_6); - goto -> bb14; + drop(_7) -> [return: bb14, unwind: bb36]; } bb14: { + StorageDead(_7); + StorageDead(_6); + goto -> bb15; + } + + bb15: { StorageLive(_8); StorageLive(_9); StorageLive(_10); _10 = Droppy(const 1_u8); _9 = (_10.0: u8); _8 = Gt(move _9, const 1_u8); - switchInt(move _8) -> [0: bb16, otherwise: bb15]; - } - - bb15: { - drop(_10) -> [return: bb17, unwind: bb34]; + switchInt(move _8) -> [0: bb17, otherwise: bb16]; } bb16: { - goto -> bb19; + drop(_10) -> [return: bb18, unwind: bb36]; } bb17: { - StorageDead(_10); - StorageDead(_9); - goto -> bb18; + goto -> bb20; } bb18: { - _1 = const (); - goto -> bb22; + StorageDead(_10); + StorageDead(_9); + goto -> bb19; } bb19: { - drop(_10) -> [return: bb20, unwind: bb34]; + _1 = const (); + goto -> bb23; } bb20: { - StorageDead(_10); - StorageDead(_9); - goto -> bb21; + drop(_10) -> [return: bb21, unwind: bb36]; } bb21: { - _1 = const (); + StorageDead(_10); + StorageDead(_9); goto -> bb22; } bb22: { + _1 = const (); + goto -> bb23; + } + + bb23: { StorageDead(_8); StorageDead(_5); StorageDead(_4); StorageDead(_2); StorageDead(_1); StorageLive(_11); - _11 = always_true() -> [return: bb23, unwind: bb34]; - } - - bb23: { - switchInt(move _11) -> [0: bb25, otherwise: bb24]; + _11 = always_true() -> [return: bb24, unwind: bb36]; } bb24: { - goto -> bb32; + switchInt(move _11) -> [0: bb26, otherwise: bb25]; } bb25: { - goto -> bb26; + goto -> bb34; } bb26: { - StorageLive(_12); - _12 = E::f() -> [return: bb27, unwind: bb34]; + goto -> bb27; } bb27: { - PlaceMention(_12); - _13 = discriminant(_12); - switchInt(move _13) -> [1: bb29, otherwise: bb28]; + StorageLive(_12); + _12 = E::f() -> [return: bb28, unwind: bb36]; } bb28: { - goto -> bb32; + PlaceMention(_12); + _13 = discriminant(_12); + switchInt(move _13) -> [1: bb31, otherwise: bb30]; } bb29: { - falseEdge -> [real: bb31, imaginary: bb28]; + goto -> bb34; } bb30: { - goto -> bb28; + goto -> bb29; } bb31: { - _0 = const (); - goto -> bb33; + falseEdge -> [real: bb33, imaginary: bb29]; } bb32: { - _0 = const (); - goto -> bb33; + goto -> bb30; } bb33: { + _0 = const (); + goto -> bb35; + } + + bb34: { + _0 = const (); + goto -> bb35; + } + + bb35: { StorageDead(_11); StorageDead(_12); return; } - bb34 (cleanup): { + bb36 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir index bade0fa4b45c..623dd51c3584 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; + switchInt(move _4) -> [0: bb6, 1: bb3, otherwise: bb2]; } bb1: { @@ -37,39 +37,43 @@ fn full_tested_match() -> () { } bb2: { - falseEdge -> [real: bb7, imaginary: bb3]; + goto -> bb1; } bb3: { - falseEdge -> [real: bb12, imaginary: bb5]; + falseEdge -> [real: bb8, imaginary: bb4]; } bb4: { - goto -> bb1; + falseEdge -> [real: bb13, imaginary: bb6]; } bb5: { - _1 = (const 3_i32, const 3_i32); - goto -> bb13; + goto -> bb2; } bb6: { - goto -> bb1; + _1 = (const 3_i32, const 3_i32); + goto -> bb14; } bb7: { + goto -> bb2; + } + + bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb16]; - } - - bb8: { - switchInt(move _7) -> [0: bb10, otherwise: bb9]; + _7 = guard() -> [return: bb9, unwind: bb17]; } bb9: { + switchInt(move _7) -> [0: bb11, otherwise: bb10]; + } + + bb10: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -81,20 +85,20 @@ fn full_tested_match() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb13; - } - - bb10: { - goto -> bb11; + goto -> bb14; } bb11: { - StorageDead(_7); - StorageDead(_6); - goto -> bb3; + goto -> bb12; } bb12: { + StorageDead(_7); + StorageDead(_6); + goto -> bb4; + } + + bb13: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -102,10 +106,10 @@ fn full_tested_match() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb13; + goto -> bb14; } - bb13: { + bb14: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -113,16 +117,16 @@ fn full_tested_match() -> () { return; } - bb14: { + bb15: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb15: { - goto -> bb14; + bb16: { + goto -> bb15; } - bb16 (cleanup): { + bb17 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir index 0d78bb8b2358..3cb037bf9560 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match2() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; + switchInt(move _4) -> [0: bb6, 1: bb3, otherwise: bb2]; } bb1: { @@ -37,10 +37,14 @@ fn full_tested_match2() -> () { } bb2: { - falseEdge -> [real: bb7, imaginary: bb5]; + goto -> bb1; } bb3: { + falseEdge -> [real: bb8, imaginary: bb6]; + } + + bb4: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -48,34 +52,34 @@ fn full_tested_match2() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb13; - } - - bb4: { - goto -> bb1; + goto -> bb14; } bb5: { - falseEdge -> [real: bb12, imaginary: bb3]; + goto -> bb2; } bb6: { - goto -> bb1; + falseEdge -> [real: bb13, imaginary: bb4]; } bb7: { + goto -> bb2; + } + + bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb16]; - } - - bb8: { - switchInt(move _7) -> [0: bb10, otherwise: bb9]; + _7 = guard() -> [return: bb9, unwind: bb17]; } bb9: { + switchInt(move _7) -> [0: bb11, otherwise: bb10]; + } + + bb10: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -87,25 +91,25 @@ fn full_tested_match2() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb13; - } - - bb10: { - goto -> bb11; + goto -> bb14; } bb11: { - StorageDead(_7); - StorageDead(_6); - falseEdge -> [real: bb3, imaginary: bb5]; + goto -> bb12; } bb12: { - _1 = (const 3_i32, const 3_i32); - goto -> bb13; + StorageDead(_7); + StorageDead(_6); + falseEdge -> [real: bb4, imaginary: bb6]; } bb13: { + _1 = (const 3_i32, const 3_i32); + goto -> bb14; + } + + bb14: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -113,16 +117,16 @@ fn full_tested_match2() -> () { return; } - bb14: { + bb15: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb15: { - goto -> bb14; + bb16: { + goto -> bb15; } - bb16 (cleanup): { + bb17 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index ebb75ae141a3..134517ad2aec 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -38,8 +38,8 @@ fn main() -> () { StorageLive(_2); _2 = Option::::Some(const 1_i32); PlaceMention(_2); - _5 = discriminant(_2); - switchInt(move _5) -> [1: bb8, otherwise: bb2]; + _4 = discriminant(_2); + switchInt(move _4) -> [1: bb3, otherwise: bb2]; } bb1: { @@ -48,15 +48,23 @@ fn main() -> () { } bb2: { - falseEdge -> [real: bb15, imaginary: bb3]; + falseEdge -> [real: bb15, imaginary: bb5]; } bb3: { - _4 = discriminant(_2); - switchInt(move _4) -> [1: bb6, otherwise: bb4]; + falseEdge -> [real: bb10, imaginary: bb2]; } bb4: { + goto -> bb2; + } + + bb5: { + _5 = discriminant(_2); + switchInt(move _5) -> [1: bb7, otherwise: bb6]; + } + + bb6: { StorageLive(_14); _14 = _2; _1 = const 4_i32; @@ -64,24 +72,16 @@ fn main() -> () { goto -> bb21; } - bb5: { - goto -> bb1; - } - - bb6: { - falseEdge -> [real: bb16, imaginary: bb4]; - } - bb7: { - goto -> bb4; + falseEdge -> [real: bb16, imaginary: bb6]; } bb8: { - falseEdge -> [real: bb10, imaginary: bb2]; + goto -> bb6; } bb9: { - goto -> bb2; + goto -> bb1; } bb10: { @@ -115,7 +115,7 @@ fn main() -> () { bb14: { StorageDead(_8); StorageDead(_7); - falseEdge -> [real: bb9, imaginary: bb2]; + falseEdge -> [real: bb4, imaginary: bb2]; } bb15: { @@ -161,7 +161,7 @@ fn main() -> () { StorageDead(_13); StorageDead(_12); StorageDead(_11); - falseEdge -> [real: bb7, imaginary: bb4]; + falseEdge -> [real: bb8, imaginary: bb6]; } bb21: { diff --git a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir index faa2456fd100..81b5ce304d0e 100644 --- a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir @@ -6,7 +6,7 @@ fn match_bool(_1: bool) -> usize { bb0: { PlaceMention(_1); - switchInt(_1) -> [0: bb2, otherwise: bb4]; + switchInt(_1) -> [0: bb2, otherwise: bb3]; } bb1: { @@ -20,17 +20,17 @@ fn match_bool(_1: bool) -> usize { } bb3: { - goto -> bb1; - } - - bb4: { falseEdge -> [real: bb6, imaginary: bb2]; } - bb5: { + bb4: { goto -> bb2; } + bb5: { + goto -> bb1; + } + bb6: { _0 = const 10_usize; goto -> bb7; diff --git a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir index 905aa19da706..c2ea5bd441c3 100644 --- a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir @@ -8,7 +8,7 @@ fn match_enum(_1: E1) -> bool { bb0: { PlaceMention(_1); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb5, 2: bb7, otherwise: bb2]; + switchInt(move _2) -> [0: bb4, 1: bb6, 2: bb8, otherwise: bb3]; } bb1: { @@ -21,40 +21,44 @@ fn match_enum(_1: E1) -> bool { } bb3: { - goto -> bb9; + goto -> bb2; } bb4: { - goto -> bb2; + goto -> bb10; } bb5: { - goto -> bb9; + goto -> bb3; } bb6: { - goto -> bb2; + goto -> bb10; } bb7: { - _0 = const false; - goto -> bb11; + goto -> bb3; } bb8: { - goto -> bb2; + _0 = const false; + goto -> bb12; } bb9: { - falseEdge -> [real: bb10, imaginary: bb7]; + goto -> bb3; } bb10: { - _0 = const true; - goto -> bb11; + falseEdge -> [real: bb11, imaginary: bb8]; } bb11: { + _0 = const true; + goto -> bb12; + } + + bb12: { return; } } diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index 060cd6132e3a..2b5dbacc2d92 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -23,52 +23,52 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { StorageDead(_5); StorageDead(_4); PlaceMention(_3); - _9 = ::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19]; + _9 = ::eq((_3.0: &str), const "a") -> [return: bb9, unwind: bb19]; } bb1: { - switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3]; + switchInt((_3.1: bool)) -> [0: bb10, otherwise: bb11]; } bb2: { + falseEdge -> [real: bb12, imaginary: bb5]; + } + + bb3: { + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb4]; + } + + bb4: { + falseEdge -> [real: bb16, imaginary: bb1]; + } + + bb5: { + _8 = ::eq((_3.0: &str), const "b") -> [return: bb8, unwind: bb19]; + } + + bb6: { + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb7]; + } + + bb7: { + falseEdge -> [real: bb15, imaginary: bb3]; + } + + bb8: { + switchInt(move _8) -> [0: bb1, otherwise: bb6]; + } + + bb9: { + switchInt(move _9) -> [0: bb5, otherwise: bb2]; + } + + bb10: { _0 = const 5_u32; goto -> bb18; } - bb3: { - falseEdge -> [real: bb17, imaginary: bb2]; - } - - bb4: { - falseEdge -> [real: bb12, imaginary: bb7]; - } - - bb5: { - switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6]; - } - - bb6: { - falseEdge -> [real: bb16, imaginary: bb1]; - } - - bb7: { - _8 = ::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19]; - } - - bb8: { - switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9]; - } - - bb9: { - falseEdge -> [real: bb15, imaginary: bb5]; - } - - bb10: { - switchInt(move _8) -> [0: bb1, otherwise: bb8]; - } - bb11: { - switchInt(move _9) -> [0: bb7, otherwise: bb4]; + falseEdge -> [real: bb17, imaginary: bb10]; } bb12: { @@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { bb14: { StorageDead(_10); - falseEdge -> [real: bb5, imaginary: bb7]; + falseEdge -> [real: bb3, imaginary: bb5]; } bb15: { diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff index 938b9bb14ade..3a5762e4f3d1 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff @@ -22,59 +22,55 @@ bb1: { StorageDead(_3); - _7 = Len((*_2)); - _8 = const 4_usize; - _9 = Ge(move _7, move _8); -- switchInt(move _9) -> [0: bb2, otherwise: bb7]; -+ switchInt(move _9) -> [0: bb2, otherwise: bb6]; + _4 = Len((*_2)); + _5 = const 4_usize; + _6 = Ge(move _4, move _5); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _4 = Len((*_2)); - _5 = const 3_usize; - _6 = Ge(move _4, move _5); -- switchInt(move _6) -> [0: bb3, otherwise: bb4]; -+ switchInt(move _6) -> [0: bb10, otherwise: bb3]; + _7 = Len((*_2)); + _8 = const 3_usize; + _9 = Ge(move _7, move _8); +- switchInt(move _9) -> [0: bb7, otherwise: bb8]; ++ switchInt(move _9) -> [0: bb10, otherwise: bb7]; } bb3: { -- _0 = const false; -- goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10]; + switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2]; } bb4: { -- switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3]; -+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10]; + switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2]; } bb5: { -- switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2]; } bb6: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3]; -+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2]; - } - - bb7: { -- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2]; -+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2]; - } - - bb8: { -- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2]; -+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2]; - } - - bb9: { -- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; + switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; } + bb7: { +- _0 = const false; +- goto -> bb14; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; + } + + bb8: { +- switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; + } + + bb9: { +- switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; ++ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + } + bb10: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; - } - - bb11: { diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff index ce89694076b0..21b197d2f270 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff @@ -22,59 +22,55 @@ bb1: { StorageDead(_3); - _7 = Len((*_2)); - _8 = const 4_usize; - _9 = Ge(move _7, move _8); -- switchInt(move _9) -> [0: bb2, otherwise: bb7]; -+ switchInt(move _9) -> [0: bb2, otherwise: bb6]; + _4 = Len((*_2)); + _5 = const 4_usize; + _6 = Ge(move _4, move _5); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _4 = Len((*_2)); - _5 = const 3_usize; - _6 = Ge(move _4, move _5); -- switchInt(move _6) -> [0: bb3, otherwise: bb4]; -+ switchInt(move _6) -> [0: bb10, otherwise: bb3]; + _7 = Len((*_2)); + _8 = const 3_usize; + _9 = Ge(move _7, move _8); +- switchInt(move _9) -> [0: bb7, otherwise: bb8]; ++ switchInt(move _9) -> [0: bb10, otherwise: bb7]; } bb3: { -- _0 = const false; -- goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10]; + switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2]; } bb4: { -- switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3]; -+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10]; + switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2]; } bb5: { -- switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2]; } bb6: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3]; -+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2]; - } - - bb7: { -- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2]; -+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2]; - } - - bb8: { -- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2]; -+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2]; - } - - bb9: { -- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; + switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; } + bb7: { +- _0 = const false; +- goto -> bb14; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; + } + + bb8: { +- switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; + } + + bb9: { +- switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; ++ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + } + bb10: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; - } - - bb11: { diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 209f0d09c294..4f29e5244d7c 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -32,25 +32,33 @@ bb0: { PlaceMention(_2); -- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; +- switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } bb1: { -- switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; +- switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- falseEdge -> [real: bb8, imaginary: bb1]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; +- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5]; - } - - bb4: { +- falseEdge -> [real: bb13, imaginary: bb3]; +- } +- +- bb5: { +- falseEdge -> [real: bb20, imaginary: bb6]; +- } +- +- bb6: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,14 +67,6 @@ + goto -> bb16; } -- bb5: { -- falseEdge -> [real: bb13, imaginary: bb2]; -- } -- -- bb6: { -- falseEdge -> [real: bb8, imaginary: bb1]; -- } -- - bb7: { + bb4: { _0 = const 1_i32; @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb2]; +- falseEdge -> [real: bb3, imaginary: bb3]; + goto -> bb2; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 209f0d09c294..4f29e5244d7c 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -32,25 +32,33 @@ bb0: { PlaceMention(_2); -- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; +- switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } bb1: { -- switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; +- switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- falseEdge -> [real: bb8, imaginary: bb1]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; +- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5]; - } - - bb4: { +- falseEdge -> [real: bb13, imaginary: bb3]; +- } +- +- bb5: { +- falseEdge -> [real: bb20, imaginary: bb6]; +- } +- +- bb6: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,14 +67,6 @@ + goto -> bb16; } -- bb5: { -- falseEdge -> [real: bb13, imaginary: bb2]; -- } -- -- bb6: { -- falseEdge -> [real: bb8, imaginary: bb1]; -- } -- - bb7: { + bb4: { _0 = const 1_i32; @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb2]; +- falseEdge -> [real: bb3, imaginary: bb3]; + goto -> bb2; } diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir index 56edd38a6da4..775bc8afd7bd 100644 --- a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir @@ -18,7 +18,7 @@ fn shortcut_second_or() -> () { _1 = (move _2, const 0_i32); StorageDead(_2); PlaceMention(_1); - switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb4, otherwise: bb2]; + switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb3, otherwise: bb2]; } bb1: { @@ -27,15 +27,15 @@ fn shortcut_second_or() -> () { } bb2: { - switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb3, otherwise: bb1]; + switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb4, otherwise: bb1]; } bb3: { - switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1]; + switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1]; } bb4: { - switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1]; + switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1]; } bb5: { From fc40247c6b8d67da1a48d0ee73f42d9a239d2ae0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 12:56:13 +0200 Subject: [PATCH 194/361] Factor out the "process remaining candidates" cases --- .../rustc_mir_build/src/build/matches/mod.rs | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 458e2c5c4069..6eb8efc54ec3 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1457,7 +1457,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, span: Span, scrutinee_span: Span, - mut start_block: BasicBlock, + start_block: BasicBlock, otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], ) { @@ -1467,41 +1467,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - match candidates { + // Process a prefix of the candidates. + let rest = match candidates { [] => { - // If there are no candidates that still need testing, we're done. Since all matches are - // exhaustive, execution should never reach this point. + // If there are no candidates that still need testing, we're done. let source_info = self.source_info(span); self.cfg.goto(start_block, source_info, otherwise_block); + return; } [first, remaining @ ..] if first.match_pairs.is_empty() => { // The first candidate has satisfied all its match pairs; we link it up and continue // with the remaining candidates. - start_block = self.select_matched_candidate(first, start_block); - self.match_candidates(span, scrutinee_span, start_block, otherwise_block, remaining) + let remainder_start = self.select_matched_candidate(first, start_block); + remainder_start.and(remaining) } candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => { // If any candidate starts with an or-pattern, we have to expand the or-pattern before we // can proceed further. - self.expand_and_match_or_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - candidates, - ) + self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates) } candidates => { // The first candidate has some unsatisfied match pairs; we proceed to do more tests. - self.test_candidates( - span, - scrutinee_span, - candidates, - start_block, - otherwise_block, - ); + self.test_candidates(span, scrutinee_span, candidates, start_block) } - } + }; + + // Process any candidates that remain. + let BlockAnd(start_block, remaining_candidates) = rest; + self.match_candidates( + span, + scrutinee_span, + start_block, + otherwise_block, + remaining_candidates, + ); } /// Link up matched candidates. @@ -1547,16 +1546,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Takes a list of candidates such that some of the candidates' first match pairs are - /// or-patterns, expands as many or-patterns as possible, and processes the resulting - /// candidates. - fn expand_and_match_or_candidates( + /// or-patterns. This expands as many or-patterns as possible and processes the resulting + /// candidates. Returns the unprocessed candidates if any. + fn expand_and_match_or_candidates<'pat, 'b, 'c>( &mut self, span: Span, scrutinee_span: Span, start_block: BasicBlock, - otherwise_block: BasicBlock, - candidates: &mut [&mut Candidate<'_, 'tcx>], - ) { + candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], + ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { // We can't expand or-patterns freely. The rule is: if the candidate has an // or-pattern as its only remaining match pair, we can expand it freely. If it has // other match pairs, we can expand it but we can't process more candidates after @@ -1625,14 +1623,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Process the remaining candidates. - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); + remainder_start.and(remaining_candidates) } /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new @@ -2003,14 +1994,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// } /// # } /// ``` + /// + /// We return the unprocessed candidates. fn test_candidates<'pat, 'b, 'c>( &mut self, span: Span, scrutinee_span: Span, candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], start_block: BasicBlock, - otherwise_block: BasicBlock, - ) { + ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { // Extract the match-pair from the highest priority candidate and build a test from it. let (match_place, test) = self.pick_test(candidates); @@ -2050,13 +2042,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target_blocks, ); - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); + remainder_start.and(remaining_candidates) } } From 3e030b38ef1593592d6f4eb4144630d9abeb43b4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 13:21:12 +0200 Subject: [PATCH 195/361] Return the `otherwise_block` instead of passing it as argument This saves a few blocks and matches the common `unpack!` paradigm. --- .../rustc_mir_build/src/build/matches/mod.rs | 86 ++++------- .../issue_101867.main.built.after.mir | 18 +-- .../building/issue_49232.main.built.after.mir | 36 +++-- ...n_conditional.test_complex.built.after.mir | 134 ++++++++---------- ...se_edges.full_tested_match.built.after.mir | 56 ++++---- ...e_edges.full_tested_match2.built.after.mir | 60 ++++---- .../match_false_edges.main.built.after.mir | 94 ++++++------ .../simple_match.match_bool.built.after.mir | 36 +++-- .../simple_match.match_enum.built.after.mir | 28 ++-- ...e_out.move_out_by_subslice.built.after.mir | 34 ++--- ...move_out.move_out_from_end.built.after.mir | 34 ++--- tests/mir-opt/issue_72181.bar.built.after.mir | 4 - .../mir-opt/issue_72181.main.built.after.mir | 16 +-- tests/mir-opt/issue_72181_1.f.built.after.mir | 6 +- tests/mir-opt/issue_91633.bar.built.after.mir | 14 +- tests/mir-opt/issue_91633.hey.built.after.mir | 8 +- .../issue_99325.main.built.after.32bit.mir | 88 ++++++------ .../issue_99325.main.built.after.64bit.mir | 88 ++++++------ ...ut_second_or.SimplifyCfg-initial.after.mir | 24 ++-- 19 files changed, 368 insertions(+), 496 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6eb8efc54ec3..2fc510a222b6 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1313,11 +1313,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], refutable: bool, ) -> BasicBlock { + // This will generate code to test scrutinee_place and branch to the appropriate arm block. // See the doc comment on `match_candidates` for why we have an otherwise block. - let otherwise_block = self.cfg.start_new_block(); - - // This will generate code to test scrutinee_place and branch to the appropriate arm block - self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); + let otherwise_block = + self.match_candidates(match_start_span, scrutinee_span, block, candidates); // Link each leaf candidate to the `false_edge_start_block` of the next one. let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; @@ -1368,27 +1367,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block } - /// The main match algorithm. It begins with a set of candidates - /// `candidates` and has the job of generating code to determine - /// which of these candidates, if any, is the correct one. The + /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of + /// generating code that branches to an appropriate block if the scrutinee matches one of these + /// candidates. The /// candidates are sorted such that the first item in the list /// has the highest priority. When a candidate is found to match /// the value, we will set and generate a branch to the appropriate /// pre-binding block. /// - /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`. + /// If none of the candidates apply, we continue to the returned `otherwise_block`. /// /// It might be surprising that the input can be non-exhaustive. - /// Indeed, initially, it is not, because all matches are + /// Indeed, for matches, initially, it is not, because all matches are /// exhaustive in Rust. But during processing we sometimes divide /// up the list of candidates and recurse with a non-exhaustive /// list. This is how our lowering approach (called "backtracking /// automaton" in the literature) works. /// See [`Builder::test_candidates`] for more details. /// - /// If `fake_borrows` is `Some`, then places which need fake borrows - /// will be added to it. - /// /// For an example of how we use `otherwise_block`, consider: /// ``` /// # fn foo((x, y): (bool, bool)) -> u32 { @@ -1413,7 +1409,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// } /// if y { /// if x { - /// // This is actually unreachable because the `(true, true)` case was handled above. + /// // This is actually unreachable because the `(true, true)` case was handled above, + /// // but we don't know that from within the lowering algorithm. /// // continue /// } else { /// return 3 @@ -1430,25 +1427,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`]. /// /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller - /// code size at the expense of non-optimal code paths. + /// code size so we accept non-optimal code paths. #[instrument(skip(self), level = "debug")] fn match_candidates( &mut self, span: Span, scrutinee_span: Span, start_block: BasicBlock, - otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], - ) { + ) -> BasicBlock { ensure_sufficient_stack(|| { - self.match_candidates_with_enough_stack( - span, - scrutinee_span, - start_block, - otherwise_block, - candidates, - ) - }); + self.match_candidates_with_enough_stack(span, scrutinee_span, start_block, candidates) + }) } /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates` @@ -1458,9 +1448,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, scrutinee_span: Span, start_block: BasicBlock, - otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], - ) { + ) -> BasicBlock { if let [first, ..] = candidates { if first.false_edge_start_block.is_none() { first.false_edge_start_block = Some(start_block); @@ -1471,9 +1460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rest = match candidates { [] => { // If there are no candidates that still need testing, we're done. - let source_info = self.source_info(span); - self.cfg.goto(start_block, source_info, otherwise_block); - return; + return start_block; } [first, remaining @ ..] if first.match_pairs.is_empty() => { // The first candidate has satisfied all its match pairs; we link it up and continue @@ -1494,13 +1481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Process any candidates that remain. let BlockAnd(start_block, remaining_candidates) = rest; - self.match_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - remaining_candidates, - ); + self.match_candidates(span, scrutinee_span, start_block, remaining_candidates) } /// Link up matched candidates. @@ -1605,14 +1586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Process the expanded candidates. - let remainder_start = self.cfg.start_new_block(); - // There might be new or-patterns obtained from expanding the old ones, so we call - // `match_candidates` again. - self.match_candidates( + let remainder_start = self.match_candidates( span, scrutinee_span, start_block, - remainder_start, expanded_candidates.as_mut_slice(), ); @@ -1711,6 +1688,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.merge_trivial_subcandidates(candidate); if !candidate.match_pairs.is_empty() { + let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span); + let source_info = self.source_info(or_span); // If more match pairs remain, test them after each subcandidate. // We could add them to the or-candidates before the call to `test_or_pattern` but this // would make it impossible to detect simplifiable or-patterns. That would guarantee @@ -1724,6 +1703,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(leaf_candidate.match_pairs.is_empty()); leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); let or_start = leaf_candidate.pre_binding_block.unwrap(); + let otherwise = + self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]); // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q, // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching // directly to `last_otherwise`. If there is a guard, @@ -1734,13 +1715,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { last_otherwise.unwrap() }; - self.match_candidates( - span, - scrutinee_span, - or_start, - or_otherwise, - &mut [leaf_candidate], - ); + self.cfg.goto(otherwise, source_info, or_otherwise); }); } } @@ -2019,15 +1994,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks: FxIndexMap<_, _> = target_candidates .into_iter() .map(|(branch, mut candidates)| { - let candidate_start = self.cfg.start_new_block(); - self.match_candidates( - span, - scrutinee_span, - candidate_start, - remainder_start, - &mut *candidates, - ); - (branch, candidate_start) + let branch_start = self.cfg.start_new_block(); + let branch_otherwise = + self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates); + let source_info = self.source_info(span); + self.cfg.goto(branch_otherwise, source_info, remainder_start); + (branch, branch_start) }) .collect(); diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 728b5b23c6a6..5c50b3db5cad 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -27,13 +27,13 @@ fn main() -> () { StorageLive(_5); PlaceMention(_1); _6 = discriminant(_1); - switchInt(move _6) -> [1: bb5, otherwise: bb4]; + switchInt(move _6) -> [1: bb4, otherwise: bb3]; } bb1: { StorageLive(_3); StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb9; + _4 = begin_panic::<&str>(const "explicit panic") -> bb8; } bb2: { @@ -43,22 +43,18 @@ fn main() -> () { } bb3: { - goto -> bb8; + goto -> bb7; } bb4: { - goto -> bb3; + falseEdge -> [real: bb6, imaginary: bb3]; } bb5: { - falseEdge -> [real: bb7, imaginary: bb3]; + goto -> bb3; } bb6: { - goto -> bb4; - } - - bb7: { _5 = ((_1 as Some).0: u8); _0 = const (); StorageDead(_5); @@ -66,12 +62,12 @@ fn main() -> () { return; } - bb8: { + bb7: { StorageDead(_5); goto -> bb1; } - bb9 (cleanup): { + bb8 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/issue_49232.main.built.after.mir b/tests/mir-opt/building/issue_49232.main.built.after.mir index ac7e530520a3..d09a1748a8b3 100644 --- a/tests/mir-opt/building/issue_49232.main.built.after.mir +++ b/tests/mir-opt/building/issue_49232.main.built.after.mir @@ -17,7 +17,7 @@ fn main() -> () { } bb1: { - falseUnwind -> [real: bb2, unwind: bb15]; + falseUnwind -> [real: bb2, unwind: bb14]; } bb2: { @@ -25,7 +25,7 @@ fn main() -> () { StorageLive(_3); _3 = const true; PlaceMention(_3); - switchInt(_3) -> [0: bb5, otherwise: bb7]; + switchInt(_3) -> [0: bb4, otherwise: bb6]; } bb3: { @@ -34,49 +34,45 @@ fn main() -> () { } bb4: { - goto -> bb3; + falseEdge -> [real: bb8, imaginary: bb6]; } bb5: { - falseEdge -> [real: bb9, imaginary: bb7]; + goto -> bb3; } bb6: { - goto -> bb4; + _0 = const (); + goto -> bb13; } bb7: { - _0 = const (); - goto -> bb14; + goto -> bb3; } bb8: { - goto -> bb4; + _2 = const 4_i32; + goto -> bb11; } bb9: { - _2 = const 4_i32; - goto -> bb12; - } - - bb10: { unreachable; } - bb11: { - goto -> bb12; + bb10: { + goto -> bb11; } - bb12: { + bb11: { FakeRead(ForLet(None), _2); StorageDead(_3); StorageLive(_5); StorageLive(_6); _6 = &_2; - _5 = std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb15]; + _5 = std::mem::drop::<&i32>(move _6) -> [return: bb12, unwind: bb14]; } - bb13: { + bb12: { StorageDead(_6); StorageDead(_5); _1 = const (); @@ -84,13 +80,13 @@ fn main() -> () { goto -> bb1; } - bb14: { + bb13: { StorageDead(_3); StorageDead(_2); return; } - bb15 (cleanup): { + bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir index 395b8b82bff4..3e16efe6980d 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir +++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir @@ -19,188 +19,180 @@ fn test_complex() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = E::f() -> [return: bb1, unwind: bb36]; + _2 = E::f() -> [return: bb1, unwind: bb34]; } bb1: { PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb4, otherwise: bb3]; + switchInt(move _3) -> [0: bb3, otherwise: bb2]; } bb2: { - goto -> bb22; + goto -> bb21; } bb3: { - goto -> bb2; + falseEdge -> [real: bb5, imaginary: bb2]; } bb4: { - falseEdge -> [real: bb6, imaginary: bb2]; + goto -> bb2; } bb5: { - goto -> bb3; + StorageLive(_4); + _4 = always_true() -> [return: bb6, unwind: bb34]; } bb6: { - StorageLive(_4); - _4 = always_true() -> [return: bb7, unwind: bb36]; + switchInt(move _4) -> [0: bb8, otherwise: bb7]; } bb7: { - switchInt(move _4) -> [0: bb9, otherwise: bb8]; - } - - bb8: { StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = Droppy(const 0_u8); _6 = (_7.0: u8); _5 = Gt(move _6, const 0_u8); - switchInt(move _5) -> [0: bb11, otherwise: bb10]; + switchInt(move _5) -> [0: bb10, otherwise: bb9]; + } + + bb8: { + goto -> bb14; } bb9: { - goto -> bb15; + drop(_7) -> [return: bb11, unwind: bb34]; } bb10: { - drop(_7) -> [return: bb12, unwind: bb36]; + goto -> bb12; } bb11: { - goto -> bb13; + StorageDead(_7); + StorageDead(_6); + goto -> bb18; } bb12: { - StorageDead(_7); - StorageDead(_6); - goto -> bb19; + drop(_7) -> [return: bb13, unwind: bb34]; } bb13: { - drop(_7) -> [return: bb14, unwind: bb36]; + StorageDead(_7); + StorageDead(_6); + goto -> bb14; } bb14: { - StorageDead(_7); - StorageDead(_6); - goto -> bb15; - } - - bb15: { StorageLive(_8); StorageLive(_9); StorageLive(_10); _10 = Droppy(const 1_u8); _9 = (_10.0: u8); _8 = Gt(move _9, const 1_u8); - switchInt(move _8) -> [0: bb17, otherwise: bb16]; + switchInt(move _8) -> [0: bb16, otherwise: bb15]; + } + + bb15: { + drop(_10) -> [return: bb17, unwind: bb34]; } bb16: { - drop(_10) -> [return: bb18, unwind: bb36]; - } - - bb17: { - goto -> bb20; - } - - bb18: { - StorageDead(_10); - StorageDead(_9); goto -> bb19; } - bb19: { + bb17: { + StorageDead(_10); + StorageDead(_9); + goto -> bb18; + } + + bb18: { _1 = const (); - goto -> bb23; + goto -> bb22; + } + + bb19: { + drop(_10) -> [return: bb20, unwind: bb34]; } bb20: { - drop(_10) -> [return: bb21, unwind: bb36]; + StorageDead(_10); + StorageDead(_9); + goto -> bb21; } bb21: { - StorageDead(_10); - StorageDead(_9); + _1 = const (); goto -> bb22; } bb22: { - _1 = const (); - goto -> bb23; - } - - bb23: { StorageDead(_8); StorageDead(_5); StorageDead(_4); StorageDead(_2); StorageDead(_1); StorageLive(_11); - _11 = always_true() -> [return: bb24, unwind: bb36]; + _11 = always_true() -> [return: bb23, unwind: bb34]; + } + + bb23: { + switchInt(move _11) -> [0: bb25, otherwise: bb24]; } bb24: { - switchInt(move _11) -> [0: bb26, otherwise: bb25]; + goto -> bb32; } bb25: { - goto -> bb34; + goto -> bb26; } bb26: { - goto -> bb27; + StorageLive(_12); + _12 = E::f() -> [return: bb27, unwind: bb34]; } bb27: { - StorageLive(_12); - _12 = E::f() -> [return: bb28, unwind: bb36]; + PlaceMention(_12); + _13 = discriminant(_12); + switchInt(move _13) -> [1: bb29, otherwise: bb28]; } bb28: { - PlaceMention(_12); - _13 = discriminant(_12); - switchInt(move _13) -> [1: bb31, otherwise: bb30]; + goto -> bb32; } bb29: { - goto -> bb34; + falseEdge -> [real: bb31, imaginary: bb28]; } bb30: { - goto -> bb29; + goto -> bb28; } bb31: { - falseEdge -> [real: bb33, imaginary: bb29]; + _0 = const (); + goto -> bb33; } bb32: { - goto -> bb30; + _0 = const (); + goto -> bb33; } bb33: { - _0 = const (); - goto -> bb35; - } - - bb34: { - _0 = const (); - goto -> bb35; - } - - bb35: { StorageDead(_11); StorageDead(_12); return; } - bb36 (cleanup): { + bb34 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir index 623dd51c3584..9ebfff18f483 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [0: bb6, 1: bb3, otherwise: bb2]; + switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; } bb1: { @@ -37,43 +37,39 @@ fn full_tested_match() -> () { } bb2: { - goto -> bb1; + falseEdge -> [real: bb7, imaginary: bb3]; } bb3: { - falseEdge -> [real: bb8, imaginary: bb4]; + falseEdge -> [real: bb12, imaginary: bb5]; } bb4: { - falseEdge -> [real: bb13, imaginary: bb6]; + goto -> bb1; } bb5: { - goto -> bb2; + _1 = (const 3_i32, const 3_i32); + goto -> bb13; } bb6: { - _1 = (const 3_i32, const 3_i32); - goto -> bb14; + goto -> bb1; } bb7: { - goto -> bb2; - } - - bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb9, unwind: bb17]; + _7 = guard() -> [return: bb8, unwind: bb15]; + } + + bb8: { + switchInt(move _7) -> [0: bb10, otherwise: bb9]; } bb9: { - switchInt(move _7) -> [0: bb11, otherwise: bb10]; - } - - bb10: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -85,20 +81,20 @@ fn full_tested_match() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb14; + goto -> bb13; + } + + bb10: { + goto -> bb11; } bb11: { - goto -> bb12; + StorageDead(_7); + StorageDead(_6); + goto -> bb3; } bb12: { - StorageDead(_7); - StorageDead(_6); - goto -> bb4; - } - - bb13: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -106,10 +102,10 @@ fn full_tested_match() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb14; + goto -> bb13; } - bb14: { + bb13: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -117,16 +113,12 @@ fn full_tested_match() -> () { return; } - bb15: { + bb14: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb16: { - goto -> bb15; - } - - bb17 (cleanup): { + bb15 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir index 3cb037bf9560..4d2989ea93ec 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match2() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [0: bb6, 1: bb3, otherwise: bb2]; + switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; } bb1: { @@ -37,14 +37,10 @@ fn full_tested_match2() -> () { } bb2: { - goto -> bb1; + falseEdge -> [real: bb7, imaginary: bb5]; } bb3: { - falseEdge -> [real: bb8, imaginary: bb6]; - } - - bb4: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -52,34 +48,34 @@ fn full_tested_match2() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb14; + goto -> bb13; + } + + bb4: { + goto -> bb1; } bb5: { - goto -> bb2; + falseEdge -> [real: bb12, imaginary: bb3]; } bb6: { - falseEdge -> [real: bb13, imaginary: bb4]; + goto -> bb1; } bb7: { - goto -> bb2; - } - - bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb9, unwind: bb17]; + _7 = guard() -> [return: bb8, unwind: bb15]; + } + + bb8: { + switchInt(move _7) -> [0: bb10, otherwise: bb9]; } bb9: { - switchInt(move _7) -> [0: bb11, otherwise: bb10]; - } - - bb10: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -91,25 +87,25 @@ fn full_tested_match2() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb14; + goto -> bb13; + } + + bb10: { + goto -> bb11; } bb11: { - goto -> bb12; + StorageDead(_7); + StorageDead(_6); + falseEdge -> [real: bb3, imaginary: bb5]; } bb12: { - StorageDead(_7); - StorageDead(_6); - falseEdge -> [real: bb4, imaginary: bb6]; + _1 = (const 3_i32, const 3_i32); + goto -> bb13; } bb13: { - _1 = (const 3_i32, const 3_i32); - goto -> bb14; - } - - bb14: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -117,16 +113,12 @@ fn full_tested_match2() -> () { return; } - bb15: { + bb14: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb16: { - goto -> bb15; - } - - bb17 (cleanup): { + bb15 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index 134517ad2aec..4ed936107066 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -39,64 +39,60 @@ fn main() -> () { _2 = Option::::Some(const 1_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [1: bb3, otherwise: bb2]; + switchInt(move _4) -> [1: bb2, otherwise: bb1]; } bb1: { - FakeRead(ForMatchedPlace(None), _2); - unreachable; + falseEdge -> [real: bb14, imaginary: bb4]; } bb2: { - falseEdge -> [real: bb15, imaginary: bb5]; + falseEdge -> [real: bb9, imaginary: bb1]; } bb3: { - falseEdge -> [real: bb10, imaginary: bb2]; + goto -> bb1; } bb4: { - goto -> bb2; + _5 = discriminant(_2); + switchInt(move _5) -> [1: bb6, otherwise: bb5]; } bb5: { - _5 = discriminant(_2); - switchInt(move _5) -> [1: bb7, otherwise: bb6]; - } - - bb6: { StorageLive(_14); _14 = _2; _1 = const 4_i32; StorageDead(_14); - goto -> bb21; + goto -> bb20; + } + + bb6: { + falseEdge -> [real: bb15, imaginary: bb5]; } bb7: { - falseEdge -> [real: bb16, imaginary: bb6]; + goto -> bb5; } bb8: { - goto -> bb6; + FakeRead(ForMatchedPlace(None), _2); + unreachable; } bb9: { - goto -> bb1; - } - - bb10: { StorageLive(_7); _7 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_8); - _8 = guard() -> [return: bb11, unwind: bb24]; + _8 = guard() -> [return: bb10, unwind: bb22]; + } + + bb10: { + switchInt(move _8) -> [0: bb12, otherwise: bb11]; } bb11: { - switchInt(move _8) -> [0: bb13, otherwise: bb12]; - } - - bb12: { StorageDead(_8); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _7); @@ -105,42 +101,42 @@ fn main() -> () { _1 = const 1_i32; StorageDead(_6); StorageDead(_7); - goto -> bb21; + goto -> bb20; + } + + bb12: { + goto -> bb13; } bb13: { - goto -> bb14; + StorageDead(_8); + StorageDead(_7); + falseEdge -> [real: bb3, imaginary: bb1]; } bb14: { - StorageDead(_8); - StorageDead(_7); - falseEdge -> [real: bb4, imaginary: bb2]; - } - - bb15: { StorageLive(_9); _9 = _2; _1 = const 2_i32; StorageDead(_9); - goto -> bb21; + goto -> bb20; } - bb16: { + bb15: { StorageLive(_11); _11 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_12); StorageLive(_13); _13 = (*_11); - _12 = guard2(move _13) -> [return: bb17, unwind: bb24]; + _12 = guard2(move _13) -> [return: bb16, unwind: bb22]; + } + + bb16: { + switchInt(move _12) -> [0: bb18, otherwise: bb17]; } bb17: { - switchInt(move _12) -> [0: bb19, otherwise: bb18]; - } - - bb18: { StorageDead(_13); StorageDead(_12); FakeRead(ForMatchGuard, _3); @@ -150,21 +146,21 @@ fn main() -> () { _1 = const 3_i32; StorageDead(_10); StorageDead(_11); - goto -> bb21; - } - - bb19: { goto -> bb20; } - bb20: { + bb18: { + goto -> bb19; + } + + bb19: { StorageDead(_13); StorageDead(_12); StorageDead(_11); - falseEdge -> [real: bb8, imaginary: bb6]; + falseEdge -> [real: bb7, imaginary: bb5]; } - bb21: { + bb20: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -172,16 +168,12 @@ fn main() -> () { return; } - bb22: { + bb21: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb23: { - goto -> bb22; - } - - bb24 (cleanup): { + bb22 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir index 81b5ce304d0e..b0ebdc37b067 100644 --- a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir @@ -6,37 +6,33 @@ fn match_bool(_1: bool) -> usize { bb0: { PlaceMention(_1); - switchInt(_1) -> [0: bb2, otherwise: bb3]; + switchInt(_1) -> [0: bb1, otherwise: bb2]; } bb1: { + _0 = const 20_usize; + goto -> bb6; + } + + bb2: { + falseEdge -> [real: bb5, imaginary: bb1]; + } + + bb3: { + goto -> bb1; + } + + bb4: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb2: { - _0 = const 20_usize; - goto -> bb7; - } - - bb3: { - falseEdge -> [real: bb6, imaginary: bb2]; - } - - bb4: { - goto -> bb2; - } - bb5: { - goto -> bb1; + _0 = const 10_usize; + goto -> bb6; } bb6: { - _0 = const 10_usize; - goto -> bb7; - } - - bb7: { return; } } diff --git a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir index c2ea5bd441c3..5e685f43cd61 100644 --- a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir @@ -8,7 +8,7 @@ fn match_enum(_1: E1) -> bool { bb0: { PlaceMention(_1); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb4, 1: bb6, 2: bb8, otherwise: bb3]; + switchInt(move _2) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb1]; } bb1: { @@ -17,48 +17,40 @@ fn match_enum(_1: E1) -> bool { } bb2: { - goto -> bb1; + goto -> bb8; } bb3: { - goto -> bb2; + goto -> bb1; } bb4: { - goto -> bb10; + goto -> bb8; } bb5: { - goto -> bb3; + goto -> bb1; } bb6: { + _0 = const false; goto -> bb10; } bb7: { - goto -> bb3; + goto -> bb1; } bb8: { - _0 = const false; - goto -> bb12; + falseEdge -> [real: bb9, imaginary: bb6]; } bb9: { - goto -> bb3; + _0 = const true; + goto -> bb10; } bb10: { - falseEdge -> [real: bb11, imaginary: bb8]; - } - - bb11: { - _0 = const true; - goto -> bb12; - } - - bb12: { return; } } diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir index db758368a138..6d3b2cf29103 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir @@ -26,7 +26,7 @@ fn move_out_by_subslice() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; } bb1: { @@ -34,7 +34,7 @@ fn move_out_by_subslice() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb13]; + drop(_6) -> [return: bb2, unwind: bb12]; } bb2: { @@ -42,7 +42,7 @@ fn move_out_by_subslice() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; } bb3: { @@ -50,18 +50,18 @@ fn move_out_by_subslice() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb12]; + drop(_11) -> [return: bb4, unwind: bb11]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb13]; + drop(_7) -> [return: bb5, unwind: bb12]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb14]; + drop(_2) -> [return: bb6, unwind: bb13]; } bb6: { @@ -71,7 +71,7 @@ fn move_out_by_subslice() -> () { StorageLive(_12); _12 = move _1[0..2]; _0 = const (); - drop(_12) -> [return: bb9, unwind: bb11]; + drop(_12) -> [return: bb8, unwind: bb10]; } bb7: { @@ -80,32 +80,28 @@ fn move_out_by_subslice() -> () { } bb8: { - goto -> bb7; + StorageDead(_12); + drop(_1) -> [return: bb9, unwind: bb13]; } bb9: { - StorageDead(_12); - drop(_1) -> [return: bb10, unwind: bb14]; - } - - bb10: { StorageDead(_1); return; } + bb10 (cleanup): { + drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + } + bb11 (cleanup): { - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_7) -> [return: bb12, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_7) -> [return: bb13, unwind terminate(cleanup)]; + drop(_2) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { - drop(_2) -> [return: bb14, unwind terminate(cleanup)]; - } - - bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir index 84cd557715c2..003b90a912d2 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir @@ -26,7 +26,7 @@ fn move_out_from_end() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; } bb1: { @@ -34,7 +34,7 @@ fn move_out_from_end() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb13]; + drop(_6) -> [return: bb2, unwind: bb12]; } bb2: { @@ -42,7 +42,7 @@ fn move_out_from_end() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; } bb3: { @@ -50,18 +50,18 @@ fn move_out_from_end() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb12]; + drop(_11) -> [return: bb4, unwind: bb11]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb13]; + drop(_7) -> [return: bb5, unwind: bb12]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb14]; + drop(_2) -> [return: bb6, unwind: bb13]; } bb6: { @@ -71,7 +71,7 @@ fn move_out_from_end() -> () { StorageLive(_12); _12 = move _1[1 of 2]; _0 = const (); - drop(_12) -> [return: bb9, unwind: bb11]; + drop(_12) -> [return: bb8, unwind: bb10]; } bb7: { @@ -80,32 +80,28 @@ fn move_out_from_end() -> () { } bb8: { - goto -> bb7; + StorageDead(_12); + drop(_1) -> [return: bb9, unwind: bb13]; } bb9: { - StorageDead(_12); - drop(_1) -> [return: bb10, unwind: bb14]; - } - - bb10: { StorageDead(_1); return; } + bb10 (cleanup): { + drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + } + bb11 (cleanup): { - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_7) -> [return: bb12, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_7) -> [return: bb13, unwind terminate(cleanup)]; + drop(_2) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { - drop(_2) -> [return: bb14, unwind terminate(cleanup)]; - } - - bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_72181.bar.built.after.mir b/tests/mir-opt/issue_72181.bar.built.after.mir index 3ab9152f8bb6..b6cc7d221956 100644 --- a/tests/mir-opt/issue_72181.bar.built.after.mir +++ b/tests/mir-opt/issue_72181.bar.built.after.mir @@ -19,8 +19,4 @@ fn bar(_1: [(Never, u32); 1]) -> u32 { FakeRead(ForMatchedPlace(None), _1); unreachable; } - - bb2: { - goto -> bb1; - } } diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir index fa101512d729..89d351d5172c 100644 --- a/tests/mir-opt/issue_72181.main.built.after.mir +++ b/tests/mir-opt/issue_72181.main.built.after.mir @@ -20,7 +20,7 @@ fn main() -> () { bb0: { StorageLive(_1); - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb7]; + _1 = std::mem::size_of::() -> [return: bb1, unwind: bb5]; } bb1: { @@ -40,7 +40,7 @@ fn main() -> () { _6 = const 0_usize; _7 = Len(_2); _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb4, unwind: bb7]; + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb5]; } bb2: { @@ -49,10 +49,6 @@ fn main() -> () { } bb3: { - goto -> bb2; - } - - bb4: { _5 = (_2[_6].0: u64); PlaceMention(_5); StorageDead(_6); @@ -62,16 +58,12 @@ fn main() -> () { return; } - bb5: { + bb4: { FakeRead(ForMatchedPlace(None), _5); unreachable; } - bb6: { - goto -> bb5; - } - - bb7 (cleanup): { + bb5 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir index 674a4013fe77..89da9a801136 100644 --- a/tests/mir-opt/issue_72181_1.f.built.after.mir +++ b/tests/mir-opt/issue_72181_1.f.built.after.mir @@ -6,15 +6,11 @@ fn f(_1: Void) -> ! { bb0: { PlaceMention(_1); - goto -> bb1; - } - - bb1: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb2: { + bb1: { return; } } diff --git a/tests/mir-opt/issue_91633.bar.built.after.mir b/tests/mir-opt/issue_91633.bar.built.after.mir index 3dcdcab9dea3..53829588a1b3 100644 --- a/tests/mir-opt/issue_91633.bar.built.after.mir +++ b/tests/mir-opt/issue_91633.bar.built.after.mir @@ -12,7 +12,7 @@ fn bar(_1: Box<[T]>) -> () { StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb5]; + _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb4]; } bb1: { @@ -20,7 +20,7 @@ fn bar(_1: Box<[T]>) -> () { PlaceMention((*_2)); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb4, unwind: bb6]; + drop(_1) -> [return: bb3, unwind: bb5]; } bb2: { @@ -29,18 +29,14 @@ fn bar(_1: Box<[T]>) -> () { } bb3: { - goto -> bb2; - } - - bb4: { return; } - bb5 (cleanup): { - drop(_1) -> [return: bb6, unwind terminate(cleanup)]; + bb4 (cleanup): { + drop(_1) -> [return: bb5, unwind terminate(cleanup)]; } - bb6 (cleanup): { + bb5 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_91633.hey.built.after.mir b/tests/mir-opt/issue_91633.hey.built.after.mir index e782f4d1a23f..a537e509996d 100644 --- a/tests/mir-opt/issue_91633.hey.built.after.mir +++ b/tests/mir-opt/issue_91633.hey.built.after.mir @@ -14,7 +14,7 @@ fn hey(_1: &[T]) -> () { StorageLive(_3); StorageLive(_4); _4 = &(*_1); - _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb4]; + _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb3]; } bb1: { @@ -32,11 +32,7 @@ fn hey(_1: &[T]) -> () { unreachable; } - bb3: { - goto -> bb2; - } - - bb4 (cleanup): { + bb3 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index b7a054b5d540..72e7f4794f98 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; } bb2: { @@ -100,24 +100,20 @@ fn main() -> () { } bb3: { - goto -> bb2; + switchInt(move _10) -> [0: bb5, otherwise: bb4]; } bb4: { - switchInt(move _10) -> [0: bb6, otherwise: bb5]; + StorageDead(_12); + StorageDead(_11); + goto -> bb9; } bb5: { - StorageDead(_12); - StorageDead(_11); - goto -> bb10; + goto -> bb6; } bb6: { - goto -> bb7; - } - - bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -136,10 +132,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; } - bb8: { + bb7: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -151,23 +147,23 @@ fn main() -> () { unreachable; } + bb8: { + goto -> bb10; + } + bb9: { - goto -> bb11; + _1 = const (); + goto -> bb10; } bb10: { - _1 = const (); + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); goto -> bb11; } bb11: { - StorageDead(_10); - StorageDead(_9); - StorageDead(_8); - goto -> bb12; - } - - bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -177,10 +173,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; } - bb13: { + bb12: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -199,33 +195,29 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; } - bb14: { + bb13: { FakeRead(ForMatchedPlace(None), _23); unreachable; } + bb14: { + switchInt(move _30) -> [0: bb16, otherwise: bb15]; + } + bb15: { - goto -> bb14; + StorageDead(_32); + StorageDead(_31); + goto -> bb20; } bb16: { - switchInt(move _30) -> [0: bb18, otherwise: bb17]; + goto -> bb17; } bb17: { - StorageDead(_32); - StorageDead(_31); - goto -> bb22; - } - - bb18: { - goto -> bb19; - } - - bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -244,10 +236,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; } - bb20: { + bb18: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -259,23 +251,23 @@ fn main() -> () { unreachable; } - bb21: { - goto -> bb23; + bb19: { + goto -> bb21; } - bb22: { + bb20: { _22 = const (); - goto -> bb23; + goto -> bb21; } - bb23: { + bb21: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb24; + goto -> bb22; } - bb24: { + bb22: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -284,7 +276,7 @@ fn main() -> () { return; } - bb25 (cleanup): { + bb23 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index b7a054b5d540..72e7f4794f98 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; } bb2: { @@ -100,24 +100,20 @@ fn main() -> () { } bb3: { - goto -> bb2; + switchInt(move _10) -> [0: bb5, otherwise: bb4]; } bb4: { - switchInt(move _10) -> [0: bb6, otherwise: bb5]; + StorageDead(_12); + StorageDead(_11); + goto -> bb9; } bb5: { - StorageDead(_12); - StorageDead(_11); - goto -> bb10; + goto -> bb6; } bb6: { - goto -> bb7; - } - - bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -136,10 +132,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; } - bb8: { + bb7: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -151,23 +147,23 @@ fn main() -> () { unreachable; } + bb8: { + goto -> bb10; + } + bb9: { - goto -> bb11; + _1 = const (); + goto -> bb10; } bb10: { - _1 = const (); + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); goto -> bb11; } bb11: { - StorageDead(_10); - StorageDead(_9); - StorageDead(_8); - goto -> bb12; - } - - bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -177,10 +173,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; } - bb13: { + bb12: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -199,33 +195,29 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; } - bb14: { + bb13: { FakeRead(ForMatchedPlace(None), _23); unreachable; } + bb14: { + switchInt(move _30) -> [0: bb16, otherwise: bb15]; + } + bb15: { - goto -> bb14; + StorageDead(_32); + StorageDead(_31); + goto -> bb20; } bb16: { - switchInt(move _30) -> [0: bb18, otherwise: bb17]; + goto -> bb17; } bb17: { - StorageDead(_32); - StorageDead(_31); - goto -> bb22; - } - - bb18: { - goto -> bb19; - } - - bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -244,10 +236,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; } - bb20: { + bb18: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -259,23 +251,23 @@ fn main() -> () { unreachable; } - bb21: { - goto -> bb23; + bb19: { + goto -> bb21; } - bb22: { + bb20: { _22 = const (); - goto -> bb23; + goto -> bb21; } - bb23: { + bb21: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb24; + goto -> bb22; } - bb24: { + bb22: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -284,7 +276,7 @@ fn main() -> () { return; } - bb25 (cleanup): { + bb23 (cleanup): { resume; } } diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir index 775bc8afd7bd..e357e785e33e 100644 --- a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir @@ -18,24 +18,24 @@ fn shortcut_second_or() -> () { _1 = (move _2, const 0_i32); StorageDead(_2); PlaceMention(_1); - switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb3, otherwise: bb2]; + switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb2, otherwise: bb1]; } bb1: { + switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb4, otherwise: bb3]; + } + + bb2: { + switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb3]; + } + + bb3: { _0 = const (); goto -> bb14; } - bb2: { - switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb4, otherwise: bb1]; - } - - bb3: { - switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1]; - } - bb4: { - switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1]; + switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb3]; } bb5: { @@ -43,7 +43,7 @@ fn shortcut_second_or() -> () { } bb6: { - falseEdge -> [real: bb11, imaginary: bb2]; + falseEdge -> [real: bb11, imaginary: bb1]; } bb7: { @@ -51,7 +51,7 @@ fn shortcut_second_or() -> () { } bb8: { - falseEdge -> [real: bb13, imaginary: bb1]; + falseEdge -> [real: bb13, imaginary: bb3]; } bb9: { From 42772e98e0d1d3ca0f6660c697e881f5de4b392e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 5 Jul 2024 22:23:14 +0200 Subject: [PATCH 196/361] Address review comments --- compiler/rustc_mir_build/src/build/matches/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 2fc510a222b6..841ef2719c99 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1437,17 +1437,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'_, 'tcx>], ) -> BasicBlock { ensure_sufficient_stack(|| { - self.match_candidates_with_enough_stack(span, scrutinee_span, start_block, candidates) + self.match_candidates_inner(span, scrutinee_span, start_block, candidates) }) } /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates` /// instead to reserve sufficient stack space. - fn match_candidates_with_enough_stack( + fn match_candidates_inner( &mut self, span: Span, scrutinee_span: Span, - start_block: BasicBlock, + mut start_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], ) -> BasicBlock { if let [first, ..] = candidates { @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; // Process any candidates that remain. - let BlockAnd(start_block, remaining_candidates) = rest; + let remaining_candidates = unpack!(start_block = rest); self.match_candidates(span, scrutinee_span, start_block, remaining_candidates) } From 8a390bae06dbb5686b581797b8f46cb0353dc255 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jul 2024 14:41:39 +1000 Subject: [PATCH 197/361] Change empty replace range condition. The new condition is equivalent in practice, but it's much more obvious that it would result in an empty range, because the condition lines up with the contents of the iterator. --- .../rustc_parse/src/parser/attr_wrapper.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 67d2424bb48a..e90568f177c2 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -295,21 +295,22 @@ impl<'a> Parser<'a> { let num_calls = end_pos - start_pos; - // If we have no attributes, then we will never need to - // use any replace ranges. - let replace_ranges: Box<[ReplaceRange]> = if ret.attrs().is_empty() && !self.capture_cfg { - Box::new([]) - } else { - // Grab any replace ranges that occur *inside* the current AST node. - // We will perform the actual replacement when we convert the `LazyAttrTokenStream` - // to an `AttrTokenStream`. - self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] - .iter() - .cloned() - .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) - .collect() - }; + // This is hot enough for `deep-vector` that checking the conditions for an empty iterator + // is measurably faster than actually executing the iterator. + let replace_ranges: Box<[ReplaceRange]> = + if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() { + Box::new([]) + } else { + // Grab any replace ranges that occur *inside* the current AST node. + // We will perform the actual replacement when we convert the `LazyAttrTokenStream` + // to an `AttrTokenStream`. + self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] + .iter() + .cloned() + .chain(inner_attr_replace_ranges.iter().cloned()) + .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) + .collect() + }; let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { start_token, From fee152556fda2260a17fa24cea21d18b57c8460d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jul 2024 14:51:41 +1000 Subject: [PATCH 198/361] Rework `Attribute::get_tokens`. Returning `Vec` works better for the call sites than returning `TokenStream`. --- compiler/rustc_ast/src/attr/mod.rs | 23 ++++++++++------------- compiler/rustc_ast/src/tokenstream.rs | 9 +++++---- compiler/rustc_expand/src/config.rs | 4 +--- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 088ae9ba4410..d2c7b1c0753d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -202,21 +202,18 @@ impl Attribute { } } - // Named `get_tokens` to distinguish it from the `::tokens` method. - pub fn get_tokens(&self) -> TokenStream { - match &self.kind { - AttrKind::Normal(normal) => TokenStream::new( - normal - .tokens - .as_ref() - .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) - .to_attr_token_stream() - .to_token_trees(), - ), - &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( + pub fn token_trees(&self) -> Vec { + match self.kind { + AttrKind::Normal(ref normal) => normal + .tokens + .as_ref() + .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) + .to_attr_token_stream() + .to_token_trees(), + AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone( token::DocComment(comment_kind, self.style, data), self.span, - ), + )], } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index ee068f19332a..1f2adde2570d 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -225,11 +225,12 @@ impl AttrTokenStream { // properly implemented - we always synthesize fake tokens, // so we never reach this code. - let mut stream = TokenStream::default(); + let mut tts = vec![]; for inner_attr in inner_attrs { - stream.push_stream(inner_attr.get_tokens()); + tts.extend(inner_attr.token_trees()); } - stream.push_stream(delim_tokens.clone()); + tts.extend(delim_tokens.0.iter().cloned()); + let stream = TokenStream::new(tts); *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); found = true; break; @@ -242,7 +243,7 @@ impl AttrTokenStream { ); } for attr in outer_attrs { - res.extend(attr.get_tokens().0.iter().cloned()); + res.extend(attr.token_trees()); } res.extend(target_tokens); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 40e16b451157..8d796500dcc6 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -292,8 +292,6 @@ impl<'a> StripUnconfigured<'a> { attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.get_tokens(); - // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We // have captured tokens for `attr` itself, but we need to @@ -302,7 +300,7 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let mut orig_trees = orig_tokens.trees(); + let mut orig_trees = attr.token_trees().into_iter(); let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = orig_trees.next().unwrap().clone() else { From e42a380afcd228fad0696d4cb919173b51083212 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Wed, 10 Jul 2024 08:10:35 +0300 Subject: [PATCH 199/361] Revert accidental "Why restrict this?" change --- clippy_lints/src/operators/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index bf7a581c8486..59834781a58a 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -636,7 +636,7 @@ declare_clippy_lint! { /// values (apart from zero), except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// ### Why is this bad? + /// ### Why restrict this? /// Floating point calculations are usually imprecise, so asking if two values are *exactly* /// equal is asking for trouble because arriving at the same logical result via different /// routes (e.g. calculation versus constant) may yield different values. From d8b6aa6d0dabc0c102f16f9f9bb35f687a63101c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jul 2024 15:11:57 +1000 Subject: [PATCH 200/361] Use `cfg_attr` as a name more. In various functions where the attribute being processed is known to be a `#[cfg_attr(...)]` attribute. I find this a helpful reminder. --- compiler/rustc_expand/src/config.rs | 22 +++++++++++----------- compiler/rustc_parse/src/lib.rs | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8d796500dcc6..13414f990fba 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -253,9 +253,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// 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, attr: &Attribute, recursive: bool) -> Vec { + pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(attr, &self.sess.psess) + rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) else { return vec![]; }; @@ -264,7 +264,7 @@ impl<'a> StripUnconfigured<'a> { if expanded_attrs.is_empty() { self.sess.psess.buffer_lint( rustc_lint_defs::builtin::UNUSED_ATTRIBUTES, - attr.span, + cfg_attr.span, ast::CRATE_NODE_ID, BuiltinLintDiag::CfgAttrNoAttributes, ); @@ -280,16 +280,16 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(cfg_attr, item)).collect() } } fn expand_cfg_attr_item( &self, - attr: &Attribute, + cfg_attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` @@ -300,11 +300,11 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let mut orig_trees = attr.token_trees().into_iter(); + let mut orig_trees = cfg_attr.token_trees().into_iter(); let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = orig_trees.next().unwrap().clone() else { - panic!("Bad tokens for attribute {attr:?}"); + panic!("Bad tokens for attribute {cfg_attr:?}"); }; // We don't really have a good span to use for the synthesized `[]` @@ -318,12 +318,12 @@ impl<'a> StripUnconfigured<'a> { .unwrap_or_else(|| panic!("Missing tokens for {item:?}")) .to_attr_token_stream(), ); - let trees = if attr.style == AttrStyle::Inner { + let trees = if cfg_attr.style == AttrStyle::Inner { // For inner attributes, we do the same thing for the `!` in `#![some_attr]` let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = orig_trees.next().unwrap().clone() else { - panic!("Bad tokens for attribute {attr:?}"); + panic!("Bad tokens for attribute {cfg_attr:?}"); }; vec![ AttrTokenTree::Token(pound_token, Spacing::Joint), @@ -338,7 +338,7 @@ impl<'a> StripUnconfigured<'a> { &self.sess.psess.attr_id_generator, item, tokens, - attr.style, + cfg_attr.style, item_span, ); if attr.has_name(sym::crate_type) { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 5522127be83e..4454747ea021 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -157,14 +157,14 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok } pub fn parse_cfg_attr( - attr: &Attribute, + cfg_attr: &Attribute, psess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ "; - match attr.get_normal_item().args { + match cfg_attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => { @@ -180,7 +180,7 @@ pub fn parse_cfg_attr( } _ => { psess.dcx().emit_err(errors::MalformedCfgAttr { - span: attr.span, + span: cfg_attr.span, sugg: CFG_ATTR_GRAMMAR_HELP, }); } From 0134bd2e670140e7f3ef98007f811ba2ca0ff882 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 10 Jul 2024 08:35:31 +0300 Subject: [PATCH 201/361] remove unnecessary `git` usages `Config::src` already contains the top-level path, so we don't need to add git overhead just to reach this path. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 10ac6c93e9a4..84c621a06b54 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2445,14 +2445,6 @@ impl Config { } }; - // Handle running from a directory other than the top level - let top_level = output( - &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, - ); - let top_level = top_level.trim_end(); - let compiler = format!("{top_level}/compiler/"); - let library = format!("{top_level}/library/"); - // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( @@ -2473,7 +2465,9 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) - .args(["diff-index", "--quiet", commit, "--", &compiler, &library]) + .args(["diff-index", "--quiet", commit]) + .arg("--") + .args([self.src.join("compiler"), self.src.join("library")]) .command .status()) .success(); @@ -2545,12 +2539,6 @@ impl Config { option_name: &str, if_unchanged: bool, ) -> Option { - // Handle running from a directory other than the top level - let top_level = output( - &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, - ); - let top_level = top_level.trim_end(); - // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( @@ -2573,8 +2561,11 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.args(["diff-index", "--quiet", commit, "--"]); + // Handle running from a directory other than the top level + let top_level = &self.src; + for path in modified_paths { - git.arg(format!("{top_level}/{path}")); + git.arg(top_level.join(path)); } let has_changes = !t!(git.command.status()).success(); From d6ebbbfcb203b969f9b6e02998efd9badbe885d6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jul 2024 15:47:02 +1000 Subject: [PATCH 202/361] Factor out `AttrsTarget` flattening code. This commit does the following. - Pulls the code out of `AttrTokenStream::to_token_trees` into a new function `attrs_and_tokens_to_token_trees`. - Simplifies `TokenStream::from_ast` by calling the new function. This is nicer than the old way, which created a temporary `AttrTokenStream` containing a single `AttrsTarget` (which required some cloning) just to call `to_token_trees` on it. (It is good to remove this use of `AttrsTarget` which isn't related to `cfg_attr` expansion.) --- compiler/rustc_ast/src/tokenstream.rs | 132 +++++++++++++------------- compiler/rustc_expand/src/config.rs | 5 +- 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 1f2adde2570d..1f69a7dc3566 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -16,7 +16,7 @@ use crate::ast::{AttrStyle, StmtKind}; use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; -use crate::AttrVec; +use crate::{AttrVec, Attribute}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, Lrc}; @@ -179,11 +179,10 @@ impl AttrTokenStream { AttrTokenStream(Lrc::new(tokens)) } - /// Converts this `AttrTokenStream` to a plain `Vec`. - /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened' - /// back to a `TokenStream` of the form `outer_attr attr_target`. - /// If there are inner attributes, they are inserted into the proper - /// place in the attribute target tokens. + /// Converts this `AttrTokenStream` to a plain `Vec`. During + /// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a + /// `TokenStream`, as described in the comment on + /// `attrs_and_tokens_to_token_trees`. pub fn to_token_trees(&self) -> Vec { let mut res = Vec::with_capacity(self.0.len()); for tree in self.0.iter() { @@ -200,52 +199,7 @@ impl AttrTokenStream { )) } AttrTokenTree::AttrsTarget(target) => { - let idx = target - .attrs - .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = target.attrs.split_at(idx); - - let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees(); - if !inner_attrs.is_empty() { - let mut found = false; - // Check the last two trees (to account for a trailing semi) - for tree in target_tokens.iter_mut().rev().take(2) { - if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { - // Inner attributes are only supported on extern blocks, functions, - // impls, and modules. All of these have their inner attributes - // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr] } - // - // Therefore, we can insert them back into the right location - // without needing to do any extra position tracking. - // - // Note: Outline modules are an exception - they can - // have attributes like `#![my_attr]` at the start of a file. - // Support for custom attributes in this position is not - // properly implemented - we always synthesize fake tokens, - // so we never reach this code. - - let mut tts = vec![]; - for inner_attr in inner_attrs { - tts.extend(inner_attr.token_trees()); - } - tts.extend(delim_tokens.0.iter().cloned()); - let stream = TokenStream::new(tts); - *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); - found = true; - break; - } - } - - assert!( - found, - "Failed to find trailing delimited group in: {target_tokens:?}" - ); - } - for attr in outer_attrs { - res.extend(attr.token_trees()); - } - res.extend(target_tokens); + attrs_and_tokens_to_token_trees(&target.attrs, &target.tokens, &mut res); } } } @@ -253,6 +207,64 @@ impl AttrTokenStream { } } +// Converts multiple attributes and the tokens for a target AST node into token trees, and appends +// them to `res`. +// +// Example: if the AST node is "fn f() { blah(); }", then: +// - Simple if no attributes are present, e.g. "fn f() { blah(); }" +// - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }" +// - Trickier if inner attributes are present, because they must be moved within the AST node's +// tokens, e.g. "#[outer] fn f() { #![inner] blah() }" +fn attrs_and_tokens_to_token_trees( + attrs: &[Attribute], + target_tokens: &LazyAttrTokenStream, + res: &mut Vec, +) { + let idx = attrs.partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); + let (outer_attrs, inner_attrs) = attrs.split_at(idx); + + // Add outer attribute tokens. + for attr in outer_attrs { + res.extend(attr.token_trees()); + } + + // Add target AST node tokens. + res.extend(target_tokens.to_attr_token_stream().to_token_trees()); + + // Insert inner attribute tokens. + if !inner_attrs.is_empty() { + let mut found = false; + // Check the last two trees (to account for a trailing semi) + for tree in res.iter_mut().rev().take(2) { + if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { + // Inner attributes are only supported on extern blocks, functions, + // impls, and modules. All of these have their inner attributes + // placed at the beginning of the rightmost outermost braced group: + // e.g. fn foo() { #![my_attr] } + // + // Therefore, we can insert them back into the right location + // without needing to do any extra position tracking. + // + // Note: Outline modules are an exception - they can + // have attributes like `#![my_attr]` at the start of a file. + // Support for custom attributes in this position is not + // properly implemented - we always synthesize fake tokens, + // so we never reach this code. + let mut tts = vec![]; + for inner_attr in inner_attrs { + tts.extend(inner_attr.token_trees()); + } + tts.extend(delim_tokens.0.iter().cloned()); + let stream = TokenStream::new(tts); + *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); + found = true; + break; + } + } + assert!(found, "Failed to find trailing delimited group in: {res:?}"); + } +} + /// Stores the tokens for an attribute target, along /// with its attributes. /// @@ -438,18 +450,10 @@ impl TokenStream { } pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream { - let Some(tokens) = node.tokens() else { - panic!("missing tokens for node: {:?}", node); - }; - let attrs = node.attrs(); - let attr_stream = if attrs.is_empty() { - tokens.to_attr_token_stream() - } else { - let target = - AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)]) - }; - TokenStream::new(attr_stream.to_token_trees()) + let tokens = node.tokens().unwrap_or_else(|| panic!("missing tokens for node: {:?}", node)); + let mut tts = vec![]; + attrs_and_tokens_to_token_trees(node.attrs(), tokens, &mut tts); + TokenStream::new(tts) } pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 13414f990fba..323cea1af4ac 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -283,7 +283,10 @@ impl<'a> StripUnconfigured<'a> { .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(cfg_attr, item)).collect() + expanded_attrs + .into_iter() + .map(|item| self.expand_cfg_attr_item(cfg_attr, item)) + .collect() } } From 478ba5902629b0a4dda914e81167e6b3b44c3a51 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jul 2024 16:29:48 +1000 Subject: [PATCH 203/361] Add some comments. Explaining things that took me some time to work out. --- compiler/rustc_ast/src/tokenstream.rs | 5 ++++- compiler/rustc_expand/src/config.rs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 1f69a7dc3566..a92ef575777c 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -269,11 +269,14 @@ fn attrs_and_tokens_to_token_trees( /// with its attributes. /// /// This is constructed during parsing when we need to capture -/// tokens. +/// tokens, for `cfg` and `cfg_attr` attributes. /// /// For example, `#[cfg(FALSE)] struct Foo {}` would /// have an `attrs` field containing the `#[cfg(FALSE)]` attr, /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` +/// +/// The `cfg`/`cfg_attr` processing occurs in +/// `StripUnconfigured::configure_tokens`. #[derive(Clone, Debug, Encodable, Decodable)] pub struct AttrsTarget { /// Attributes, both outer and inner. diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 323cea1af4ac..9da4aa84db52 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -187,6 +187,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .filter_map(|tree| match tree.clone() { AttrTokenTree::AttrsTarget(mut target) => { + // Expand any `cfg_attr` attributes. target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&target.attrs) { @@ -195,6 +196,8 @@ impl<'a> StripUnconfigured<'a> { ); Some(AttrTokenTree::AttrsTarget(target)) } else { + // Remove the target if there's a `cfg` attribute and + // the condition isn't satisfied. None } } From 45ad522e8745b9d2da00c56e93cca4d2f8c8fe7c Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 10 Jul 2024 15:47:24 +0200 Subject: [PATCH 204/361] Don't mark `DEBUG_EVENT` struct as `repr(packed)` That would give it alignment of 1 which is ABI-incompatible with its C definition. --- library/std/src/process/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 63455a274faa..b4f6bb71c79c 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -386,7 +386,7 @@ fn test_interior_nul_in_env_value_is_error() { fn test_creation_flags() { use crate::os::windows::process::CommandExt; use crate::sys::c::{BOOL, DWORD, INFINITE}; - #[repr(C, packed)] + #[repr(C)] struct DEBUG_EVENT { pub event_code: DWORD, pub process_id: DWORD, From a987c308cdcfc000d6980487f05222c0799c09e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Jul 2024 17:18:05 +0200 Subject: [PATCH 205/361] Fix `iter_next_loop.rs` ui test --- tests/ui/iter_next_loop.rs | 2 +- tests/ui/iter_next_loop.stderr | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/ui/iter_next_loop.rs b/tests/ui/iter_next_loop.rs index 548b799de44e..d425f4da0e81 100644 --- a/tests/ui/iter_next_loop.rs +++ b/tests/ui/iter_next_loop.rs @@ -3,7 +3,7 @@ fn main() { let x = [1, 2, 3, 4]; - for _ in vec.iter().next() {} + for _ in x.iter().next() {} struct Unrelated(&'static [u8]); impl Unrelated { diff --git a/tests/ui/iter_next_loop.stderr b/tests/ui/iter_next_loop.stderr index 85c23f4e7094..acc55031c3b2 100644 --- a/tests/ui/iter_next_loop.stderr +++ b/tests/ui/iter_next_loop.stderr @@ -1,9 +1,11 @@ -error[E0423]: expected value, found macro `vec` +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want --> tests/ui/iter_next_loop.rs:6:14 | -LL | for _ in vec.iter().next() {} - | ^^^ not a value +LL | for _ in x.iter().next() {} + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::iter-next-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0423`. From 153a3811040601703f91802b912133df7993ee69 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 16:29:05 -0400 Subject: [PATCH 206/361] Report usage of lib features in ast validation --- compiler/rustc_ast_passes/src/feature_gate.rs | 6 +++--- compiler/rustc_passes/messages.ftl | 3 --- compiler/rustc_passes/src/errors.rs | 8 -------- compiler/rustc_passes/src/stability.rs | 6 ------ 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9cf3182daea5..2178b65727d0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -607,8 +607,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) // does not check the same for lib features unless there's at least one // declared lang feature if !sess.opts.unstable_features.is_nightly_build() { - let lang_features = &features.declared_lang_features; - if lang_features.len() == 0 { + if features.declared_features.is_empty() { return; } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { @@ -624,7 +623,8 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { let name = ident.name; - let stable_since = lang_features + let stable_since = features + .declared_lang_features .iter() .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d7513fbad63c..1d93cbaddd6f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -290,9 +290,6 @@ passes_export_name = passes_extern_main = the `main` function cannot be declared in an `extern` block -passes_feature_only_on_nightly = - `#![feature]` may not be used on the {$release_channel} release channel - passes_feature_previously_declared = feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a026ff3b13b5..58d27d5b4bba 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1492,14 +1492,6 @@ pub struct TraitImplConstStable { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_feature_only_on_nightly, code = E0554)] -pub struct FeatureOnlyOnNightly { - #[primary_span] - pub span: Span, - pub release_channel: &'static str, -} - #[derive(Diagnostic)] #[diag(passes_unknown_feature, code = E0635)] pub struct UnknownFeature { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6bdfaf0c9089..2c34f477de5c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -936,12 +936,6 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let declared_lib_features = &tcx.features().declared_lib_features; let mut remaining_lib_features = FxIndexMap::default(); for (feature, span) in declared_lib_features { - if !tcx.sess.opts.unstable_features.is_nightly_build() { - tcx.dcx().emit_err(errors::FeatureOnlyOnNightly { - span: *span, - release_channel: env!("CFG_RELEASE_CHANNEL"), - }); - } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); From 00657639504230363d22b731ed15a2a80112a8b2 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 10 Jul 2024 23:21:57 +0200 Subject: [PATCH 207/361] core: Limit remaining f16 doctests to x86_64 linux On s390x, every use of the f16 data type will currently ICE due to https://github.com/llvm/llvm-project/issues/50374, causing doctest failures on the platform. Most doctests were already restricted to certain platforms, so fix this by likewise restricting the remaining five. --- library/core/src/num/f16.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e74300d6c2f3..0e54d78231da 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -353,12 +353,15 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0_f16; /// let g = -7.0_f16; /// /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); + /// # } /// ``` #[inline] #[must_use] @@ -376,12 +379,15 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0_f16; /// let g = -7.0_f16; /// /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); + /// # } /// ``` #[inline] #[must_use] @@ -694,9 +700,12 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_be_bytes(); /// assert_eq!(bytes, [0x4a, 0x40]); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] @@ -715,9 +724,12 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_le_bytes(); /// assert_eq!(bytes, [0x40, 0x4a]); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] @@ -742,6 +754,8 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_ne_bytes(); /// assert_eq!( @@ -752,6 +766,7 @@ impl f16 { /// [0x40, 0x4a] /// } /// ); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] From df72e478b0179581c985ec53ebd6a0d14a330366 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 18:55:45 -0400 Subject: [PATCH 208/361] Make sure that labels are defined after the primary span in diagnostics --- .../rustc_macros/src/diagnostics/diagnostic_builder.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 46bd80c2df64..f93d89d6c0f0 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -269,6 +269,7 @@ impl DiagnosticDeriveVariantBuilder { let field_binding = &binding_info.binding; let inner_ty = FieldInnerTy::from_type(&field.ty); + let mut seen_label = false; field .attrs @@ -280,6 +281,14 @@ impl DiagnosticDeriveVariantBuilder { } let name = attr.path().segments.last().unwrap().ident.to_string(); + + if name == "primary_span" && seen_label { + span_err(attr.span().unwrap(), format!("`#[primary_span]` must be placed before labels, since it overwrites the span of the diagnostic")).emit(); + } + if name == "label" { + seen_label = true; + } + let needs_clone = name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); let (binding, needs_destructure) = if needs_clone { From 12ae282987762a71cf146efa3fb6c6fcf4956475 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 18:55:51 -0400 Subject: [PATCH 209/361] Fix diagnostic and add a test for it --- compiler/rustc_resolve/src/errors.rs | 2 +- tests/ui/tool-attributes/invalid-tool.rs | 6 ++++++ tests/ui/tool-attributes/invalid-tool.stderr | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/ui/tool-attributes/invalid-tool.rs create mode 100644 tests/ui/tool-attributes/invalid-tool.stderr diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0620f3d709eb..cd6503ae444a 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1089,8 +1089,8 @@ pub(crate) struct ToolWasAlreadyRegistered { #[derive(Diagnostic)] #[diag(resolve_tool_only_accepts_identifiers)] pub(crate) struct ToolOnlyAcceptsIdentifiers { - #[label] #[primary_span] + #[label] pub(crate) span: Span, pub(crate) tool: Symbol, } diff --git a/tests/ui/tool-attributes/invalid-tool.rs b/tests/ui/tool-attributes/invalid-tool.rs new file mode 100644 index 000000000000..125333231d21 --- /dev/null +++ b/tests/ui/tool-attributes/invalid-tool.rs @@ -0,0 +1,6 @@ +#![feature(register_tool)] + +#![register_tool(1)] +//~^ ERROR `register_tool` only accepts identifiers + +fn main() {} diff --git a/tests/ui/tool-attributes/invalid-tool.stderr b/tests/ui/tool-attributes/invalid-tool.stderr new file mode 100644 index 000000000000..deafa6d167c2 --- /dev/null +++ b/tests/ui/tool-attributes/invalid-tool.stderr @@ -0,0 +1,8 @@ +error: `register_tool` only accepts identifiers + --> $DIR/invalid-tool.rs:3:18 + | +LL | #![register_tool(1)] + | ^ not an identifier + +error: aborting due to 1 previous error + From 27d5db166e8e640ab8317cc96b91ffe60270b6c5 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 11 Jul 2024 08:14:28 +0200 Subject: [PATCH 210/361] Allows `#[diagnostic::do_not_recommend]` to supress trait impls in suggestions as well This commit changes the error reporting mechanism for not implemented traits to skip impl marked as `#[diagnostic::do_not_recommend]` in the help part of the error message ("the following other types implement trait `Foo`:"). The main use case here is to allow crate authors to skip non-meaningful confusing suggestions. A common example for this are fully generic impls on tuples. --- .../traits/fulfillment_errors.rs | 19 ++++++++++++++ ...supress_suggestions_in_help.current.stderr | 18 +++++++++++++ .../supress_suggestions_in_help.next.stderr | 18 +++++++++++++ .../supress_suggestions_in_help.rs | 25 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs 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 f7ec5f1ff325..2e6247b46401 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 @@ -1776,6 +1776,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true }; + // we filter before checking if `impl_candidates` is empty + // to get the fallback solution if we filtered out any impls + let impl_candidates = impl_candidates + .into_iter() + .cloned() + .filter(|cand| { + !self.tcx.has_attrs_with_path( + cand.impl_def_id, + &[sym::diagnostic, sym::do_not_recommend], + ) + }) + .collect::>(); + let def_id = trait_ref.def_id(); if impl_candidates.is_empty() { if self.tcx.trait_is_auto(def_id) @@ -1788,6 +1801,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut impl_candidates: Vec<_> = self .tcx .all_impls(def_id) + // ignore `do_not_recommend` items + .filter(|def_id| { + !self + .tcx + .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend]) + }) // Ignore automatically derived impls and `!Trait` impls. .filter_map(|def_id| self.tcx.impl_trait_header(def_id)) .filter_map(|header| { diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr new file mode 100644 index 000000000000..629fc59361dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr new file mode 100644 index 000000000000..629fc59361dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs new file mode 100644 index 000000000000..ef6f255c3518 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(do_not_recommend)] + +trait Foo {} + +#[diagnostic::do_not_recommend] +impl Foo for (A,) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B, C) {} + +impl Foo for i32 {} + +fn check(a: impl Foo) {} + +fn main() { + check(()); + //~^ ERROR the trait bound `(): Foo` is not satisfied +} From ab56fe20533d843b0ad29e969c67e3e0f9c588bf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 11 Jul 2024 03:16:45 -0400 Subject: [PATCH 211/361] Rename `lazy_cell_consume` to `lazy_cell_into_inner` Name this something that is less confusable with an atomic consume API for `{Lazy,Once}Lock`. --- library/core/src/cell/lazy.rs | 4 ++-- library/std/src/sync/lazy_lock.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 7c7130ec075e..21452d40f9de 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -67,7 +67,7 @@ impl T> LazyCell { /// # Examples /// /// ``` - /// #![feature(lazy_cell_consume)] + /// #![feature(lazy_cell_into_inner)] /// /// use std::cell::LazyCell; /// @@ -78,7 +78,7 @@ impl T> LazyCell { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "125623")] + #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub fn into_inner(this: Self) -> Result { match this.state.into_inner() { State::Init(data) => Ok(data), diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index b70c041fa428..18906aceffa3 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -107,7 +107,7 @@ impl T> LazyLock { /// # Examples /// /// ``` - /// #![feature(lazy_cell_consume)] + /// #![feature(lazy_cell_into_inner)] /// /// use std::sync::LazyLock; /// @@ -118,7 +118,7 @@ impl T> LazyLock { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "125623")] + #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { From a01f49e7f32b39b77f6a5804c1ed12aadaa89ec5 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:12:00 +0400 Subject: [PATCH 212/361] check is_ident before parse_ident --- compiler/rustc_parse/src/parser/item.rs | 4 ++-- tests/ui/parser/ice-issue-127600.rs | 2 ++ tests/ui/parser/ice-issue-127600.stderr | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 tests/ui/parser/ice-issue-127600.rs create mode 100644 tests/ui/parser/ice-issue-127600.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f31e634f55c8..2c98feeece77 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -387,8 +387,8 @@ impl<'a> Parser<'a> { let span = if is_pub { self.prev_token.span.to(ident_span) } else { ident_span }; let insert_span = ident_span.shrink_to_lo(); - let ident = if (!is_const - || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis))) + let ident = if self.token.is_ident() + && (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis))) && self.look_ahead(1, |t| { [ token::Lt, diff --git a/tests/ui/parser/ice-issue-127600.rs b/tests/ui/parser/ice-issue-127600.rs new file mode 100644 index 000000000000..709c10253266 --- /dev/null +++ b/tests/ui/parser/ice-issue-127600.rs @@ -0,0 +1,2 @@ +const!(&raw mut a); +//~^ ERROR expected identifier, found `!` diff --git a/tests/ui/parser/ice-issue-127600.stderr b/tests/ui/parser/ice-issue-127600.stderr new file mode 100644 index 000000000000..629fc4ae40b6 --- /dev/null +++ b/tests/ui/parser/ice-issue-127600.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `!` + --> $DIR/ice-issue-127600.rs:1:6 + | +LL | const!(&raw mut a); + | ^ expected identifier + +error: aborting due to 1 previous error + From 8a50bcbdceacca60126c085c7cad46aced589c87 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 10 Jul 2024 17:20:21 +0200 Subject: [PATCH 213/361] Remove extern "wasm" ABI Remove the unstable `extern "wasm"` ABI (`wasm_abi` feature tracked in #83788). As discussed in https://github.com/rust-lang/rust/pull/127513#issuecomment-2220410679 and following, this ABI is a failed experiment that did not end up being used for anything. Keeping support for this ABI in LLVM 19 would require us to switch wasm targets to the `experimental-mv` ABI, which we do not want to do. It should be noted that `Abi::Wasm` was internally used for two things: The `-Z wasm-c-abi=legacy` ABI that is still used by default on some wasm targets, and the `extern "wasm"` ABI. Despite both being `Abi::Wasm` internally, they were not the same. An explicit `extern "wasm"` additionally enabled the `+multivalue` feature. I've opted to remove `Abi::Wasm` in this patch entirely, instead of keeping it as an ABI with only internal usage. Both `-Z wasm-c-abi` variants are now treated as part of the normal C ABI, just with different different treatment in adjust_for_foreign_abi. --- compiler/rustc_codegen_llvm/src/attributes.rs | 14 +-- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_middle/src/ty/layout.rs | 1 - .../rustc_smir/src/rustc_internal/internal.rs | 1 - .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 - compiler/rustc_target/src/abi/call/mod.rs | 14 +-- compiler/rustc_target/src/spec/abi/mod.rs | 26 +++--- compiler/rustc_target/src/spec/mod.rs | 17 +--- compiler/rustc_ty_utils/src/abi.rs | 3 +- compiler/stable_mir/src/ty.rs | 1 - tests/run-make/wasm-abi/foo.rs | 87 ------------------- tests/run-make/wasm-abi/host.wat | 22 ----- tests/run-make/wasm-abi/rmake.rs | 29 ------- tests/ui/abi/removed-wasm-abi.rs | 4 + tests/ui/abi/removed-wasm-abi.stderr | 12 +++ tests/ui/abi/unsupported.aarch64.stderr | 24 ++--- tests/ui/abi/unsupported.arm.stderr | 22 ++--- tests/ui/abi/unsupported.i686.stderr | 18 ++-- tests/ui/abi/unsupported.riscv32.stderr | 22 ++--- tests/ui/abi/unsupported.riscv64.stderr | 22 ++--- tests/ui/abi/unsupported.rs | 3 - tests/ui/abi/unsupported.x64.stderr | 22 ++--- .../ui/feature-gates/feature-gate-wasm_abi.rs | 26 ------ .../feature-gate-wasm_abi.stderr | 73 ---------------- 25 files changed, 87 insertions(+), 382 deletions(-) delete mode 100644 tests/run-make/wasm-abi/foo.rs delete mode 100644 tests/run-make/wasm-abi/host.wat delete mode 100644 tests/run-make/wasm-abi/rmake.rs create mode 100644 tests/ui/abi/removed-wasm-abi.rs create mode 100644 tests/ui/abi/removed-wasm-abi.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-wasm_abi.rs delete mode 100644 tests/ui/feature-gates/feature-gate-wasm_abi.stderr diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index cd82894af18e..e76694700263 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,7 +6,6 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFuncti use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; @@ -482,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( return; } - let mut function_features = function_features + let function_features = function_features .iter() .flat_map(|feat| { llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{f}")) @@ -504,17 +503,6 @@ pub fn from_fn_attrs<'ll, 'tcx>( let name = name.as_str(); to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name)); } - - // The `"wasm"` abi on wasm targets automatically enables the - // `+multivalue` feature because the purpose of the wasm abi is to match - // the WebAssembly specification, which has this feature. This won't be - // needed when LLVM enables this `multivalue` feature by default. - if !cx.tcx.is_closure_like(instance.def_id()) { - let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); - if abi == Abi::Wasm { - function_features.push("+multivalue".to_string()); - } - } } let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index aea447b2aff1..f13aa506c1ec 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -215,6 +215,9 @@ declare_features! ( /// Permits specifying whether a function should permit unwinding or abort on unwind. (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")), (removed, visible_private_types, "1.0.0", None, None), + /// Allows `extern "wasm" fn` + (removed, wasm_abi, "CURRENT_RUSTC_VERSION", Some(83788), + Some("non-standard wasm ABI is no longer supported")), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c05cac155b74..d7d994d95c51 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -640,8 +640,6 @@ declare_features! ( (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), - /// Allows `extern "wasm" fn` - (unstable, wasm_abi, "1.53.0", Some(83788)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index eb25aecd9cef..22a6786665ca 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1212,7 +1212,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | RiscvInterruptM | RiscvInterruptS | CCmseNonSecureCall - | Wasm | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 7b5abcf45130..7c3553b60fdd 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -466,7 +466,6 @@ impl RustcInternal for Abi { Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, - Abi::Wasm => rustc_target::spec::abi::Abi::Wasm, Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 9382460d6d40..ef2eb7d52eae 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -909,7 +909,6 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { abi::Abi::AvrInterrupt => Abi::AvrInterrupt, abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, - abi::Abi::Wasm => Abi::Wasm, abi::Abi::System { unwind } => Abi::System { unwind }, abi::Abi::RustIntrinsic => Abi::RustIntrinsic, abi::Abi::RustCall => Abi::RustCall, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8058130f4415..9f13c195e4ce 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -1,6 +1,6 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; -use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt}; +use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -854,7 +854,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { return Ok(()); } - match &cx.target_spec().arch[..] { + let spec = cx.target_spec(); + match &spec.arch[..] { "x86" => { let flavor = if let spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } = abi @@ -901,9 +902,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { - if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) - == spec::abi::Abi::PtxKernel - { + if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { nvptx64::compute_abi_info(self) @@ -912,13 +911,14 @@ impl<'a, Ty> FnAbi<'a, Ty> { "hexagon" => hexagon::compute_abi_info(self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), - "wasm32" | "wasm64" => { - if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm { + "wasm32" => { + if spec.os == "unknown" && cx.wasm_c_abi_opt() == WasmCAbi::Legacy { wasm::compute_wasm_abi_info(self) } else { wasm::compute_c_abi_info(cx, self) } } + "wasm64" => wasm::compute_c_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), arch => { return Err(AdjustForForeignAbiError::Unsupported { diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index bf51bb4bf825..0d61345a70e4 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -48,7 +48,6 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, - Wasm, System { unwind: bool, }, @@ -123,7 +122,6 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" }, - AbiData { abi: Abi::Wasm, name: "wasm" }, AbiData { abi: Abi::System { unwind: false }, name: "system" }, AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, @@ -149,6 +147,9 @@ pub fn lookup(name: &str) -> Result { "riscv-interrupt-u" => AbiUnsupported::Reason { explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314", }, + "wasm" => AbiUnsupported::Reason { + explain: "non-standard wasm ABI is no longer supported", + }, _ => AbiUnsupported::Unrecognized, @@ -241,10 +242,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_c_cmse_nonsecure_call, explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", }), - "wasm" => Err(AbiDisabled::Unstable { - feature: sym::wasm_abi, - explain: "wasm ABI is experimental and subject to change", - }), _ => Err(AbiDisabled::Unrecognized), } } @@ -287,16 +284,15 @@ impl Abi { AvrInterrupt => 23, AvrNonBlockingInterrupt => 24, CCmseNonSecureCall => 25, - Wasm => 26, // Cross-platform ABIs - System { unwind: false } => 27, - System { unwind: true } => 28, - RustIntrinsic => 29, - RustCall => 30, - Unadjusted => 31, - RustCold => 32, - RiscvInterruptM => 33, - RiscvInterruptS => 34, + System { unwind: false } => 26, + System { unwind: true } => 27, + RustIntrinsic => 28, + RustCall => 29, + Unadjusted => 30, + RustCold => 31, + RiscvInterruptM => 32, + RiscvInterruptS => 33, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 81ada30a5943..607eeac7ccdc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2608,22 +2608,8 @@ impl DerefMut for Target { impl Target { /// Given a function ABI, turn it into the correct ABI for this target. - pub fn adjust_abi(&self, cx: &C, abi: Abi, c_variadic: bool) -> Abi - where - C: HasWasmCAbiOpt, - { + pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi { match abi { - Abi::C { .. } => { - if self.arch == "wasm32" - && self.os == "unknown" - && cx.wasm_c_abi_opt() == WasmCAbi::Legacy - { - Abi::Wasm - } else { - abi - } - } - // On Windows, `extern "system"` behaves like msvc's `__stdcall`. // `__stdcall` only applies on x86 and on non-variadic functions: // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 @@ -2676,7 +2662,6 @@ impl Target { Msp430Interrupt => self.arch == "msp430", RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]), AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", - Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]), Thiscall { .. } => self.arch == "x86", // On windows these fall-back to platform native calling convention (C) when the // architecture is not supported. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f078cfe1b250..4eb7b58bff9f 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -324,7 +324,7 @@ fn fn_sig_for_fn_abi<'tcx>( #[inline] fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { use rustc_target::spec::abi::Abi::*; - match tcx.sess.target.adjust_abi(&tcx, abi, c_variadic) { + match tcx.sess.target.adjust_abi(abi, c_variadic) { RustIntrinsic | Rust | RustCall => Conv::Rust, // This is intentionally not using `Conv::Cold`, as that has to preserve @@ -352,7 +352,6 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }, RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }, - Wasm => Conv::C, // These API constants ought to be more specific... Cdecl { .. } => Conv::C, diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 01e4f1d1f33b..9b912d160742 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1045,7 +1045,6 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, - Wasm, System { unwind: bool }, RustIntrinsic, RustCall, diff --git a/tests/run-make/wasm-abi/foo.rs b/tests/run-make/wasm-abi/foo.rs deleted file mode 100644 index 0678eb3ff51a..000000000000 --- a/tests/run-make/wasm-abi/foo.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![crate_type = "cdylib"] -#![deny(warnings)] -#![feature(wasm_abi)] - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoI32 { - pub a: i32, - pub b: i32, -} - -#[no_mangle] -pub extern "wasm" fn return_two_i32() -> TwoI32 { - TwoI32 { a: 1, b: 2 } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoI64 { - pub a: i64, - pub b: i64, -} - -#[no_mangle] -pub extern "wasm" fn return_two_i64() -> TwoI64 { - TwoI64 { a: 3, b: 4 } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoF32 { - pub a: f32, - pub b: f32, -} - -#[no_mangle] -pub extern "wasm" fn return_two_f32() -> TwoF32 { - TwoF32 { a: 5., b: 6. } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoF64 { - pub a: f64, - pub b: f64, -} - -#[no_mangle] -pub extern "wasm" fn return_two_f64() -> TwoF64 { - TwoF64 { a: 7., b: 8. } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct Mishmash { - pub a: f64, - pub b: f32, - pub c: i32, - pub d: i64, - pub e: TwoI32, -} - -#[no_mangle] -pub extern "wasm" fn return_mishmash() -> Mishmash { - Mishmash { a: 9., b: 10., c: 11, d: 12, e: TwoI32 { a: 13, b: 14 } } -} - -#[link(wasm_import_module = "host")] -extern "wasm" { - fn two_i32() -> TwoI32; - fn two_i64() -> TwoI64; - fn two_f32() -> TwoF32; - fn two_f64() -> TwoF64; - fn mishmash() -> Mishmash; -} - -#[no_mangle] -pub unsafe extern "C" fn call_imports() { - assert_eq!(two_i32(), TwoI32 { a: 100, b: 101 }); - assert_eq!(two_i64(), TwoI64 { a: 102, b: 103 }); - assert_eq!(two_f32(), TwoF32 { a: 104., b: 105. }); - assert_eq!(two_f64(), TwoF64 { a: 106., b: 107. }); - assert_eq!( - mishmash(), - Mishmash { a: 108., b: 109., c: 110, d: 111, e: TwoI32 { a: 112, b: 113 } } - ); -} diff --git a/tests/run-make/wasm-abi/host.wat b/tests/run-make/wasm-abi/host.wat deleted file mode 100644 index e87097ac8a14..000000000000 --- a/tests/run-make/wasm-abi/host.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - (func (export "two_i32") (result i32 i32) - i32.const 100 - i32.const 101) - (func (export "two_i64") (result i64 i64) - i64.const 102 - i64.const 103) - (func (export "two_f32") (result f32 f32) - f32.const 104 - f32.const 105) - (func (export "two_f64") (result f64 f64) - f64.const 106 - f64.const 107) - - (func (export "mishmash") (result f64 f32 i32 i64 i32 i32) - f64.const 108 - f32.const 109 - i32.const 110 - i64.const 111 - i32.const 112 - i32.const 113) -) diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs deleted file mode 100644 index ff12bcd536e7..000000000000 --- a/tests/run-make/wasm-abi/rmake.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ only-wasm32-wasip1 -//@ needs-wasmtime - -use run_make_support::{cmd, rustc}; -use std::path::Path; - -fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); - - let file = Path::new("foo.wasm"); - - run(&file, "return_two_i32", "1\n2\n"); - run(&file, "return_two_i64", "3\n4\n"); - run(&file, "return_two_f32", "5\n6\n"); - run(&file, "return_two_f64", "7\n8\n"); - run(&file, "return_mishmash", "9\n10\n11\n12\n13\n14\n"); - run(&file, "call_imports", ""); -} - -fn run(file: &Path, method: &str, expected_output: &str) { - cmd("wasmtime") - .arg("run") - .arg("--preload=host=host.wat") - .arg("--invoke") - .arg(method) - .arg(file) - .run() - .assert_stdout_equals(expected_output); -} diff --git a/tests/ui/abi/removed-wasm-abi.rs b/tests/ui/abi/removed-wasm-abi.rs new file mode 100644 index 000000000000..a45e42bfe020 --- /dev/null +++ b/tests/ui/abi/removed-wasm-abi.rs @@ -0,0 +1,4 @@ +extern "wasm" fn test() {} +//~^ ERROR invalid ABI: found `wasm` + +fn main() {} diff --git a/tests/ui/abi/removed-wasm-abi.stderr b/tests/ui/abi/removed-wasm-abi.stderr new file mode 100644 index 000000000000..6007c4e25801 --- /dev/null +++ b/tests/ui/abi/removed-wasm-abi.stderr @@ -0,0 +1,12 @@ +error[E0703]: invalid ABI: found `wasm` + --> $DIR/removed-wasm-abi.rs:1:8 + | +LL | extern "wasm" fn test() {} + | ^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + = note: non-standard wasm ABI is no longer supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0703`. diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 72a9519e3e77..123e76632574 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 473b59a334df..7376bb17d6b9 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index f0af3d251e24..23b0e581887f 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,39 +1,33 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index b466a2a6ff86..708fd2c92a99 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index b466a2a6ff86..708fd2c92a99 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index cd7e76c7158f..c12883e3fce2 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -19,7 +19,6 @@ abi_ptx, abi_msp430_interrupt, abi_avr_interrupt, - wasm_abi, abi_x86_interrupt, abi_riscv_interrupt )] @@ -28,8 +27,6 @@ trait Sized {} extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI -extern "wasm" fn wasm() {} -//~^ ERROR is not a supported ABI extern "aapcs" fn aapcs() {} //[x64]~^ ERROR is not a supported ABI //[i686]~^^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 4a2b7e749692..7b918a948d3b 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.rs b/tests/ui/feature-gates/feature-gate-wasm_abi.rs deleted file mode 100644 index da1d9300a2bd..000000000000 --- a/tests/ui/feature-gates/feature-gate-wasm_abi.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ needs-llvm-components: webassembly -//@ compile-flags: --target=wasm32-unknown-unknown --crate-type=rlib -#![no_core] -#![feature(no_core, lang_items)] -#[lang="sized"] -trait Sized { } - -extern "wasm" fn fu() {} //~ ERROR wasm ABI is experimental - -trait T { - extern "wasm" fn mu(); //~ ERROR wasm ABI is experimental - extern "wasm" fn dmu() {} //~ ERROR wasm ABI is experimental -} - -struct S; -impl T for S { - extern "wasm" fn mu() {} //~ ERROR wasm ABI is experimental -} - -impl S { - extern "wasm" fn imu() {} //~ ERROR wasm ABI is experimental -} - -type TAU = extern "wasm" fn(); //~ ERROR wasm ABI is experimental - -extern "wasm" {} //~ ERROR wasm ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr b/tests/ui/feature-gates/feature-gate-wasm_abi.stderr deleted file mode 100644 index 973c42af19c5..000000000000 --- a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr +++ /dev/null @@ -1,73 +0,0 @@ -error[E0658]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:8:8 - | -LL | extern "wasm" fn fu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:11:12 - | -LL | extern "wasm" fn mu(); - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:12:12 - | -LL | extern "wasm" fn dmu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:17:12 - | -LL | extern "wasm" fn mu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:21:12 - | -LL | extern "wasm" fn imu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:24:19 - | -LL | type TAU = extern "wasm" fn(); - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:26:8 - | -LL | extern "wasm" {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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 7 previous errors - -For more information about this error, try `rustc --explain E0658`. From 08a2992d6bed7be4e673989965949b610c46e7e8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 11 Jul 2024 21:17:09 +1000 Subject: [PATCH 214/361] compiletest: Better error message for bad `normalize-*` headers --- src/tools/compiletest/src/header.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7479be90797e..7f5d4f4b4169 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -991,13 +991,19 @@ impl Config { } fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> { - if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match { - let (regex, replacement) = parse_normalize_rule(line) - .unwrap_or_else(|| panic!("couldn't parse custom normalization rule: `{line}`")); - Some((regex, replacement)) - } else { - None + let parsed = parse_cfg_name_directive(self, line, prefix); + if parsed.outcome != MatchOutcome::Match { + return None; } + let name = parsed.name.expect("successful match always has a name"); + + let Some((regex, replacement)) = parse_normalize_rule(line) else { + panic!( + "couldn't parse custom normalization rule: `{line}`\n\ + help: expected syntax is: `{prefix}-{name}: \"REGEX\" -> \"REPLACEMENT\"`" + ); + }; + Some((regex, replacement)) } fn parse_name_directive(&self, line: &str, directive: &str) -> bool { From 3b1266cd312bb58dc2e09edbcabd27b5b7fe7d69 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Jul 2024 15:29:22 +0200 Subject: [PATCH 215/361] Bump nightly version -> 2024-07-11 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 52e8831eeb3a..a61c22c59f98 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-06-27" +channel = "nightly-2024-07-11" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From f56b2074c688f09be47e6ca82f604eabaa0b8f35 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 11 Jul 2024 15:39:17 +0200 Subject: [PATCH 216/361] solve -> solve/mod --- compiler/rustc_type_ir/src/{solve.rs => solve/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename compiler/rustc_type_ir/src/{solve.rs => solve/mod.rs} (100%) diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve/mod.rs similarity index 100% rename from compiler/rustc_type_ir/src/solve.rs rename to compiler/rustc_type_ir/src/solve/mod.rs From 977439d9b8c6f42cdccb40dab94f7328cfa9d022 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 19 Jun 2024 21:23:40 +0200 Subject: [PATCH 217/361] Use uplifted `rustc-stable-hash` crate in `rustc_data_structures` --- Cargo.lock | 7 + compiler/rustc_data_structures/Cargo.toml | 1 + .../rustc_data_structures/src/fingerprint.rs | 9 +- compiler/rustc_data_structures/src/hashes.rs | 17 +- compiler/rustc_data_structures/src/lib.rs | 2 - compiler/rustc_data_structures/src/sip128.rs | 505 ------------------ .../rustc_data_structures/src/sip128/tests.rs | 304 ----------- .../src/stable_hasher.rs | 162 +----- .../src/stable_hasher/tests.rs | 65 --- .../src/tagged_ptr/copy/tests.rs | 6 +- src/tools/tidy/src/deps.rs | 1 + 11 files changed, 30 insertions(+), 1049 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/sip128.rs delete mode 100644 compiler/rustc_data_structures/src/sip128/tests.rs diff --git a/Cargo.lock b/Cargo.lock index afeb9faec097..eba4eed3686b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3514,6 +3514,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" +[[package]] +name = "rustc-stable-hash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2" + [[package]] name = "rustc-std-workspace-alloc" version = "1.99.0" @@ -3852,6 +3858,7 @@ dependencies = [ "portable-atomic", "rustc-hash", "rustc-rayon", + "rustc-stable-hash", "rustc_arena", "rustc_graphviz", "rustc_index", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c4b2e067bbeb..e5e733439ea0 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "11" rustc-hash = "1.1.0" rustc-rayon = { version = "0.5.0", optional = true } +rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_index = { path = "../rustc_index", package = "rustc_index" } diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 1bee159489dc..30e3d6aa86ce 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -1,5 +1,5 @@ use crate::stable_hasher::impl_stable_traits_for_trivial_type; -use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult}; +use crate::stable_hasher::{FromStableHash, Hash64, StableHasherHash}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::hash::{Hash, Hasher}; @@ -154,10 +154,11 @@ impl FingerprintHasher for crate::unhash::Unhasher { } } -impl StableHasherResult for Fingerprint { +impl FromStableHash for Fingerprint { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); + fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self { Fingerprint(_0, _1) } } diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs index 1564eeb4baee..ef5d2e845ef0 100644 --- a/compiler/rustc_data_structures/src/hashes.rs +++ b/compiler/rustc_data_structures/src/hashes.rs @@ -11,7 +11,7 @@ //! connect the fact that they can only be produced by a `StableHasher` to their //! `Encode`/`Decode` impls. -use crate::stable_hasher::{StableHasher, StableHasherResult}; +use crate::stable_hasher::{FromStableHash, StableHasherHash}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::ops::BitXorAssign; @@ -56,10 +56,12 @@ impl Decodable for Hash64 { } } -impl StableHasherResult for Hash64 { +impl FromStableHash for Hash64 { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - Self { inner: hasher.finalize().0 } + fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self { + Self { inner: _0 } } } @@ -121,10 +123,11 @@ impl Decodable for Hash128 { } } -impl StableHasherResult for Hash128 { +impl FromStableHash for Hash128 { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); + fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self { Self { inner: u128::from(_0) | (u128::from(_1) << 64) } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 356ddf014bee..3f18b036940b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -24,7 +24,6 @@ #![feature(core_intrinsics)] #![feature(extend_one)] #![feature(hash_raw_entry)] -#![feature(hasher_prefixfree_extras)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -67,7 +66,6 @@ pub mod owned_slice; pub mod packed; pub mod profiling; pub mod sharded; -pub mod sip128; pub mod small_c_str; pub mod snapshot_map; pub mod sorted_map; diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs deleted file mode 100644 index 812ed410a94b..000000000000 --- a/compiler/rustc_data_structures/src/sip128.rs +++ /dev/null @@ -1,505 +0,0 @@ -//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes. - -// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. -// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 -use rustc_serialize::int_overflow::{DebugStrictAdd, DebugStrictSub}; -use std::hash::Hasher; -use std::mem::{self, MaybeUninit}; -use std::ptr; - -#[cfg(test)] -mod tests; - -// The SipHash algorithm operates on 8-byte chunks. -const ELEM_SIZE: usize = mem::size_of::(); - -// Size of the buffer in number of elements, not including the spill. -// -// The selection of this size was guided by rustc-perf benchmark comparisons of -// different buffer sizes. It should be periodically reevaluated as the compiler -// implementation and input characteristics change. -// -// Using the same-sized buffer for everything we hash is a performance versus -// complexity tradeoff. The ideal buffer size, and whether buffering should even -// be used, depends on what is being hashed. It may be worth it to size the -// buffer appropriately (perhaps by making SipHasher128 generic over the buffer -// size) or disable buffering depending on what is being hashed. But at this -// time, we use the same buffer size for everything. -const BUFFER_CAPACITY: usize = 8; - -// Size of the buffer in bytes, not including the spill. -const BUFFER_SIZE: usize = BUFFER_CAPACITY * ELEM_SIZE; - -// Size of the buffer in number of elements, including the spill. -const BUFFER_WITH_SPILL_CAPACITY: usize = BUFFER_CAPACITY + 1; - -// Size of the buffer in bytes, including the spill. -const BUFFER_WITH_SPILL_SIZE: usize = BUFFER_WITH_SPILL_CAPACITY * ELEM_SIZE; - -// Index of the spill element in the buffer. -const BUFFER_SPILL_INDEX: usize = BUFFER_WITH_SPILL_CAPACITY - 1; - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct SipHasher128 { - // The access pattern during hashing consists of accesses to `nbuf` and - // `buf` until the buffer is full, followed by accesses to `state` and - // `processed`, and then repetition of that pattern until hashing is done. - // This is the basis for the ordering of fields below. However, in practice - // the cache miss-rate for data access is extremely low regardless of order. - nbuf: usize, // how many bytes in buf are valid - buf: [MaybeUninit; BUFFER_WITH_SPILL_CAPACITY], // unprocessed bytes le - state: State, // hash State - processed: usize, // how many bytes we've processed -} - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -struct State { - // v0, v2 and v1, v3 show up in pairs in the algorithm, - // and simd implementations of SipHash will use vectors - // of v02 and v13. By placing them in this order in the struct, - // the compiler can pick up on just a few simd optimizations by itself. - v0: u64, - v2: u64, - v1: u64, - v3: u64, -} - -macro_rules! compress { - ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }}; - ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ - $v0 = $v0.wrapping_add($v1); - $v2 = $v2.wrapping_add($v3); - $v1 = $v1.rotate_left(13); - $v1 ^= $v0; - $v3 = $v3.rotate_left(16); - $v3 ^= $v2; - $v0 = $v0.rotate_left(32); - - $v2 = $v2.wrapping_add($v1); - $v0 = $v0.wrapping_add($v3); - $v1 = $v1.rotate_left(17); - $v1 ^= $v2; - $v3 = $v3.rotate_left(21); - $v3 ^= $v0; - $v2 = $v2.rotate_left(32); - }}; -} - -// Copies up to 8 bytes from source to destination. This performs better than -// `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real -// workloads since all of the copies have fixed sizes and avoid calling memcpy. -// -// This is specifically designed for copies of up to 8 bytes, because that's the -// maximum of number bytes needed to fill an 8-byte-sized element on which -// SipHash operates. Note that for variable-sized copies which are known to be -// less than 8 bytes, this function will perform more work than necessary unless -// the compiler is able to optimize the extra work away. -#[inline] -unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { - debug_assert!(count <= 8); - - unsafe { - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); - return; - } - - let mut i = 0; - if i.debug_strict_add(3) < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i = i.debug_strict_add(4); - } - - if i.debug_strict_add(1) < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i = i.debug_strict_add(2) - } - - if i < count { - *dst.add(i) = *src.add(i); - i = i.debug_strict_add(1); - } - - debug_assert_eq!(i, count); - } -} - -// # Implementation -// -// This implementation uses buffering to reduce the hashing cost for inputs -// consisting of many small integers. Buffering simplifies the integration of -// integer input--the integer write function typically just appends to the -// buffer with a statically sized write, updates metadata, and returns. -// -// Buffering also prevents alternating between writes that do and do not trigger -// the hashing process. Only when the entire buffer is full do we transition -// into hashing. This allows us to keep the hash state in registers for longer, -// instead of loading and storing it before and after processing each element. -// -// When a write fills the buffer, a buffer processing function is invoked to -// hash all of the buffered input. The buffer processing functions are marked -// `#[inline(never)]` so that they aren't inlined into the append functions, -// which ensures the more frequently called append functions remain inlineable -// and don't include register pushing/popping that would only be made necessary -// by inclusion of the complex buffer processing path which uses those -// registers. -// -// The buffer includes a "spill"--an extra element at the end--which simplifies -// the integer write buffer processing path. The value that fills the buffer can -// be written with a statically sized write that may spill over into the spill. -// After the buffer is processed, the part of the value that spilled over can be -// written from the spill to the beginning of the buffer with another statically -// sized write. This write may copy more bytes than actually spilled over, but -// we maintain the metadata such that any extra copied bytes will be ignored by -// subsequent processing. Due to the static sizes, this scheme performs better -// than copying the exact number of bytes needed into the end and beginning of -// the buffer. -// -// The buffer is uninitialized, which improves performance, but may preclude -// efficient implementation of alternative approaches. The improvement is not so -// large that an alternative approach should be disregarded because it cannot be -// efficiently implemented with an uninitialized buffer. On the other hand, an -// uninitialized buffer may become more important should a larger one be used. -// -// # Platform Dependence -// -// The SipHash algorithm operates on byte sequences. It parses the input stream -// as 8-byte little-endian integers. Therefore, given the same byte sequence, it -// produces the same result on big- and little-endian hardware. -// -// However, the Hasher trait has methods which operate on multi-byte integers. -// How they are converted into byte sequences can be endian-dependent (by using -// native byte order) or independent (by consistently using either LE or BE byte -// order). It can also be `isize` and `usize` size dependent (by using the -// native size), or independent (by converting to a common size), supposing the -// values can be represented in 32 bits. -// -// In order to make `SipHasher128` consistent with `SipHasher` in libstd, we -// choose to do the integer to byte sequence conversion in the platform- -// dependent way. Clients can achieve platform-independent hashing by widening -// `isize` and `usize` integers to 64 bits on 32-bit systems and byte-swapping -// integers on big-endian systems before passing them to the writing functions. -// This causes the input byte sequence to look identical on big- and little- -// endian systems (supposing `isize` and `usize` values can be represented in 32 -// bits), which ensures platform-independent results. -impl SipHasher128 { - #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { - let mut hasher = SipHasher128 { - nbuf: 0, - buf: [MaybeUninit::uninit(); BUFFER_WITH_SPILL_CAPACITY], - state: State { - v0: key0 ^ 0x736f6d6570736575, - // The XOR with 0xee is only done on 128-bit algorithm version. - v1: key1 ^ (0x646f72616e646f6d ^ 0xee), - v2: key0 ^ 0x6c7967656e657261, - v3: key1 ^ 0x7465646279746573, - }, - processed: 0, - }; - - unsafe { - // Initialize spill because we read from it in `short_write_process_buffer`. - *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); - } - - hasher - } - - #[inline] - pub fn short_write(&mut self, bytes: [u8; LEN]) { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - if nbuf.debug_strict_add(LEN) < BUFFER_SIZE { - unsafe { - // The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - } - - self.nbuf = nbuf.debug_strict_add(LEN); - - return; - } - - unsafe { self.short_write_process_buffer(bytes) } - } - - // A specialized write function for values with size <= 8 that should only - // be called when the write would cause the buffer to fill. - // - // SAFETY: the write of `x` into `self.buf` starting at byte offset - // `self.nbuf` must cause `self.buf` to become fully initialized (and not - // overflow) if it wasn't already. - #[inline(never)] - unsafe fn short_write_process_buffer(&mut self, bytes: [u8; LEN]) { - unsafe { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN >= BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - // Copy first part of input into end of buffer, possibly into spill - // element. The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - - // Process buffer. - for i in 0..BUFFER_CAPACITY { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Copy remaining input into start of buffer by copying LEN - 1 - // elements from spill (at most LEN - 1 bytes could have overflowed - // into the spill). The memcpy call is optimized away because the size - // is known. And the whole copy is optimized away for LEN == 1. - let dst = self.buf.as_mut_ptr() as *mut u8; - let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, dst, LEN - 1); - - // This function should only be called when the write fills the buffer. - // Therefore, when LEN == 1, the new `self.nbuf` must be zero. - // LEN is statically known, so the branch is optimized away. - self.nbuf = - if LEN == 1 { 0 } else { nbuf.debug_strict_add(LEN).debug_strict_sub(BUFFER_SIZE) }; - self.processed = self.processed.debug_strict_add(BUFFER_SIZE); - } - } - - // A write function for byte slices. - #[inline] - fn slice_write(&mut self, msg: &[u8]) { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - - if nbuf.debug_strict_add(length) < BUFFER_SIZE { - unsafe { - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - - if length <= 8 { - copy_nonoverlapping_small(msg.as_ptr(), dst, length); - } else { - // This memcpy is *not* optimized away. - ptr::copy_nonoverlapping(msg.as_ptr(), dst, length); - } - } - - self.nbuf = nbuf.debug_strict_add(length); - - return; - } - - unsafe { self.slice_write_process_buffer(msg) } - } - - // A write function for byte slices that should only be called when the - // write would cause the buffer to fill. - // - // SAFETY: `self.buf` must be initialized up to the byte offset `self.nbuf`, - // and `msg` must contain enough bytes to initialize the rest of the element - // containing the byte offset `self.nbuf`. - #[inline(never)] - unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { - unsafe { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + length >= BUFFER_SIZE); - - // Always copy first part of input into current element of buffer. - // This function should only be called when the write fills the buffer, - // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE.debug_strict_sub(valid_in_elem); - - let src = msg.as_ptr(); - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - copy_nonoverlapping_small(src, dst, needed_in_elem); - - // Process buffer. - - // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / - // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. - // We know that is true, because last step ensured we have a full - // element in the buffer. - let last = (nbuf / ELEM_SIZE).debug_strict_add(1); - - for i in 0..last { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Process the remaining element-sized chunks of input. - let mut processed = needed_in_elem; - let input_left = length.debug_strict_sub(processed); - let elems_left = input_left / ELEM_SIZE; - let extra_bytes_left = input_left % ELEM_SIZE; - - for _ in 0..elems_left { - let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - processed = processed.debug_strict_add(ELEM_SIZE); - } - - // Copy remaining input into start of buffer. - let src = msg.as_ptr().add(processed); - let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, extra_bytes_left); - - self.nbuf = extra_bytes_left; - self.processed = self.processed.debug_strict_add(nbuf.debug_strict_add(processed)); - } - } - - #[inline] - pub fn finish128(mut self) -> (u64, u64) { - debug_assert!(self.nbuf < BUFFER_SIZE); - - // Process full elements in buffer. - let last = self.nbuf / ELEM_SIZE; - - // Since we're consuming self, avoid updating members for a potential - // performance gain. - let mut state = self.state; - - for i in 0..last { - let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() }; - state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= elem; - } - - // Get remaining partial element. - let elem = if self.nbuf % ELEM_SIZE != 0 { - unsafe { - // Ensure element is initialized by writing zero bytes. At most - // `ELEM_SIZE - 1` are required given the above check. It's safe - // to write this many because we have the spill and we maintain - // `self.nbuf` such that this write will start before the spill. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf); - ptr::write_bytes(dst, 0, ELEM_SIZE - 1); - self.buf.get_unchecked(last).assume_init().to_le() - } - } else { - 0 - }; - - // Finalize the hash. - let length = self.processed.debug_strict_add(self.nbuf); - let b: u64 = ((length as u64 & 0xff) << 56) | elem; - - state.v3 ^= b; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= b; - - state.v2 ^= 0xee; - Sip13Rounds::d_rounds(&mut state); - let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - state.v1 ^= 0xdd; - Sip13Rounds::d_rounds(&mut state); - let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - (_0, _1) - } -} - -impl Hasher for SipHasher128 { - #[inline] - fn write_u8(&mut self, i: u8) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.short_write((i as u8).to_ne_bytes()); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.short_write((i as u16).to_ne_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.short_write((i as u32).to_ne_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.short_write((i as u64).to_ne_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - self.short_write((i as usize).to_ne_bytes()); - } - - #[inline] - fn write(&mut self, msg: &[u8]) { - self.slice_write(msg); - } - - #[inline] - fn write_str(&mut self, s: &str) { - // This hasher works byte-wise, and `0xFF` cannot show up in a `str`, - // so just hashing the one extra byte is enough to be prefix-free. - self.write(s.as_bytes()); - self.write_u8(0xFF); - } - - fn finish(&self) -> u64 { - panic!("SipHasher128 cannot provide valid 64 bit hashes") - } -} - -#[derive(Debug, Clone, Default)] -struct Sip13Rounds; - -impl Sip13Rounds { - #[inline] - fn c_rounds(state: &mut State) { - compress!(state); - } - - #[inline] - fn d_rounds(state: &mut State) { - compress!(state); - compress!(state); - compress!(state); - } -} diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs deleted file mode 100644 index e9dd0f1176b9..000000000000 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ /dev/null @@ -1,304 +0,0 @@ -use super::*; - -use std::hash::Hash; - -// Hash just the bytes of the slice, without length prefix -struct Bytes<'a>(&'a [u8]); - -impl<'a> Hash for Bytes<'a> { - #[allow(unused_must_use)] - fn hash(&self, state: &mut H) { - for byte in self.0 { - state.write_u8(*byte); - } - } -} - -fn hash_with(mut st: SipHasher128, x: &T) -> (u64, u64) { - x.hash(&mut st); - st.finish128() -} - -fn hash(x: &T) -> (u64, u64) { - hash_with(SipHasher128::new_with_keys(0, 0), x) -} -#[rustfmt::skip] -const TEST_VECTOR: [[u8; 16]; 64] = [ - [0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01], - [0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63], - [0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95], - [0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43], - [0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25], - [0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e], - [0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8], - [0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77], - [0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99], - [0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42], - [0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4], - [0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e], - [0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65], - [0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44], - [0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78], - [0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09], - [0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93], - [0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec], - [0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b], - [0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9], - [0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7], - [0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef], - [0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79], - [0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59], - [0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a], - [0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2], - [0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64], - [0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93], - [0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14], - [0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86], - [0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06], - [0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10], - [0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3], - [0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b], - [0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9], - [0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f], - [0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40], - [0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10], - [0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93], - [0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c], - [0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38], - [0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3], - [0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02], - [0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56], - [0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a], - [0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58], - [0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8], - [0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37], - [0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08], - [0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f], - [0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66], - [0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a], - [0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca], - [0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b], - [0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b], - [0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22], - [0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84], - [0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10], - [0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69], - [0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e], - [0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61], - [0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7], - [0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18], - [0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad], -]; - -#[test] -fn test_siphash_1_3_test_vector() { - let k0 = 0x_07_06_05_04_03_02_01_00; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; - - let mut input: Vec = Vec::new(); - - for i in 0..64 { - let out = hash_with(SipHasher128::new_with_keys(k0, k1), &Bytes(&input[..])); - let expected = ( - ((TEST_VECTOR[i][0] as u64) << 0) - | ((TEST_VECTOR[i][1] as u64) << 8) - | ((TEST_VECTOR[i][2] as u64) << 16) - | ((TEST_VECTOR[i][3] as u64) << 24) - | ((TEST_VECTOR[i][4] as u64) << 32) - | ((TEST_VECTOR[i][5] as u64) << 40) - | ((TEST_VECTOR[i][6] as u64) << 48) - | ((TEST_VECTOR[i][7] as u64) << 56), - ((TEST_VECTOR[i][8] as u64) << 0) - | ((TEST_VECTOR[i][9] as u64) << 8) - | ((TEST_VECTOR[i][10] as u64) << 16) - | ((TEST_VECTOR[i][11] as u64) << 24) - | ((TEST_VECTOR[i][12] as u64) << 32) - | ((TEST_VECTOR[i][13] as u64) << 40) - | ((TEST_VECTOR[i][14] as u64) << 48) - | ((TEST_VECTOR[i][15] as u64) << 56), - ); - - assert_eq!(out, expected); - input.push(i as u8); - } -} - -#[test] -#[cfg(target_arch = "arm")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86_64")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as usize))); - assert!(hash(&(val as u32)) != hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} - -#[test] -fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); -} - -#[test] -fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - assert!(hash(&val) != hash(&zero_byte(val, 4))); - assert!(hash(&val) != hash(&zero_byte(val, 5))); - assert!(hash(&val) != hash(&zero_byte(val, 6))); - assert!(hash(&val) != hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: usize) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: usize) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert!(s != t && t != u); - assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - - let u = [1, 0, 0, 0]; - let v = (&u[..1], &u[1..3], &u[3..]); - let w = (&u[..], &u[4..4], &u[4..4]); - - assert!(v != w); - assert!(hash(&v) != hash(&w)); -} - -#[test] -fn test_short_write_works() { - let test_u8 = 0xFF_u8; - let test_u16 = 0x1122_u16; - let test_u32 = 0x22334455_u32; - let test_u64 = 0x33445566_778899AA_u64; - let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -1_i8; - let test_i16 = -2_i16; - let test_i32 = -3_i32; - let test_i64 = -4_i64; - let test_i128 = -5_i128; - let test_isize = -6_isize; - - let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write(b"bytes"); - h1.write(b"string"); - h1.write_u8(test_u8); - h1.write_u16(test_u16); - h1.write_u32(test_u32); - h1.write_u64(test_u64); - h1.write_u128(test_u128); - h1.write_usize(test_usize); - h1.write_i8(test_i8); - h1.write_i16(test_i16); - h1.write_i32(test_i32); - h1.write_i64(test_i64); - h1.write_i128(test_i128); - h1.write_isize(test_isize); - - let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(b"bytes"); - h2.write(b"string"); - h2.write(&test_u8.to_ne_bytes()); - h2.write(&test_u16.to_ne_bytes()); - h2.write(&test_u32.to_ne_bytes()); - h2.write(&test_u64.to_ne_bytes()); - h2.write(&test_u128.to_ne_bytes()); - h2.write(&test_usize.to_ne_bytes()); - h2.write(&test_i8.to_ne_bytes()); - h2.write(&test_i16.to_ne_bytes()); - h2.write(&test_i32.to_ne_bytes()); - h2.write(&test_i64.to_ne_bytes()); - h2.write(&test_i128.to_ne_bytes()); - h2.write(&test_isize.to_ne_bytes()); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); -} - -macro_rules! test_fill_buffer { - ($type:ty, $write_method:ident) => {{ - // Test filling and overfilling the buffer from all possible offsets - // for a given integer type and its corresponding write method. - const SIZE: usize = std::mem::size_of::<$type>(); - let input = [42; BUFFER_SIZE]; - let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type; - let x_bytes = &x.to_ne_bytes(); - - for i in 1..=SIZE { - let s = &input[..BUFFER_SIZE - i]; - - let mut h1 = SipHasher128::new_with_keys(7, 13); - h1.write(s); - h1.$write_method(x); - - let mut h2 = SipHasher128::new_with_keys(7, 13); - h2.write(s); - h2.write(x_bytes); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); - } - }}; -} - -#[test] -fn test_fill_buffer() { - test_fill_buffer!(u8, write_u8); - test_fill_buffer!(u16, write_u16); - test_fill_buffer!(u32, write_u32); - test_fill_buffer!(u64, write_u64); - test_fill_buffer!(u128, write_u128); - test_fill_buffer!(usize, write_usize); - - test_fill_buffer!(i8, write_i8); - test_fill_buffer!(i16, write_i16); - test_fill_buffer!(i32, write_i32); - test_fill_buffer!(i64, write_i64); - test_fill_buffer!(i128, write_i128); - test_fill_buffer!(isize, write_isize); -} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index a57f5067dd8d..83883eeba9ca 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -1,8 +1,6 @@ -use crate::sip128::SipHasher128; use rustc_index::bit_set::{self, BitSet}; use rustc_index::{Idx, IndexSlice, IndexVec}; use smallvec::SmallVec; -use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; use std::marker::PhantomData; use std::mem; @@ -13,163 +11,9 @@ mod tests; pub use crate::hashes::{Hash128, Hash64}; -/// When hashing something that ends up affecting properties like symbol names, -/// we want these symbol names to be calculated independently of other factors -/// like what architecture you're compiling *from*. -/// -/// To that end we always convert integers to little-endian format before -/// hashing and the architecture dependent `isize` and `usize` types are -/// extended to 64 bits if needed. -pub struct StableHasher { - state: SipHasher128, -} - -impl fmt::Debug for StableHasher { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.state) - } -} - -pub trait StableHasherResult: Sized { - fn finish(hasher: StableHasher) -> Self; -} - -impl StableHasher { - #[inline] - pub fn new() -> Self { - StableHasher { state: SipHasher128::new_with_keys(0, 0) } - } - - #[inline] - pub fn finish(self) -> W { - W::finish(self) - } -} - -impl StableHasher { - #[inline] - pub fn finalize(self) -> (u64, u64) { - self.state.finish128() - } -} - -impl Hasher for StableHasher { - fn finish(&self) -> u64 { - panic!("use StableHasher::finalize instead"); - } - - #[inline] - fn write(&mut self, bytes: &[u8]) { - self.state.write(bytes); - } - - #[inline] - fn write_str(&mut self, s: &str) { - self.state.write_str(s); - } - - #[inline] - fn write_length_prefix(&mut self, len: usize) { - // Our impl for `usize` will extend it if needed. - self.write_usize(len); - } - - #[inline] - fn write_u8(&mut self, i: u8) { - self.state.write_u8(i); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u128(&mut self, i: u128) { - self.write_u64(i as u64); - self.write_u64((i >> 64) as u64); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - // Always treat usize as u64 so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.state.write_i8(i); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.state.short_write((i as u16).to_le_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.state.short_write((i as u32).to_le_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i128(&mut self, i: i128) { - self.state.write(&(i as u128).to_le_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. Sign extending here is preferable as it means that the - // same negative number hashes the same on both 32 and 64 bit platforms. - let value = i as u64; - - // Cold path - #[cold] - #[inline(never)] - fn hash_value(state: &mut SipHasher128, value: u64) { - state.write_u8(0xFF); - state.short_write(value.to_le_bytes()); - } - - // `isize` values often seem to have a small (positive) numeric value in practice. - // To exploit this, if the value is small, we will hash a smaller amount of bytes. - // However, we cannot just skip the leading zero bytes, as that would produce the same hash - // e.g. if you hash two values that have the same bit pattern when they are swapped. - // See https://github.com/rust-lang/rust/pull/93014 for context. - // - // Therefore, we employ the following strategy: - // 1) When we encounter a value that fits within a single byte (the most common case), we - // hash just that byte. This is the most common case that is being optimized. However, we do - // not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8). - // 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding - // 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two - // `isize`s that fit within a different amount of bytes, they should always produce a different - // byte stream for the hasher. - if value < 0xFF { - self.state.write_u8(value as u8); - } else { - hash_value(&mut self.state, value); - } - } -} +pub use rustc_stable_hash::FromStableHash; +pub use rustc_stable_hash::SipHasher128Hash as StableHasherHash; +pub use rustc_stable_hash::StableSipHasher128 as StableHasher; /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index c8921f6a7784..aab50a13af0e 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -7,71 +7,6 @@ use super::*; // ways). The expected values depend on the hashing algorithm used, so they // need to be updated whenever StableHasher changes its hashing algorithm. -#[test] -fn test_hash_integers() { - // Test that integers are handled consistently across platforms. - let test_u8 = 0xAB_u8; - let test_u16 = 0xFFEE_u16; - let test_u32 = 0x445577AA_u32; - let test_u64 = 0x01234567_13243546_u64; - let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -100_i8; - let test_i16 = -200_i16; - let test_i32 = -300_i32; - let test_i64 = -400_i64; - let test_i128 = -500_i128; - let test_isize = -600_isize; - - let mut h = StableHasher::new(); - test_u8.hash(&mut h); - test_u16.hash(&mut h); - test_u32.hash(&mut h); - test_u64.hash(&mut h); - test_u128.hash(&mut h); - test_usize.hash(&mut h); - test_i8.hash(&mut h); - test_i16.hash(&mut h); - test_i32.hash(&mut h); - test_i64.hash(&mut h); - test_i128.hash(&mut h); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (13997337031081104755, 6178945012502239489); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_usize() { - // Test that usize specifically is handled consistently across platforms. - let test_usize = 0xABCDEF01_usize; - - let mut h = StableHasher::new(); - test_usize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (12037165114281468837, 3094087741167521712); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_isize() { - // Test that isize specifically is handled consistently across platforms. - let test_isize = -7_isize; - - let mut h = StableHasher::new(); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (3979067582695659080, 2322428596355037273); - - assert_eq!(h.finalize(), expected); -} - fn hash>(t: &T) -> Hash128 { let mut h = StableHasher::new(); let ctx = &mut (); diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs index bfcc2e603de4..160af8a65d9c 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs @@ -1,5 +1,6 @@ use std::ptr; +use crate::hashes::Hash128; use crate::stable_hasher::{HashStable, StableHasher}; use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2}; @@ -31,14 +32,13 @@ fn stable_hash_hashes_as_tuple() { let hash_packed = { let mut hasher = StableHasher::new(); tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - - hasher.finalize() + hasher.finish::() }; let hash_tupled = { let mut hasher = StableHasher::new(); (&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - hasher.finalize() + hasher.finish::() }; assert_eq!(hash_packed, hash_tupled); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 82fa43f581fd..3c72fae0881e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -353,6 +353,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-hash", "rustc-rayon", "rustc-rayon-core", + "rustc-stable-hash", "rustc_apfloat", "rustc_version", "rustix", From 55256c5a183c175a38ee83def7314bf3ad440253 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 10 Jul 2024 15:44:09 +0000 Subject: [PATCH 218/361] Update dist-riscv64-linux to binutils 2.40 binutils 2.40 is required by LLVM 19, as older versions do not know about the zmmull extension. I've had to backport some patches to glibc and gcc as well, as they don't build with binutils 2.40. Alternatively, we could also switch to glibc 2.35 and gcc 12 (I think). I figured we'd want to avoid the glibc version change, but if that's fine for riscv I can go with that instead. --- .../host-x86_64/dist-riscv64-linux/Dockerfile | 1 + .../gcc/8.5.0/0001-divdi3-div-zero.patch | 37 ++++++ .../gcc/8.5.0/0002-hidden-jump-target.patch | 117 ++++++++++++++++++ .../glibc/2.29/0001-hidden-jump-target.patch | 58 +++++++++ .../riscv64-unknown-linux-gnu.defconfig | 4 +- 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch create mode 100644 src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch create mode 100644 src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile index 426e601f5d34..4d9334dde8c5 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile @@ -11,6 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-riscv64-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch new file mode 100644 index 000000000000..f688eaf8029e --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch @@ -0,0 +1,37 @@ +From 4013baf99c38f7bca06a51f8301e8fb195ccfa33 Mon Sep 17 00:00:00 2001 +From: Jim Wilson +Date: Tue, 2 Jun 2020 11:19:39 -0700 +Subject: [PATCH] RISC-V: Make __divdi3 handle div by zero same as hardware. + +The ISA manual specifies that divide by zero always returns -1 as the result. +We were failing to do that when the dividend was negative. + +Original patch from Virginie Moser. + + libgcc/ + * config/riscv/div.S (__divdi3): For negative arguments, change bgez + to bgtz. +--- + libgcc/config/riscv/div.S | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S +index 151f8e273ac77..17234324c1e41 100644 +--- a/libgcc/config/riscv/div.S ++++ b/libgcc/config/riscv/div.S +@@ -107,10 +107,12 @@ FUNC_END (__umoddi3) + /* Handle negative arguments to __divdi3. */ + .L10: + neg a0, a0 +- bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ ++ /* Zero is handled as a negative so that the result will not be inverted. */ ++ bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ ++ + neg a1, a1 +- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ +-.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ ++ j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ ++.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ + neg a1, a1 + .L12: + move t0, ra diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch new file mode 100644 index 000000000000..7ae4469428b1 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch @@ -0,0 +1,117 @@ +From 45116f342057b7facecd3d05c2091ce3a77eda59 Mon Sep 17 00:00:00 2001 +From: Nelson Chu +Date: Mon, 29 Nov 2021 04:48:20 -0800 +Subject: [PATCH] RISC-V: jal cannot refer to a default visibility symbol for + shared object. + +This is the original binutils bugzilla report, +https://sourceware.org/bugzilla/show_bug.cgi?id=28509 + +And this is the first version of the proposed binutils patch, +https://sourceware.org/pipermail/binutils/2021-November/118398.html + +After applying the binutils patch, I get the the unexpected error when +building libgcc, + +/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42: +/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC + +Therefore, this patch add an extra hidden alias symbol for __udivdi3, and +then use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. +The solution is similar to glibc as follows, +https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b + +libgcc/ChangeLog: + + * config/riscv/div.S: Add the hidden alias symbol for __udivdi3, and + then use HIDDEN_JUMPTARGET to target it since it is non-preemptible. + * config/riscv/riscv-asm.h: Added new macros HIDDEN_JUMPTARGET and + HIDDEN_DEF. +--- + libgcc/config/riscv/div.S | 15 ++++++++------- + libgcc/config/riscv/riscv-asm.h | 6 ++++++ + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S +index c9bd7879c1e36..723c3b82e48c6 100644 +--- a/libgcc/config/riscv/div.S ++++ b/libgcc/config/riscv/div.S +@@ -40,7 +40,7 @@ FUNC_BEGIN (__udivsi3) + sll a0, a0, 32 + sll a1, a1, 32 + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + sext.w a0, a0 + jr t0 + FUNC_END (__udivsi3) +@@ -52,7 +52,7 @@ FUNC_BEGIN (__umodsi3) + srl a0, a0, 32 + srl a1, a1, 32 + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + sext.w a0, a1 + jr t0 + FUNC_END (__umodsi3) +@@ -95,11 +95,12 @@ FUNC_BEGIN (__udivdi3) + .L5: + ret + FUNC_END (__udivdi3) ++HIDDEN_DEF (__udivdi3) + + FUNC_BEGIN (__umoddi3) + /* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */ + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + move a0, a1 + jr t0 + FUNC_END (__umoddi3) +@@ -111,12 +112,12 @@ FUNC_END (__umoddi3) + bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ + + neg a1, a1 +- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ ++ j HIDDEN_JUMPTARGET(__udivdi3) /* Compute __udivdi3(-a0, -a1). */ + .L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ + neg a1, a1 + .L12: + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + neg a0, a0 + jr t0 + FUNC_END (__divdi3) +@@ -126,7 +127,7 @@ FUNC_BEGIN (__moddi3) + bltz a1, .L31 + bltz a0, .L32 + .L30: +- jal __udivdi3 /* The dividend is not negative. */ ++ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is not negative. */ + move a0, a1 + jr t0 + .L31: +@@ -134,7 +135,7 @@ FUNC_BEGIN (__moddi3) + bgez a0, .L30 + .L32: + neg a0, a0 +- jal __udivdi3 /* The dividend is hella negative. */ ++ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is hella negative. */ + neg a0, a1 + jr t0 + FUNC_END (__moddi3) +diff --git a/libgcc/config/riscv/riscv-asm.h b/libgcc/config/riscv/riscv-asm.h +index 8550707a4a26a..96dd85b0df2e5 100644 +--- a/libgcc/config/riscv/riscv-asm.h ++++ b/libgcc/config/riscv/riscv-asm.h +@@ -33,3 +33,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + #define FUNC_ALIAS(X,Y) \ + .globl X; \ + X = Y ++ ++#define CONCAT1(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a ## b ++#define HIDDEN_JUMPTARGET(X) CONCAT1(__hidden_, X) ++#define HIDDEN_DEF(X) FUNC_ALIAS(HIDDEN_JUMPTARGET(X), X); \ ++ .hidden HIDDEN_JUMPTARGET(X) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch new file mode 100644 index 000000000000..d267b961d347 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch @@ -0,0 +1,58 @@ +From 68389203832ab39dd0dbaabbc4059e7fff51c29b Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Thu, 28 Oct 2021 11:39:49 -0700 +Subject: [PATCH] riscv: Fix incorrect jal with HIDDEN_JUMPTARGET + +A non-local STV_DEFAULT defined symbol is by default preemptible in a +shared object. j/jal cannot target a preemptible symbol. On other +architectures, such a jump instruction either causes PLT [BZ #18822], or +if short-ranged, sometimes rejected by the linker (but not by GNU ld's +riscv port [ld PR/28509]). + +Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. + +With this patch, ld.so and libc.so can be linked with LLD if source +files are compiled/assembled with -mno-relax/-Wa,-mno-relax. + +Acked-by: Palmer Dabbelt +Reviewed-by: Adhemerval Zanella +--- + sysdeps/riscv/setjmp.S | 2 +- + sysdeps/unix/sysv/linux/riscv/setcontext.S | 5 +++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S +index 0b92016b311..bec7ff80f49 100644 +--- a/sysdeps/riscv/setjmp.S ++++ b/sysdeps/riscv/setjmp.S +@@ -21,7 +21,7 @@ + + ENTRY (_setjmp) + li a1, 0 +- j __sigsetjmp ++ j HIDDEN_JUMPTARGET (__sigsetjmp) + END (_setjmp) + ENTRY (setjmp) + li a1, 1 +diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S +index 9510518750a..e44a68aad47 100644 +--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S ++++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S +@@ -95,6 +95,7 @@ LEAF (__setcontext) + 99: j __syscall_error + + END (__setcontext) ++libc_hidden_def (__setcontext) + weak_alias (__setcontext, setcontext) + + LEAF (__start_context) +@@ -108,7 +109,7 @@ LEAF (__start_context) + /* Invoke subsequent context if present, else exit(0). */ + mv a0, s2 + beqz s2, 1f +- jal __setcontext +-1: j exit ++ jal HIDDEN_JUMPTARGET (__setcontext) ++1: j HIDDEN_JUMPTARGET (exit) + + END (__start_context) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig index 470cef1a84e1..f7c93a9d5fc8 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig @@ -3,6 +3,8 @@ CT_EXPERIMENTAL=y CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_PATCH_BUNDLED_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_RISCV=y # CT_DEMULTILIB is not set CT_ARCH_USE_MMU=y @@ -10,7 +12,7 @@ CT_ARCH_64=y CT_ARCH_ARCH="rv64gc" CT_KERNEL_LINUX=y CT_LINUX_V_4_20=y -CT_BINUTILS_V_2_36=y +CT_BINUTILS_V_2_40=y CT_GLIBC_V_2_29=y CT_GCC_V_8=y CT_CC_LANG_CXX=y From 03bee1e1e56b10a3bff0e8eb524faacdb745cabc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 14:00:54 -0400 Subject: [PATCH 219/361] Suggest using precise capturing for hidden type that captures region --- .../src/infer/error_reporting/region.rs | 124 ++++++++++++++++-- .../forgot-to-capture-lifetime.stderr | 6 +- .../hidden-type-suggestion.rs | 30 +++++ .../hidden-type-suggestion.stderr | 67 ++++++++++ 4 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs create mode 100644 tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs index 5a465f46e47d..793e0c70d3cf 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/region.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs @@ -1,5 +1,6 @@ use std::iter; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495, }; @@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::symbol::kw; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol}; use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; @@ -1201,17 +1202,21 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( "", ); if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) { - let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); - nice_region_error::suggest_new_region_bound( - tcx, - &mut err, - fn_returns, - hidden_region.to_string(), - None, - format!("captures `{hidden_region}`"), - None, - Some(reg_info.def_id), - ) + if infcx.tcx.features().precise_capturing { + suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); + } else { + let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); + nice_region_error::suggest_new_region_bound( + tcx, + &mut err, + fn_returns, + hidden_region.to_string(), + None, + format!("captures `{hidden_region}`"), + None, + Some(reg_info.def_id), + ) + } } } ty::RePlaceholder(_) => { @@ -1257,3 +1262,98 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( err } + +fn suggest_precise_capturing<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_def_id: LocalDefId, + captured_lifetime: ty::Region<'tcx>, + diag: &mut Diag<'_>, +) { + let hir::OpaqueTy { bounds, .. } = + tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + + let new_lifetime = Symbol::intern(&captured_lifetime.to_string()); + + if let Some((args, span)) = bounds.iter().find_map(|bound| match bound { + hir::GenericBound::Use(args, span) => Some((args, span)), + _ => None, + }) { + let last_lifetime_span = args.iter().rev().find_map(|arg| match arg { + hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span), + _ => None, + }); + + let first_param_span = args.iter().find_map(|arg| match arg { + hir::PreciseCapturingArg::Param(p) => Some(p.ident.span), + _ => None, + }); + + let (insertion_span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span { + (last_lifetime_span.shrink_to_hi(), ", ", "") + } else if let Some(first_param_span) = first_param_span { + (first_param_span.shrink_to_lo(), "", ", ") + } else { + (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "") + }; + + diag.span_suggestion_verbose( + insertion_span, + format!("add `{new_lifetime}` to the `use<...>` bound to explicitly capture it",), + format!("{pre}{new_lifetime}{post}"), + Applicability::MachineApplicable, + ); + } else { + let mut captured_lifetimes = FxIndexSet::default(); + let mut captured_non_lifetimes = FxIndexSet::default(); + + let variances = tcx.variances_of(opaque_def_id); + let mut generics = tcx.generics_of(opaque_def_id); + loop { + for param in &generics.own_params { + if variances[param.index as usize] == ty::Bivariant { + continue; + } + + match param.kind { + ty::GenericParamDefKind::Lifetime => { + captured_lifetimes.insert(param.name); + } + ty::GenericParamDefKind::Type { synthetic: true, .. } => { + // FIXME: We can't provide a good suggestion for + // `use<...>` if we have an APIT. Bail for now. + return; + } + ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Const { .. } => { + captured_non_lifetimes.insert(param.name); + } + } + } + + if let Some(parent) = generics.parent { + generics = tcx.generics_of(parent); + } else { + break; + } + } + + if !captured_lifetimes.insert(new_lifetime) { + // Uh, strange. This lifetime appears to already be captured... + return; + } + + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::>() + .join(", "); + + diag.span_suggestion_verbose( + tcx.def_span(opaque_def_id).shrink_to_hi(), + format!("add a `use<...>` bound to explicitly capture `{new_lifetime}`",), + format!(" + use<{concatenated_bounds}>"), + Applicability::MachineApplicable, + ); + } +} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr index 6544837ba832..979c0ca6d7b6 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr @@ -16,10 +16,10 @@ LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } | | opaque type defined here | hidden type `&'a ()` captures the lifetime `'a` as defined here | -help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound +help: add `'a` to the `use<...>` bound to explicitly capture it | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x } - | ++++ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<'a> { x } + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs new file mode 100644 index 000000000000..e0b115b0ce41 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs @@ -0,0 +1,30 @@ +#![feature(precise_capturing)] + +fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn param<'a, T>(x: &'a ()) -> impl Sized + use { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn empty<'a>(x: &'a ()) -> impl Sized + use<> { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +trait Captures<'a> {} +impl Captures<'_> for T {} + +fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> { +//~^ HELP add a `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr new file mode 100644 index 000000000000..391f16d012e4 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr @@ -0,0 +1,67 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:5:5 + | +LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { + | -- -------------------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b, 'a> { + | ++++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:11:5 + | +LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use { + | -- ------------------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<'a, T> { + | +++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:17:5 + | +LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<> { + | -- ------------------ opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<'a> { + | ++ + +error[E0700]: hidden type for `impl Captures<'captured>` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:26:5 + | +LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> { + | -- ------------------------ opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> { + | ++++++++++++++++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0700`. From 42653c0045e46c26d2468b2aa2bba97802c08795 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 14:14:17 -0400 Subject: [PATCH 220/361] Make it translatable too --- compiler/rustc_infer/messages.ftl | 4 +++ compiler/rustc_infer/src/errors/mod.rs | 29 +++++++++++++++++++ .../src/infer/error_reporting/region.rs | 23 +++++++-------- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index fbe8d31370cc..7a5e71599203 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -221,6 +221,10 @@ infer_opaque_hidden_type = infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... + +infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it +infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` + infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a801001eaf98..ce1b0f86d034 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1581,3 +1581,32 @@ pub enum ObligationCauseFailureCode { subdiags: Vec, }, } + +#[derive(Subdiagnostic)] +pub enum AddPreciseCapturing { + #[suggestion( + infer_precise_capturing_new, + style = "verbose", + code = " + use<{concatenated_bounds}>", + applicability = "machine-applicable" + )] + New { + #[primary_span] + span: Span, + new_lifetime: Symbol, + concatenated_bounds: String, + }, + #[suggestion( + infer_precise_capturing_existing, + style = "verbose", + code = "{pre}{new_lifetime}{post}", + applicability = "machine-applicable" + )] + Existing { + #[primary_span] + span: Span, + new_lifetime: Symbol, + pre: &'static str, + post: &'static str, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs index 793e0c70d3cf..191cb23184da 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/region.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs @@ -1288,20 +1288,18 @@ fn suggest_precise_capturing<'tcx>( _ => None, }); - let (insertion_span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span { + let (span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span { (last_lifetime_span.shrink_to_hi(), ", ", "") } else if let Some(first_param_span) = first_param_span { (first_param_span.shrink_to_lo(), "", ", ") } else { + // If we have no args, then have `use<>` and need to fall back to using + // span math. This sucks, but should be reliable due to the construction + // of the `use<>` span. (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "") }; - diag.span_suggestion_verbose( - insertion_span, - format!("add `{new_lifetime}` to the `use<...>` bound to explicitly capture it",), - format!("{pre}{new_lifetime}{post}"), - Applicability::MachineApplicable, - ); + diag.subdiagnostic(errors::AddPreciseCapturing::Existing { span, new_lifetime, pre, post }); } else { let mut captured_lifetimes = FxIndexSet::default(); let mut captured_non_lifetimes = FxIndexSet::default(); @@ -1349,11 +1347,10 @@ fn suggest_precise_capturing<'tcx>( .collect::>() .join(", "); - diag.span_suggestion_verbose( - tcx.def_span(opaque_def_id).shrink_to_hi(), - format!("add a `use<...>` bound to explicitly capture `{new_lifetime}`",), - format!(" + use<{concatenated_bounds}>"), - Applicability::MachineApplicable, - ); + diag.subdiagnostic(errors::AddPreciseCapturing::New { + span: tcx.def_span(opaque_def_id).shrink_to_hi(), + new_lifetime, + concatenated_bounds, + }); } } From b77d3ef7c470f1d37a54665a0f21b5df22f4f86a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 15:31:34 -0400 Subject: [PATCH 221/361] Mark builtin syntax as internal --- compiler/rustc_feature/src/unstable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c05cac155b74..27a0a71a4d2c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -248,6 +248,8 @@ declare_features! ( (unstable, auto_traits, "1.50.0", Some(13231)), /// Allows using `box` in patterns (RFC 469). (unstable, box_patterns, "1.0.0", Some(29641)), + /// Allows builtin # foo() syntax + (internal, builtin_syntax, "1.71.0", Some(110680)), /// Allows `#[doc(notable_trait)]`. /// Renamed from `doc_spotlight`. (unstable, doc_notable_trait, "1.52.0", Some(45040)), @@ -361,8 +363,6 @@ declare_features! ( (unstable, async_fn_track_caller, "1.73.0", Some(110011)), /// Allows `for await` loops. (unstable, async_for_loop, "1.77.0", Some(118898)), - /// Allows builtin # foo() syntax - (unstable, builtin_syntax, "1.71.0", Some(110680)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. From d9021791eb097ae80bb1f1dd691e7e47c8e16f59 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Thu, 11 Jul 2024 22:38:34 +0200 Subject: [PATCH 222/361] Revert accidental comment deletion --- compiler/rustc_borrowck/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d258c68b9598..9ad941dabbe6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -821,6 +821,8 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> | TerminatorKind::Return | TerminatorKind::TailCall { .. } | TerminatorKind::CoroutineDrop => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let borrow_set = self.borrow_set.clone(); From b56dc8ee90582d9c1322632d570b996bcb73ecda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 5 Jul 2024 19:32:17 +0000 Subject: [PATCH 223/361] Use verbose style when suggesting changing `const` with `let` --- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 5 ++- compiler/rustc_resolve/src/errors.rs | 4 +- tests/ui/asm/parse-error.stderr | 40 ++++++++++++------- tests/ui/asm/type-check-1.stderr | 24 ++++++----- tests/ui/asm/x86_64/x86_64_parse_error.stderr | 24 ++++++----- .../legacy-const-generics-bad.stderr | 7 +++- tests/ui/consts/issue-3521.stderr | 8 ++-- tests/ui/consts/issue-91560.stderr | 16 +++++--- .../ui/consts/non-const-value-in-const.stderr | 17 +++++--- tests/ui/error-codes/E0435.stderr | 7 +++- tests/ui/issues/issue-27433.stderr | 9 +++-- tests/ui/issues/issue-3521-2.stderr | 9 +++-- .../issue-3668-2.stderr | 9 +++-- .../issue-3668.stderr | 9 +++-- tests/ui/issues/issue-44239.stderr | 8 ++-- tests/ui/parser/suggest-assoc-const.stderr | 7 +++- tests/ui/repeat-expr/repeat_count.stderr | 7 +++- .../type-dependent-def-issue-49241.stderr | 9 +++-- tests/ui/typeof/issue-42060.stderr | 14 +++++-- 20 files changed, 153 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f31e634f55c8..8e3887dfb254 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -810,7 +810,7 @@ impl<'a> Parser<'a> { self.dcx().struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); if is_let { - err.span_suggestion( + err.span_suggestion_verbose( non_item_span, "consider using `const` instead of `let` for associated const", "const", diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ffd495aa9857..f879e548f275 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -836,11 +836,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let ((with, with_label), without) = match sp { Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => { - let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32))); + let sp = sp + .with_lo(BytePos(sp.lo().0 - (current.len() as u32))) + .until(ident.span); ( (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion { span: sp, - ident, suggestion, current, }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})), diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0620f3d709eb..a4bdd62acbbd 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -242,13 +242,13 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { #[derive(Subdiagnostic)] #[suggestion( resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion, - code = "{suggestion} {ident}", + code = "{suggestion} ", + style = "verbose", applicability = "maybe-incorrect" )] pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { #[primary_span] pub(crate) span: Span, - pub(crate) ident: Ident, pub(crate) suggestion: &'a str, pub(crate) current: &'a str, } diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 80ee5191dbbe..8030face1d25 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -371,47 +371,57 @@ LL | global_asm!("{}", label {}); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:71:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:74:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error: aborting due to 64 previous errors diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index 07a609c52139..deba9e0fc544 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -1,29 +1,35 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:41:26 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const x); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:44:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_foo(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:47:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_bar(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error: invalid `sym` operand --> $DIR/type-check-1.rs:49:24 diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index f2854ae51285..95b86d533fa8 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -15,29 +15,35 @@ LL | asm!("{1}", in("eax") foo, const bar); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:13:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:15:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:17:42 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 83c71e07253b..6285d4780710 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/legacy-const-generics-bad.rs:7:35 | -LL | let a = 1; - | ----- help: consider using `const` instead of `let`: `const a` LL | legacy_const_generics::foo(0, a, 2); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const a = 1; + | ~~~~~ error: generic parameters may not be used in const operations --> $DIR/legacy-const-generics-bad.rs:12:35 diff --git a/tests/ui/consts/issue-3521.stderr b/tests/ui/consts/issue-3521.stderr index 70ce9b2d6a08..c0e4cdc5a94c 100644 --- a/tests/ui/consts/issue-3521.stderr +++ b/tests/ui/consts/issue-3521.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521.rs:8:15 | -LL | let foo: isize = 100; - | ------- help: consider using `const` instead of `let`: `const foo` -... LL | Bar = foo | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: isize = 100; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-91560.stderr b/tests/ui/consts/issue-91560.stderr index e1b5d4cacf8e..37c8f50d4943 100644 --- a/tests/ui/consts/issue-91560.stderr +++ b/tests/ui/consts/issue-91560.stderr @@ -1,20 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:10:19 | -LL | let mut length: usize = 2; - | -------------- help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:17:19 | -LL | let length: usize = 2; - | ------------ help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index 0ce4b4b70533..ee9ac16fe42b 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -2,18 +2,23 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:3:20 | LL | const Y: i32 = x; - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let Y` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let Y: i32 = x; + | ~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:6:17 | -LL | let x = 5; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | let _ = [0; x]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 5; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0435.stderr b/tests/ui/error-codes/E0435.stderr index 68d6ddba2a10..1ebb99763944 100644 --- a/tests/ui/error-codes/E0435.stderr +++ b/tests/ui/error-codes/E0435.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/E0435.rs:5:17 | -LL | let foo: usize = 42; - | ------- help: consider using `const` instead of `let`: `const foo` LL | let _: [u8; foo]; | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: usize = 42; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27433.stderr b/tests/ui/issues/issue-27433.stderr index aba8e612858a..f6d5fc2b768f 100644 --- a/tests/ui/issues/issue-27433.stderr +++ b/tests/ui/issues/issue-27433.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-27433.rs:5:23 | LL | const FOO : u32 = foo; - | --------- ^^^ non-constant value - | | - | help: consider using `let` instead of `const`: `let FOO` + | ^^^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let FOO : u32 = foo; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/issues/issue-3521-2.stderr index 0be0e93c19e6..a12241cb1dfd 100644 --- a/tests/ui/issues/issue-3521-2.stderr +++ b/tests/ui/issues/issue-3521-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521-2.rs:5:23 | LL | static y: isize = foo + 1; - | -------- ^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let y` + | ^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let y: isize = foo + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr index 3676f388891e..9661dbf2f62f 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668-2.rs:4:27 | LL | static child: isize = x + 1; - | ------------ ^ non-constant value - | | - | help: consider using `let` instead of `static`: `let child` + | ^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let child: isize = x + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr index d761b2d87db4..7fad45f4b1a2 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668.rs:8:34 | LL | static childVal: Box

= self.child.get(); - | --------------- ^^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let childVal` + | ^^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let childVal: Box

= self.child.get(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-44239.stderr b/tests/ui/issues/issue-44239.stderr index 633fb177b75d..1a047d4c63b6 100644 --- a/tests/ui/issues/issue-44239.stderr +++ b/tests/ui/issues/issue-44239.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-44239.rs:8:26 | -LL | let n: usize = 0; - | ----- help: consider using `const` instead of `let`: `const n` -... LL | const N: usize = n; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n: usize = 0; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr index 6e29fad98d46..70ebeded3137 100644 --- a/tests/ui/parser/suggest-assoc-const.stderr +++ b/tests/ui/parser/suggest-assoc-const.stderr @@ -2,7 +2,12 @@ error: non-item in item list --> $DIR/suggest-assoc-const.rs:5:5 | LL | let _X: i32; - | ^^^ help: consider using `const` instead of `let` for associated const: `const` + | ^^^ + | +help: consider using `const` instead of `let` for associated const + | +LL | const _X: i32; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 8a1ed8f3b9c7..9b5afc557357 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/repeat_count.rs:5:17 | -LL | let n = 1; - | ----- help: consider using `const` instead of `let`: `const n` LL | let a = [0; n]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n = 1; + | ~~~~~ error[E0308]: mismatched types --> $DIR/repeat_count.rs:7:17 diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr index 15d47cca3d20..cf372dc59681 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.stderr +++ b/tests/ui/type/type-dependent-def-issue-49241.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-dependent-def-issue-49241.rs:3:22 | LL | const l: usize = v.count(); - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let l` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let l: usize = v.count(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr index effcbe4d7f3e..7af65633f71d 100644 --- a/tests/ui/typeof/issue-42060.stderr +++ b/tests/ui/typeof/issue-42060.stderr @@ -1,18 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:3:23 | -LL | let thing = (); - | --------- help: consider using `const` instead of `let`: `const thing` LL | let other: typeof(thing) = thing; | ^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const thing = (); + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 | -LL | let q = 1; - | ----- help: consider using `const` instead of `let`: `const q` LL | ::N | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const q = 1; + | ~~~~~ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 From cbe75486f7eb6ae9fb00602f5347a09a62a7a9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 8 Jul 2024 19:43:20 +0000 Subject: [PATCH 224/361] Account for `let foo = expr`; to suggest `const foo: Ty = expr;` --- compiler/rustc_resolve/src/diagnostics.rs | 8 +++- compiler/rustc_resolve/src/errors.rs | 10 +++-- compiler/rustc_resolve/src/ident.rs | 44 ++++++++++++++----- compiler/rustc_resolve/src/lib.rs | 11 ++--- tests/ui/asm/parse-error.stderr | 20 ++++----- tests/ui/asm/type-check-1.stderr | 12 ++--- tests/ui/asm/x86_64/x86_64_parse_error.stderr | 12 ++--- .../legacy-const-generics-bad.stderr | 4 +- .../ui/consts/non-const-value-in-const.stderr | 4 +- tests/ui/issues/issue-27433.fixed | 2 +- tests/ui/issues/issue-27433.rs | 2 +- tests/ui/repeat-expr/repeat_count.stderr | 4 +- tests/ui/typeof/issue-42060.stderr | 8 ++-- 13 files changed, 85 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f879e548f275..09221041031a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span }) } - ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => { + ResolutionError::AttemptToUseNonConstantValueInConstant { + ident, + suggestion, + current, + type_span, + } => { // let foo =... // ^^^ given this Span // ------- get this Span to have an applicable suggestion @@ -844,6 +849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span: sp, suggestion, current, + type_span, }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})), None, ) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index a4bdd62acbbd..79c76e7a976a 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { } #[derive(Subdiagnostic)] -#[suggestion( +#[multipart_suggestion( resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion, - code = "{suggestion} ", style = "verbose", - applicability = "maybe-incorrect" + applicability = "has-placeholders" )] pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { - #[primary_span] + // #[primary_span] + #[suggestion_part(code = "{suggestion} ")] pub(crate) span: Span, pub(crate) suggestion: &'a str, + #[suggestion_part(code = ": /* Type */")] + pub(crate) type_span: Option, pub(crate) current: &'a str, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7d531385e212..f1934ff184bc 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { let (span, resolution_error) = match item { None if rib_ident.as_str() == "self" => (span, LowercaseSelf), - None => ( - rib_ident.span, - AttemptToUseNonConstantValueInConstant( - original_rib_ident_def, - "const", - "let", - ), - ), + None => { + // If we have a `let name = expr;`, we have the span for + // `name` and use that to see if it is followed by a type + // specifier. If not, then we know we need to suggest + // `const name: Ty = expr;`. This is a heuristic, it will + // break down in the presence of macros. + let sm = self.tcx.sess.source_map(); + let type_span = match sm.span_look_ahead( + original_rib_ident_def.span, + ":", + None, + ) { + None => { + Some(original_rib_ident_def.span.shrink_to_hi()) + } + Some(_) => None, + }; + ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant { + ident: original_rib_ident_def, + suggestion: "const", + current: "let", + type_span, + }, + ) + } Some((ident, kind)) => ( span, - AttemptToUseNonConstantValueInConstant( + AttemptToUseNonConstantValueInConstant { ident, - "let", - kind.as_str(), - ), + suggestion: "let", + current: kind.as_str(), + type_span: None, + }, ), }; self.report_error(span, resolution_error); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7cb5a3fb2fd1..3dcb83d65b02 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -236,11 +236,12 @@ enum ResolutionError<'a> { /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. - AttemptToUseNonConstantValueInConstant( - Ident, - /* suggestion */ &'static str, - /* current */ &'static str, - ), + AttemptToUseNonConstantValueInConstant { + ident: Ident, + suggestion: &'static str, + current: &'static str, + type_span: Option, + }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { shadowing_binding: PatternSource, diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 8030face1d25..1999cd09aa3b 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -376,8 +376,8 @@ LL | asm!("{}", options(), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:71:44 @@ -387,8 +387,8 @@ LL | asm!("{}", clobber_abi("C"), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:74:55 @@ -398,8 +398,8 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:31 @@ -409,8 +409,8 @@ LL | asm!("{a}", a = const foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:46 @@ -420,8 +420,8 @@ LL | asm!("{a}", a = const foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 64 previous errors diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index deba9e0fc544..185262321181 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -6,8 +6,8 @@ LL | asm!("{}", const x); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:44:36 @@ -17,8 +17,8 @@ LL | asm!("{}", const const_foo(x)); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:47:36 @@ -28,8 +28,8 @@ LL | asm!("{}", const const_bar(x)); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: invalid `sym` operand --> $DIR/type-check-1.rs:49:24 diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index 95b86d533fa8..9751f7b09d0e 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -20,8 +20,8 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:15:46 @@ -31,8 +31,8 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:17:42 @@ -42,8 +42,8 @@ LL | asm!("{1}", in("eax") foo, const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 6285d4780710..e9ea22e472c1 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -6,8 +6,8 @@ LL | legacy_const_generics::foo(0, a, 2); | help: consider using `const` instead of `let` | -LL | const a = 1; - | ~~~~~ +LL | const a: /* Type */ = 1; + | ~~~~~ ++++++++++++ error: generic parameters may not be used in const operations --> $DIR/legacy-const-generics-bad.rs:12:35 diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index ee9ac16fe42b..654b573544c2 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -17,8 +17,8 @@ LL | let _ = [0; x]; | help: consider using `const` instead of `let` | -LL | const x = 5; - | ~~~~~ +LL | const x: /* Type */ = 5; + | ~~~~~ ++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-27433.fixed b/tests/ui/issues/issue-27433.fixed index ff6704e393b5..f847b698976a 100644 --- a/tests/ui/issues/issue-27433.fixed +++ b/tests/ui/issues/issue-27433.fixed @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] let FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-27433.rs b/tests/ui/issues/issue-27433.rs index 2a34b43f58d2..9bbc5bcbb459 100644 --- a/tests/ui/issues/issue-27433.rs +++ b/tests/ui/issues/issue-27433.rs @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] const FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 9b5afc557357..350ac287507a 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -6,8 +6,8 @@ LL | let a = [0; n]; | help: consider using `const` instead of `let` | -LL | const n = 1; - | ~~~~~ +LL | const n: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0308]: mismatched types --> $DIR/repeat_count.rs:7:17 diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr index 7af65633f71d..86ba9432384b 100644 --- a/tests/ui/typeof/issue-42060.stderr +++ b/tests/ui/typeof/issue-42060.stderr @@ -6,8 +6,8 @@ LL | let other: typeof(thing) = thing; | help: consider using `const` instead of `let` | -LL | const thing = (); - | ~~~~~ +LL | const thing: /* Type */ = (); + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 @@ -17,8 +17,8 @@ LL | ::N | help: consider using `const` instead of `let` | -LL | const q = 1; - | ~~~~~ +LL | const q: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 From 4df75140dde8776fb4e371a28474d899524d99e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Jul 2024 17:27:08 +0000 Subject: [PATCH 225/361] Fix aarch64 test --- tests/ui/asm/aarch64/parse-error.stderr | 64 +++++++++++++++---------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index 539c134472fd..d21a8ab1f85f 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -313,74 +313,90 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:47:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:50:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:59:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:61:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:63:41 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 57 previous errors From d9170dc6666211902c7fbfa4f229c43cc286890c Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:20:53 +0000 Subject: [PATCH 226/361] Add regression test for issue 127545 --- .../transforming-option-ref-issue-127545.rs | 6 ++++++ .../transforming-option-ref-issue-127545.stderr | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs create mode 100644 tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs new file mode 100644 index 000000000000..5ba58e742758 --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -0,0 +1,6 @@ +// Regression test for . +#![crate_type = "lib"] + +pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + arg //~ ERROR 5:5: 5:8: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr new file mode 100644 index 000000000000..798a4da23b0d --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:5:5 + | +LL | pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + | -------------- expected `Option<&[i32]>` because of return type +LL | arg + | ^^^ expected `Option<&[i32]>`, found `Option<&Vec>` + | + = note: expected enum `Option<&[i32]>` + found enum `Option<&Vec>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 872d7b82e181235bdf8842847c76592f70419b09 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:15:48 +0000 Subject: [PATCH 227/361] Add suggestion for `Option<&Vec> -> Option<&[T]` --- .../src/fn_ctxt/suggestions.rs | 49 +++++++++++++------ ...ransforming-option-ref-issue-127545.stderr | 4 ++ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8d380caf9162..50c4e9d5d607 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -466,21 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { borrow_removal_span, }); return true; - } else if let Some((deref_ty, _)) = - self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1) - && self.can_eq(self.param_env, deref_ty, peeled) - && error_tys_equate_as_ref - { - let sugg = prefix_wrap(".as_deref()"); - err.subdiagnostic(errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }); - return true; - } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() + } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind() + && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. @@ -496,6 +483,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); return true; + } else { + if !error_tys_equate_as_ref { + return false; + } + let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors(); + if let Some((deref_ty, _)) = steps.nth(1) + && self.can_eq(self.param_env, deref_ty, peeled) + { + let sugg = prefix_wrap(".as_deref()"); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + for (deref_ty, n_step) in steps { + if self.can_eq(self.param_env, deref_ty, peeled) { + let explicit_deref = "*".repeat(n_step); + let sugg = prefix_wrap(&format!(".map(|v| &{explicit_deref}v)")); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + } } } diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 798a4da23b0d..b7c7202113a1 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -8,6 +8,10 @@ LL | arg | = note: expected enum `Option<&[i32]>` found enum `Option<&Vec>` +help: try using `.map(|v| &**v)` to convert `Option<&Vec>` to `Option<&[i32]>` + | +LL | arg.map(|v| &**v) + | ++++++++++++++ error: aborting due to 1 previous error From a776e5f922d3b39d74d4b4d3acb752ce3585a2fb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 05:10:20 +0000 Subject: [PATCH 228/361] Add doc for deconstruct_option_or_result --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 50c4e9d5d607..0817ad3aed2c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -521,6 +521,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// If `ty` is `Option`, returns `T, T, None`. + /// If `ty` is `Result`, returns `T, T, Some(E, E)`. + /// Otherwise, returns `None`. fn deconstruct_option_or_result( &self, found_ty: Ty<'tcx>, From 2c8bbeebf1c630d06e44fa131d1cb0908b5ad56c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 19:15:00 -0400 Subject: [PATCH 229/361] Remove fully_normalize --- .../src/opaque_hidden_inferred_bound.rs | 31 +++++++------ .../rustc_trait_selection/src/traits/mod.rs | 46 ++++--------------- .../src/traits/normalize.rs | 8 ++-- .../src/traits/specialize/mod.rs | 29 +++++------- 4 files changed, 38 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 5ee73dbfdc65..fdb71ad41a75 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -5,8 +5,7 @@ use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifie use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::kw, Span}; -use rustc_trait_selection::traits; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use crate::{LateContext, LateLintPass, LintContext}; @@ -130,24 +129,26 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { .iter_instantiated_copied(cx.tcx, proj.projection_term.args) { let assoc_pred = assoc_pred.fold_with(proj_replacer); - let Ok(assoc_pred) = traits::fully_normalize( - infcx, - traits::ObligationCause::dummy(), - cx.param_env, - assoc_pred, - ) else { - continue; - }; - // If that predicate doesn't hold modulo regions (but passed during type-check), - // then we must've taken advantage of the hack in `project_and_unify_types` where - // we replace opaques with inference vars. Emit a warning! - if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( + let ocx = ObligationCtxt::new(infcx); + let assoc_pred = + ocx.normalize(&traits::ObligationCause::dummy(), cx.param_env, assoc_pred); + if !ocx.select_all_or_error().is_empty() { + // Can't normalize for some reason...? + continue; + } + + ocx.register_obligation(traits::Obligation::new( cx.tcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred, - )) { + )); + + // If that predicate doesn't hold modulo regions (but passed during type-check), + // then we must've taken advantage of the hack in `project_and_unify_types` where + // we replace opaques with inference vars. Emit a warning! + if !ocx.select_all_or_error().is_empty() { // If it's a trait bound and an opaque that doesn't satisfy it, // then we can emit a suggestion to add the bound. let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 703ff2f7f169..d28982ed8492 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -271,13 +271,14 @@ fn do_normalize_predicates<'tcx>( // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. let infcx = tcx.infer_ctxt().ignoring_regions().build(); - let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { - Ok(predicates) => predicates, - Err(errors) => { - let reported = infcx.err_ctxt().report_fulfillment_errors(errors); - return Err(reported); - } - }; + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + let predicates = ocx.normalize(&cause, elaborated_env, predicates); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); + } debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); @@ -465,37 +466,6 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } -/// Normalize a type and process all resulting obligations, returning any errors. -/// -/// FIXME(-Znext-solver): This should be replaced by `At::deeply_normalize` -/// which has the same behavior with the new solver. Because using a separate -/// fulfillment context worsens caching in the old solver, `At::deeply_normalize` -/// is still lazy with the old solver as it otherwise negatively impacts perf. -#[instrument(skip_all)] -pub fn fully_normalize<'tcx, T>( - infcx: &InferCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: T, -) -> Result>> -where - T: TypeFoldable>, -{ - let ocx = ObligationCtxt::new_with_diagnostics(infcx); - debug!(?value); - let normalized_value = ocx.normalize(&cause, param_env, value); - debug!(?normalized_value); - debug!("select_all_or_error start"); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - return Err(errors); - } - debug!("select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(normalized_value); - debug!(?resolved_value); - Ok(resolved_value) -} - /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 3a7481acbafd..01ba8c02ea6e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -42,11 +42,9 @@ impl<'tcx> At<'_, 'tcx> { /// same goals in both a temporary and the shared context which negatively impacts /// performance as these don't share caching. /// - /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize` - /// in the new solver, but because of performance reasons, we currently reuse an - /// existing fulfillment context in the old solver. Once we also eagerly prove goals with - /// the old solver or have removed the old solver, remove `traits::fully_normalize` and - /// rename this function to `At::fully_normalize`. + /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing + /// fulfillment context in the old solver. Once we have removed the old solver, we + /// can remove the `fulfill_cx` parameter on this function. fn deeply_normalize( self, value: T, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 6a904ef487ea..3c33d13567d7 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -18,9 +18,7 @@ use crate::error_reporting::traits::to_pretty_impl_header; use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{ - self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, -}; +use crate::traits::{coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -219,19 +217,17 @@ fn fulfill_implication<'tcx>( param_env, source_trait_ref, target_impl ); - let source_trait_ref = - match traits::fully_normalize(infcx, ObligationCause::dummy(), param_env, source_trait_ref) - { - Ok(source_trait_ref) => source_trait_ref, - Err(_errors) => { - infcx.dcx().span_delayed_bug( - infcx.tcx.def_span(source_impl), - format!("failed to fully normalize {source_trait_ref}"), - ); - source_trait_ref - } - }; + let ocx = ObligationCtxt::new(infcx); + let source_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, source_trait_ref); + if !ocx.select_all_or_error().is_empty() { + infcx.dcx().span_delayed_bug( + infcx.tcx.def_span(source_impl), + format!("failed to fully normalize {source_trait_ref}"), + ); + } + + let source_trait_ref = infcx.resolve_vars_if_possible(source_trait_ref); let source_trait = ImplSubject::Trait(source_trait_ref); let selcx = SelectionContext::new(infcx); @@ -253,9 +249,6 @@ fn fulfill_implication<'tcx>( return Err(()); }; - // Needs to be `in_snapshot` because this function is used to rebase - // generic parameters, which may happen inside of a select within a probe. - let ocx = ObligationCtxt::new(infcx); // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) ocx.register_obligations(obligations.chain(more_obligations)); From a36fcc8969761fa08c8f969104bba500ff0fb75c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 18:57:56 -0400 Subject: [PATCH 230/361] Remove lang feature for type ascription --- compiler/rustc_codegen_gcc/example/mini_core.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index a48c0a4450c2..f47bfdad1312 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -1,5 +1,5 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + no_core, lang_items, intrinsics, unboxed_closures, extern_types, decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, thread_local )] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c05cac155b74..87fd01a17893 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -621,8 +621,6 @@ declare_features! ( (unstable, try_blocks, "1.29.0", Some(31436)), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (unstable, type_alias_impl_trait, "1.38.0", Some(63063)), - /// Allows the use of type ascription in expressions. - (unstable, type_ascription, "1.6.0", Some(23416)), /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), From ec05c4ea3fd9b6f7978091f3098ac52116e47a20 Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 23 Jun 2024 12:12:51 +0530 Subject: [PATCH 231/361] Add the feature gate and target-features --- compiler/rustc_codegen_ssa/src/target_features.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 5 +++++ tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- .../feature-gate-x86_amx_intrinsics.rs | 6 ++++++ .../feature-gate-x86_amx_intrinsics.stderr | 13 +++++++++++++ 8 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs create mode 100644 tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index bcddfe9fb9cb..22006c0b4712 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -80,6 +80,7 @@ pub fn from_target_feature( Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, + Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index d7d994d95c51..3f550f658e83 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -640,6 +640,8 @@ declare_features! ( (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), + /// Allows use of x86 `AMX` target-feature attributes and intrinsics + (unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index af56f4e51413..827b9062d83a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2072,6 +2072,7 @@ symbols! { write_str, write_via_move, writeln_macro, + x86_amx_intrinsics, x87_reg, xer, xmm_reg, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 017fd3072fdb..aec2828181b9 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -192,6 +192,11 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-start ("adx", Stable), ("aes", Stable), + ("amx-bf16", Unstable(sym::x86_amx_intrinsics)), + ("amx-complex", Unstable(sym::x86_amx_intrinsics)), + ("amx-fp16", Unstable(sym::x86_amx_intrinsics)), + ("amx-int8", Unstable(sym::x86_amx_intrinsics)), + ("amx-tile", Unstable(sym::x86_amx_intrinsics)), ("avx", Stable), ("avx2", Stable), ("avx512bf16", Unstable(sym::avx512_target_feature)), diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index cc63466585a6..15b0100d7d23 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, and `avxvnniint8` and 191 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 196 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 8a99ace75d85..c35fb68c839d 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs new file mode 100644 index 000000000000..ecbfc0bce5c5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "amx-tile")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr new file mode 100644 index 000000000000..58d577a37902 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `amx-tile` is currently unstable + --> $DIR/feature-gate-x86_amx_intrinsics.rs:2:18 + | +LL | #[target_feature(enable = "amx-tile")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #126622 for more information + = help: add `#![feature(x86_amx_intrinsics)]` 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 692bc344d55cf9d86c60b06c92a70684d013c89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 6 Jul 2024 03:07:46 +0000 Subject: [PATCH 232/361] Make parse error suggestions verbose and fix spans Go over all structured parser suggestions and make them verbose style. When suggesting to add or remove delimiters, turn them into multiple suggestion parts. --- compiler/rustc_parse/messages.ftl | 4 +- compiler/rustc_parse/src/errors.rs | 392 ++++++++++++------ .../rustc_parse/src/parser/diagnostics.rs | 35 +- compiler/rustc_parse/src/parser/expr.rs | 11 +- compiler/rustc_parse/src/parser/item.rs | 6 +- compiler/rustc_parse/src/parser/pat.rs | 50 ++- compiler/rustc_parse/src/parser/stmt.rs | 8 +- compiler/rustc_parse/src/parser/ty.rs | 23 +- ...led-doctest-extra-semicolon-on-item.stdout | 7 +- .../incorrect-syntax-suggestions.stderr | 144 ++++++- tests/ui/attributes/issue-90873.stderr | 7 +- .../cfg-attr-parse.stderr | 6 +- .../ui/consts/const-eval/issue-104390.stderr | 27 +- tests/ui/coverage-attr/bad-syntax.stderr | 11 +- tests/ui/did_you_mean/E0178.stderr | 21 +- ...1679-tilde-bitwise-negation-attempt.stderr | 43 +- ...-identifier-not-instead-of-negation.stderr | 43 +- ...sue-54109-and_instead_of_ampersands.stderr | 48 ++- .../issue-54109-without-witness.stderr | 48 ++- tests/ui/did_you_mean/pub-macro-rules.stderr | 7 +- ...reference-without-parens-suggestion.stderr | 14 +- .../did_you_mean/use_instead_of_import.stderr | 28 +- tests/ui/enum/nested-enum.stderr | 30 +- tests/ui/error-codes/E0586.stderr | 7 +- tests/ui/expr/if/attrs/else-attrs.stderr | 9 +- tests/ui/extern/extern-const.stderr | 8 +- tests/ui/fmt/format-string-error-2.stderr | 7 +- tests/ui/fn/fn-recover-return-sign.fixed | 4 +- tests/ui/fn/fn-recover-return-sign.stderr | 28 +- tests/ui/fn/fn-recover-return-sign2.stderr | 7 +- .../generics/issue-95208-ignore-qself.stderr | 9 +- tests/ui/generics/issue-95208.stderr | 9 +- ...ingle-colon-path-not-const-generics.stderr | 6 +- ...pats-inclusive-dotdotdot-bad-syntax.stderr | 34 +- ...lf-open-range-pats-inclusive-no-end.stderr | 42 +- ...pen-range-pats-ref-ambiguous-interp.stderr | 56 ++- .../extra-impl-in-trait-impl.stderr | 14 +- .../impl-fn-parsing-ambiguities.stderr | 14 +- .../impl-trait-plus-priority.stderr | 70 +++- tests/ui/issues/issue-40782.stderr | 14 +- tests/ui/label/label_misspelled_2.stderr | 14 +- .../let-else-missing-semicolon.stderr | 14 +- ...-bare-cr-string-literal-doc-comment.stderr | 7 +- tests/ui/macros/bang-after-name.stderr | 8 +- tests/ui/macros/missing-bang-in-decl.stderr | 8 +- tests/ui/macros/recovery-allowed.stderr | 9 +- .../malformed/malformed-special-attrs.stderr | 12 +- .../avoid-ice-on-warning.new.stderr | 7 +- .../avoid-ice-on-warning.old.stderr | 7 +- .../less-than-greater-than.stderr | 7 +- .../or-patterns/fn-param-wrap-parens.stderr | 7 +- .../issue-64879-trailing-before-guard.stderr | 8 +- .../or-patterns/multiple-pattern-typo.stderr | 49 ++- .../nested-undelimited-precedence.stderr | 35 +- .../or-patterns-syntactic-fail.stderr | 28 +- .../ui/or-patterns/remove-leading-vert.fixed | 2 +- .../ui/or-patterns/remove-leading-vert.stderr | 160 ++++++- .../attribute/attr-stmt-expr-attr-bad.stderr | 93 ++++- tests/ui/parser/bad-char-literals.stderr | 28 +- tests/ui/parser/bad-fn-ptr-qualifier.stderr | 112 ++++- tests/ui/parser/byte-literals.stderr | 14 +- .../char/whitespace-character-literal.stderr | 8 +- .../parser/default-on-wrong-item-kind.stderr | 8 +- tests/ui/parser/do-catch-suggests-try.stderr | 6 +- .../parser/doc-comment-in-if-statement.stderr | 9 +- tests/ui/parser/expr-rarrow-call.stderr | 30 +- tests/ui/parser/fn-colon-return-type.stderr | 7 +- .../parser/foreign-const-semantic-fail.stderr | 16 +- .../foreign-const-syntactic-fail.stderr | 16 +- tests/ui/parser/ident-recovery.stderr | 22 +- tests/ui/parser/if-in-in.stderr | 10 +- tests/ui/parser/impl-parsing.stderr | 14 +- .../ui/parser/intersection-patterns-1.stderr | 12 +- ...icolon-issue-124935-semi-after-item.stderr | 8 +- .../parser/issues/issue-100197-mut-let.stderr | 7 +- .../ui/parser/issues/issue-101477-enum.stderr | 7 +- .../ui/parser/issues/issue-101477-let.stderr | 8 +- tests/ui/parser/issues/issue-103425.stderr | 21 +- .../issue-108109-fn-missing-params.stderr | 14 +- tests/ui/parser/issues/issue-113203.stderr | 7 +- .../ui/parser/issues/issue-118530-ice.stderr | 13 +- .../issues/issue-17718-const-mut.stderr | 7 +- .../issues/issue-23620-invalid-escapes.stderr | 9 +- tests/ui/parser/issues/issue-27255.stderr | 14 +- tests/ui/parser/issues/issue-3036.stderr | 7 +- tests/ui/parser/issues/issue-32501.stderr | 7 +- tests/ui/parser/issues/issue-46186.stderr | 7 +- tests/ui/parser/issues/issue-48636.stderr | 5 +- tests/ui/parser/issues/issue-49040.stderr | 8 +- tests/ui/parser/issues/issue-52496.stderr | 7 +- tests/ui/parser/issues/issue-54521-2.stderr | 32 +- tests/ui/parser/issues/issue-54521-3.stderr | 32 +- tests/ui/parser/issues/issue-57684.stderr | 18 +- tests/ui/parser/issues/issue-57819.stderr | 56 ++- ...sue-65122-mac-invoc-in-mut-patterns.stderr | 14 +- ...sue-65257-invalid-var-decl-recovery.stderr | 14 +- ...ue-70388-recover-dotdotdot-rest-pat.stderr | 22 +- .../issues/issue-70388-without-witness.stderr | 22 +- ...9-resolve-after-recovered-self-ctor.stderr | 8 +- .../issue-73568-lifetime-after-mut.stderr | 20 +- .../issue-87197-missing-semicolon.stderr | 21 +- tests/ui/parser/issues/issue-89574.stderr | 7 +- tests/ui/parser/issues/issue-90993.stderr | 6 +- ...9625-enum-struct-mutually-exclusive.stderr | 7 +- ...-99910-const-let-mutually-exclusive.stderr | 14 +- ...g-main-issue-124935-semi-after-item.stderr | 7 +- ...em-free-const-no-body-semantic-fail.stderr | 7 +- ...m-free-static-no-body-semantic-fail.stderr | 14 +- tests/ui/parser/item-kw-case-mismatch.stderr | 98 ++++- tests/ui/parser/label-after-block-like.stderr | 63 ++- tests/ui/parser/labeled-no-colon-expr.stderr | 53 ++- tests/ui/parser/let-binop.stderr | 21 +- .../parser/lifetime-in-pattern-recover.stderr | 16 +- tests/ui/parser/lifetime-in-pattern.stderr | 8 +- tests/ui/parser/macro/pub-item-macro.stderr | 7 +- tests/ui/parser/macros-no-semicolon.stderr | 14 +- tests/ui/parser/match-arm-without-body.stderr | 7 +- .../ui/parser/match-arm-without-braces.stderr | 7 +- tests/ui/parser/mut-patterns.stderr | 61 ++- tests/ui/parser/not-a-pred.stderr | 7 +- tests/ui/parser/pat-recover-wildcards.stderr | 7 +- tests/ui/parser/pub-method-macro.stderr | 7 +- .../range-inclusive-extra-equals.stderr | 6 +- tests/ui/parser/range_inclusive.stderr | 7 +- tests/ui/parser/raw/raw-str-unbalanced.stderr | 7 +- .../recover/recover-const-async-fn-ptr.stderr | 112 ++++- ...gle-brackets-in-struct-with-a-field.stderr | 13 +- .../recover-field-extra-angle-brackets.stderr | 8 +- .../recover-missing-semi-before-item.stderr | 70 +++- .../recover/recover-missing-semi.stderr | 14 +- .../parser/recover/recover-range-pats.stderr | 188 +++++++-- .../parser/recover/recover-ref-dyn-mut.stderr | 7 +- .../recover/recover-unticked-labels.stderr | 18 +- .../parser/regions-out-of-scope-slice.stderr | 9 +- .../removed-syntax-fn-sigil.stderr | 7 +- .../removed-syntax-static-fn.stderr | 7 +- ...-values-and-missing-field-separator.stderr | 80 +++- .../ui/parser/trait-object-delimiters.stderr | 14 +- .../trait-object-lifetime-parens.stderr | 16 +- .../parser/trait-object-polytrait-priority.rs | 1 - .../trait-object-polytrait-priority.stderr | 7 +- .../parser/unicode-character-literal.stderr | 8 +- tests/ui/parser/unmatched-langle-1.stderr | 8 +- tests/ui/parser/unnecessary-let.stderr | 23 +- tests/ui/parser/use-colon-as-mod-sep.stderr | 24 +- ...ld-before-at-syntactically-rejected.stderr | 18 +- ...e-80186-mut-binding-help-suggestion.stderr | 6 +- .../pattern/pattern-bad-ref-box-order.stderr | 7 +- ...tern-meant-to-be-slice-rest-pattern.stderr | 7 +- tests/ui/pub/pub-restricted.stderr | 30 +- tests/ui/range/impossible_range.stderr | 14 +- .../range-inclusive-pattern-precedence.stderr | 7 +- ...range-inclusive-pattern-precedence2.stderr | 7 +- .../rfcs/rfc-0000-never_patterns/parse.stderr | 21 +- tests/ui/self/self-vs-path-ambiguity.stderr | 8 +- tests/ui/self/self_type_keyword.stderr | 7 +- .../ui/structs/struct-duplicate-comma.stderr | 11 +- .../structs/struct-field-init-syntax.stderr | 14 +- tests/ui/suggestions/const-no-type.stderr | 21 +- .../suggestions/js-style-comparison-op.stderr | 14 +- tests/ui/suggestions/missing-semicolon.stderr | 14 +- ...ecover-from-semicolon-trailing-item.stderr | 21 +- .../suggestions/recover-invalid-float.stderr | 21 +- ...st-semicolon-for-fn-in-extern-block.stderr | 7 +- .../type-ascription-instead-of-method.stderr | 6 +- .../type-ascription-instead-of-path.stderr | 6 +- .../type-ascription-instead-of-variant.stderr | 6 +- tests/ui/type/ascription/issue-47666.stderr | 6 +- tests/ui/type/ascription/issue-54516.stderr | 6 +- tests/ui/type/ascription/issue-60933.stderr | 6 +- tests/ui/type/pattern_types/bad_pat.stderr | 14 +- ...ascription-instead-of-statement-end.stderr | 6 +- .../type/type-ascription-with-fn-call.stderr | 6 +- ...holder-to-const-static-without-type.stderr | 14 +- tests/ui/typeck/issue-79040.stderr | 7 +- 175 files changed, 3197 insertions(+), 786 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 02c3c87313bc..fd96d95bc2e5 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -1,7 +1,7 @@ parse_add_paren = try adding parentheses parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation - .suggestion = add parentheses to clarify the precedence +parse_ambiguous_range_pattern_suggestion = add parentheses to clarify the precedence parse_array_brackets_instead_of_braces = this is a block expression, not an array .suggestion = to make an array, use square brackets instead of curly braces @@ -644,7 +644,7 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported - .suggestion = remove the parentheses +parse_parenthesized_lifetime_suggestion = remove the parentheses parse_path_single_colon = path separator must be a double colon .suggestion = use a double colon instead diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3ae9b6dad998..0f13a8e5e141 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -18,10 +18,10 @@ use crate::parser::{ForbiddenLetReason, TokenDescription}; #[derive(Diagnostic)] #[diag(parse_maybe_report_ambiguous_plus)] pub(crate) struct AmbiguousPlus { - pub sum_ty: String, #[primary_span] - #[suggestion(code = "({sum_ty})")] pub span: Span, + #[subdiagnostic] + pub suggestion: AddParen, } #[derive(Diagnostic)] @@ -34,17 +34,20 @@ pub(crate) struct BadTypePlus { pub sub: BadTypePlusSub, } +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")] +pub(crate) struct AddParen { + #[suggestion_part(code = "(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum BadTypePlusSub { - #[suggestion( - parse_add_paren, - code = "{sum_with_parens}", - applicability = "machine-applicable" - )] AddParen { - sum_with_parens: String, - #[primary_span] - span: Span, + #[subdiagnostic] + suggestion: AddParen, }, #[label(parse_forgot_paren)] ForgotParen { @@ -80,7 +83,7 @@ pub(crate) struct WrapType { #[diag(parse_incorrect_semicolon)] pub(crate) struct IncorrectSemicolon<'a> { #[primary_span] - #[suggestion(style = "short", code = "", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] pub span: Span, #[help] pub show_help: bool, @@ -91,7 +94,12 @@ pub(crate) struct IncorrectSemicolon<'a> { #[diag(parse_incorrect_use_of_await)] pub(crate) struct IncorrectUseOfAwait { #[primary_span] - #[suggestion(parse_parentheses_suggestion, code = "", applicability = "machine-applicable")] + #[suggestion( + parse_parentheses_suggestion, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] pub span: Span, } @@ -100,7 +108,11 @@ pub(crate) struct IncorrectUseOfAwait { pub(crate) struct IncorrectAwait { #[primary_span] pub span: Span, - #[suggestion(parse_postfix_suggestion, code = "{expr}.await{question_mark}")] + #[suggestion( + parse_postfix_suggestion, + style = "verbose", + code = "{expr}.await{question_mark}" + )] pub sugg_span: (Span, Applicability), pub expr: String, pub question_mark: &'static str, @@ -111,7 +123,7 @@ pub(crate) struct IncorrectAwait { pub(crate) struct InInTypo { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")] pub sugg_span: Span, } @@ -126,17 +138,33 @@ pub(crate) struct InvalidVariableDeclaration { #[derive(Subdiagnostic)] pub(crate) enum InvalidVariableDeclarationSub { - #[suggestion(parse_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")] + #[suggestion( + parse_switch_mut_let_order, + style = "verbose", + applicability = "maybe-incorrect", + code = "let mut" + )] SwitchMutLetOrder(#[primary_span] Span), #[suggestion( parse_missing_let_before_mut, applicability = "machine-applicable", + style = "verbose", code = "let mut" )] MissingLet(#[primary_span] Span), - #[suggestion(parse_use_let_not_auto, applicability = "machine-applicable", code = "let")] + #[suggestion( + parse_use_let_not_auto, + style = "verbose", + applicability = "machine-applicable", + code = "let" + )] UseLetNotAuto(#[primary_span] Span), - #[suggestion(parse_use_let_not_var, applicability = "machine-applicable", code = "let")] + #[suggestion( + parse_use_let_not_var, + style = "verbose", + applicability = "machine-applicable", + code = "let" + )] UseLetNotVar(#[primary_span] Span), } @@ -144,7 +172,7 @@ pub(crate) enum InvalidVariableDeclarationSub { #[diag(parse_switch_ref_box_order)] pub(crate) struct SwitchRefBoxOrder { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "box ref")] + #[suggestion(applicability = "machine-applicable", style = "verbose", code = "box ref")] pub span: Span, } @@ -162,7 +190,7 @@ pub(crate) struct InvalidComparisonOperator { pub(crate) enum InvalidComparisonOperatorSub { #[suggestion( parse_use_instead, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "{correct}" )] @@ -191,14 +219,14 @@ pub(crate) struct InvalidLogicalOperator { pub(crate) enum InvalidLogicalOperatorSub { #[suggestion( parse_use_amp_amp_for_conjunction, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "&&" )] Conjunction(#[primary_span] Span), #[suggestion( parse_use_pipe_pipe_for_disjunction, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "||" )] @@ -209,7 +237,7 @@ pub(crate) enum InvalidLogicalOperatorSub { #[diag(parse_tilde_is_not_unary_operator)] pub(crate) struct TildeAsUnaryOperator( #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = "!")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "!")] pub Span, ); @@ -227,7 +255,7 @@ pub(crate) struct NotAsNegationOperator { pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_default, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -235,7 +263,7 @@ pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_bitwise, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -243,7 +271,7 @@ pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_logical, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -254,9 +282,9 @@ pub enum NotAsNegationOperatorSub { #[diag(parse_malformed_loop_label)] pub(crate) struct MalformedLoopLabel { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "{correct_label}")] pub span: Span, - pub correct_label: Ident, + #[suggestion(applicability = "machine-applicable", code = "'", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -264,7 +292,7 @@ pub(crate) struct MalformedLoopLabel { pub(crate) struct LifetimeInBorrowExpression { #[primary_span] pub span: Span, - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] #[label] pub lifetime_span: Span, } @@ -306,7 +334,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { pub span: Span, #[label] pub label: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = ": ")] pub label_end: Span, } @@ -315,7 +343,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { #[note] pub(crate) struct DoCatchSyntaxRemoved { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "try")] + #[suggestion(applicability = "machine-applicable", code = "try", style = "verbose")] pub span: Span, } @@ -323,9 +351,9 @@ pub(crate) struct DoCatchSyntaxRemoved { #[diag(parse_float_literal_requires_integer_part)] pub(crate) struct FloatLiteralRequiresIntegerPart { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "{correct}")] pub span: Span, - pub correct: String, + #[suggestion(applicability = "machine-applicable", code = "0", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -394,7 +422,12 @@ pub struct TernaryOperator { } #[derive(Subdiagnostic)] -#[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")] +#[suggestion( + parse_extra_if_in_let_else, + applicability = "maybe-incorrect", + code = "", + style = "verbose" +)] pub(crate) struct IfExpressionLetSomeSub { #[primary_span] pub if_span: Span, @@ -463,7 +496,7 @@ pub(crate) struct ExpectedElseBlock { pub first_tok: String, #[label] pub else_span: Span, - #[suggestion(applicability = "maybe-incorrect", code = "if ")] + #[suggestion(applicability = "maybe-incorrect", code = "if ", style = "verbose")] pub condition_start: Span, } @@ -491,7 +524,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { pub ctx_span: Span, pub ctx: String, - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] pub attributes: Span, } @@ -509,12 +542,17 @@ pub(crate) enum MissingInInForLoopSub { // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect #[suggestion( parse_use_in_not_of, - style = "short", + style = "verbose", applicability = "maybe-incorrect", code = "in" )] InNotOf(#[primary_span] Span), - #[suggestion(parse_add_in, style = "short", applicability = "maybe-incorrect", code = " in ")] + #[suggestion( + parse_add_in, + style = "verbose", + applicability = "maybe-incorrect", + code = " in " + )] AddIn(#[primary_span] Span), } @@ -545,7 +583,7 @@ pub(crate) struct LoopElseNotSupported { #[diag(parse_missing_comma_after_match_arm)] pub(crate) struct MissingCommaAfterMatchArm { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = ",")] + #[suggestion(applicability = "machine-applicable", code = ",", style = "verbose")] pub span: Span, } @@ -563,7 +601,7 @@ pub(crate) struct CatchAfterTry { pub(crate) struct CommaAfterBaseStruct { #[primary_span] pub span: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = "")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")] pub comma: Span, } @@ -572,7 +610,7 @@ pub(crate) struct CommaAfterBaseStruct { pub(crate) struct EqFieldInit { #[primary_span] pub span: Span, - #[suggestion(applicability = "machine-applicable", code = ":")] + #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] pub eq: Span, } @@ -580,8 +618,18 @@ pub(crate) struct EqFieldInit { #[diag(parse_dotdotdot)] pub(crate) struct DotDotDot { #[primary_span] - #[suggestion(parse_suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] - #[suggestion(parse_suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] + #[suggestion( + parse_suggest_exclusive_range, + applicability = "maybe-incorrect", + code = "..", + style = "verbose" + )] + #[suggestion( + parse_suggest_inclusive_range, + applicability = "maybe-incorrect", + code = "..=", + style = "verbose" + )] pub span: Span, } @@ -589,7 +637,7 @@ pub(crate) struct DotDotDot { #[diag(parse_left_arrow_operator)] pub(crate) struct LeftArrowOperator { #[primary_span] - #[suggestion(applicability = "maybe-incorrect", code = "< -")] + #[suggestion(applicability = "maybe-incorrect", code = "< -", style = "verbose")] pub span: Span, } @@ -597,7 +645,7 @@ pub(crate) struct LeftArrowOperator { #[diag(parse_remove_let)] pub(crate) struct RemoveLet { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] pub span: Span, } @@ -605,8 +653,9 @@ pub(crate) struct RemoveLet { #[diag(parse_use_eq_instead)] pub(crate) struct UseEqInstead { #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = "=")] pub span: Span, + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -780,7 +829,7 @@ pub(crate) struct InclusiveRangeExtraEquals { #[primary_span] #[suggestion( parse_suggestion_remove_eq, - style = "short", + style = "verbose", code = "..=", applicability = "maybe-incorrect" )] @@ -803,13 +852,14 @@ pub(crate) struct InclusiveRangeMatchArrow { #[note] pub(crate) struct InclusiveRangeNoEnd { #[primary_span] + pub span: Span, #[suggestion( parse_suggestion_open_range, - code = "..", + code = "", applicability = "machine-applicable", - style = "short" + style = "verbose" )] - pub span: Span, + pub suggestion: Span, } #[derive(Subdiagnostic)] @@ -824,7 +874,8 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg { #[suggestion( parse_suggestion_use_comma_not_semicolon, code = ",", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] UseComma { #[primary_span] @@ -867,7 +918,7 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[diag(parse_non_string_abi_literal)] pub(crate) struct NonStringAbiLiteral { #[primary_span] - #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")] + #[suggestion(code = "\"C\"", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -890,7 +941,7 @@ pub(crate) struct MismatchedClosingDelimiter { #[help] pub(crate) struct IncorrectVisibilityRestriction { #[primary_span] - #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")] + #[suggestion(code = "in {inner_str}", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub inner_str: String, } @@ -915,7 +966,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr { pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] pub span: Span, - #[suggestion(code = ",", applicability = "machine-applicable")] + #[suggestion(code = ",", applicability = "machine-applicable", style = "verbose")] pub missing_comma: Option, } @@ -923,7 +974,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything { #[diag(parse_const_let_mutually_exclusive)] pub(crate) struct ConstLetMutuallyExclusive { #[primary_span] - #[suggestion(code = "const", applicability = "maybe-incorrect")] + #[suggestion(code = "const", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -951,8 +1002,9 @@ pub(crate) struct InvalidCurlyInLetElse { #[help] pub(crate) struct CompoundAssignmentExpressionInLet { #[primary_span] - #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")] pub span: Span, + #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -996,7 +1048,12 @@ pub(crate) struct SuggEscapeIdentifier { } #[derive(Subdiagnostic)] -#[suggestion(parse_sugg_remove_comma, applicability = "machine-applicable", code = "")] +#[suggestion( + parse_sugg_remove_comma, + applicability = "machine-applicable", + code = "", + style = "verbose" +)] pub(crate) struct SuggRemoveComma { #[primary_span] pub span: Span, @@ -1147,11 +1204,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { #[derive(Subdiagnostic)] pub(crate) enum ExpectedSemiSugg { - #[suggestion(parse_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable")] + #[suggestion( + parse_sugg_change_this_to_semi, + code = ";", + applicability = "machine-applicable", + style = "verbose" + )] ChangeToSemi(#[primary_span] Span), #[suggestion( parse_sugg_add_semi, - style = "short", + style = "verbose", code = ";", applicability = "machine-applicable" )] @@ -1198,7 +1260,7 @@ pub(crate) struct StructLiteralNeedingParensSugg { #[diag(parse_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub num_extra_brackets: usize, } @@ -1337,7 +1399,7 @@ pub(crate) struct AttributeOnParamType { #[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] - #[suggestion(code = "_", applicability = "machine-applicable")] + #[suggestion(code = "_", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -1421,7 +1483,7 @@ pub(crate) struct AsyncMoveOrderIncorrect { pub(crate) struct DoubleColonInBound { #[primary_span] pub span: Span, - #[suggestion(code = ": ", applicability = "machine-applicable")] + #[suggestion(code = ": ", applicability = "machine-applicable", style = "verbose")] pub between: Span, } @@ -1500,7 +1562,7 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { #[diag(parse_path_single_colon)] pub(crate) struct PathSingleColon { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "::")] + #[suggestion(applicability = "machine-applicable", code = "::", style = "verbose")] pub span: Span, #[note(parse_type_ascription_removed)] @@ -1511,7 +1573,7 @@ pub(crate) struct PathSingleColon { #[diag(parse_colon_as_semi)] pub(crate) struct ColonAsSemi { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = ";")] + #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")] pub span: Span, #[note(parse_type_ascription_removed)] @@ -1662,9 +1724,9 @@ pub(crate) enum MissingKeywordForItemDefinition { pub(crate) enum AmbiguousMissingKwForItemSub { #[suggestion( parse_suggestion, - style = "verbose", applicability = "maybe-incorrect", - code = "{snippet}!" + code = "{snippet}!", + style = "verbose" )] SuggestMacro { #[primary_span] @@ -1679,7 +1741,7 @@ pub(crate) enum AmbiguousMissingKwForItemSub { #[diag(parse_missing_fn_params)] pub(crate) struct MissingFnParams { #[primary_span] - #[suggestion(code = "()", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "()", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -1687,9 +1749,19 @@ pub(crate) struct MissingFnParams { #[diag(parse_missing_trait_in_trait_impl)] pub(crate) struct MissingTraitInTraitImpl { #[primary_span] - #[suggestion(parse_suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")] + #[suggestion( + parse_suggestion_add_trait, + code = " Trait ", + applicability = "has-placeholders", + style = "verbose" + )] pub span: Span, - #[suggestion(parse_suggestion_remove_for, code = "", applicability = "maybe-incorrect")] + #[suggestion( + parse_suggestion_remove_for, + code = "", + applicability = "maybe-incorrect", + style = "verbose" + )] pub for_span: Span, } @@ -1697,7 +1769,7 @@ pub(crate) struct MissingTraitInTraitImpl { #[diag(parse_missing_for_in_trait_impl)] pub(crate) struct MissingForInTraitImpl { #[primary_span] - #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = " for ", applicability = "machine-applicable")] pub span: Span, } @@ -1712,7 +1784,7 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { #[diag(parse_extra_impl_keyword_in_trait_impl)] pub(crate) struct ExtraImplKeywordInTraitImpl { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub extra_impl_kw: Span, #[note] pub impl_trait_span: Span, @@ -1771,7 +1843,7 @@ pub(crate) struct ExternCrateNameWithDashesSugg { pub(crate) struct ExternItemCannotBeConst { #[primary_span] pub ident_span: Span, - #[suggestion(code = "static ", applicability = "machine-applicable")] + #[suggestion(code = "static ", applicability = "machine-applicable", style = "verbose")] pub const_span: Option, } @@ -1781,7 +1853,7 @@ pub(crate) struct ConstGlobalCannotBeMutable { #[primary_span] #[label] pub ident_span: Span, - #[suggestion(code = "static", applicability = "maybe-incorrect")] + #[suggestion(code = "static", style = "verbose", applicability = "maybe-incorrect")] pub const_span: Span, } @@ -1789,7 +1861,7 @@ pub(crate) struct ConstGlobalCannotBeMutable { #[diag(parse_missing_const_type)] pub(crate) struct MissingConstType { #[primary_span] - #[suggestion(code = "{colon} ", applicability = "has-placeholders")] + #[suggestion(code = "{colon} ", style = "verbose", applicability = "has-placeholders")] pub span: Span, pub kind: &'static str, @@ -1800,7 +1872,7 @@ pub(crate) struct MissingConstType { #[diag(parse_enum_struct_mutually_exclusive)] pub(crate) struct EnumStructMutuallyExclusive { #[primary_span] - #[suggestion(code = "enum", applicability = "machine-applicable")] + #[suggestion(code = "enum", style = "verbose", applicability = "machine-applicable")] pub span: Span, } @@ -2037,7 +2109,12 @@ pub struct UnknownTokenStart { #[derive(Subdiagnostic)] pub enum TokenSubstitution { - #[suggestion(parse_sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_sugg_quotes, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] DirectedQuotes { #[primary_span] span: Span, @@ -2045,7 +2122,12 @@ pub enum TokenSubstitution { ascii_str: &'static str, ascii_name: &'static str, }, - #[suggestion(parse_sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_sugg_other, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] Other { #[primary_span] span: Span, @@ -2081,7 +2163,12 @@ pub enum UnescapeError { EscapeOnlyChar { #[primary_span] span: Span, - #[suggestion(parse_escape, applicability = "machine-applicable", code = "{escaped_sugg}")] + #[suggestion( + parse_escape, + applicability = "machine-applicable", + code = "{escaped_sugg}", + style = "verbose" + )] char_span: Span, escaped_sugg: String, escaped_msg: String, @@ -2090,7 +2177,12 @@ pub enum UnescapeError { #[diag(parse_bare_cr)] BareCr { #[primary_span] - #[suggestion(parse_escape, applicability = "machine-applicable", code = "\\r")] + #[suggestion( + parse_escape, + applicability = "machine-applicable", + code = "\\r", + style = "verbose" + )] span: Span, double_quotes: bool, }, @@ -2207,7 +2299,8 @@ pub enum MoreThanOneCharSugg { #[suggestion( parse_consider_normalized, code = "{normalized}", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] NormalizedForm { #[primary_span] @@ -2215,13 +2308,23 @@ pub enum MoreThanOneCharSugg { ch: String, normalized: String, }, - #[suggestion(parse_remove_non, code = "{ch}", applicability = "maybe-incorrect")] + #[suggestion( + parse_remove_non, + code = "{ch}", + applicability = "maybe-incorrect", + style = "verbose" + )] RemoveNonPrinting { #[primary_span] span: Span, ch: String, }, - #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")] + #[suggestion( + parse_use_double_quotes, + code = "{sugg}", + applicability = "machine-applicable", + style = "verbose" + )] QuotesFull { #[primary_span] span: Span, @@ -2259,7 +2362,12 @@ pub enum MoreThanOneCharNote { #[derive(Subdiagnostic)] pub enum NoBraceUnicodeSub { - #[suggestion(parse_use_braces, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_use_braces, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] Suggestion { #[primary_span] span: Span, @@ -2269,27 +2377,32 @@ pub enum NoBraceUnicodeSub { Help, } +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_sugg_wrap_pattern_in_parens, applicability = "machine-applicable")] +pub(crate) struct WrapInParens { + #[suggestion_part(code = "(")] + pub(crate) lo: Span, + #[suggestion_part(code = ")")] + pub(crate) hi: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum TopLevelOrPatternNotAllowedSugg { #[suggestion( parse_sugg_remove_leading_vert_in_pattern, - code = "{pat}", - applicability = "machine-applicable" + code = "", + applicability = "machine-applicable", + style = "verbose" )] RemoveLeadingVert { #[primary_span] span: Span, - pat: String, }, - #[suggestion( - parse_sugg_wrap_pattern_in_parens, - code = "({pat})", - applicability = "machine-applicable" - )] WrapInParens { #[primary_span] span: Span, - pat: String, + #[subdiagnostic] + suggestion: WrapInParens, }, } @@ -2298,7 +2411,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg { #[note(parse_note_pattern_alternatives_use_single_vert)] pub(crate) struct UnexpectedVertVertBeforeFunctionParam { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2306,7 +2419,7 @@ pub(crate) struct UnexpectedVertVertBeforeFunctionParam { #[diag(parse_unexpected_vert_vert_in_pattern)] pub(crate) struct UnexpectedVertVertInPattern { #[primary_span] - #[suggestion(code = "|", applicability = "machine-applicable")] + #[suggestion(code = "|", applicability = "machine-applicable", style = "verbose")] pub span: Span, #[label(parse_label_while_parsing_or_pattern_here)] pub start: Option, @@ -2316,7 +2429,7 @@ pub(crate) struct UnexpectedVertVertInPattern { #[diag(parse_trailing_vert_not_allowed)] pub(crate) struct TrailingVertNotAllowed { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, #[label(parse_label_while_parsing_or_pattern_here)] pub start: Option, @@ -2329,16 +2442,17 @@ pub(crate) struct TrailingVertNotAllowed { #[diag(parse_dotdotdot_rest_pattern)] pub(crate) struct DotDotDotRestPattern { #[primary_span] - #[suggestion(style = "short", code = "..", applicability = "machine-applicable")] #[label] pub span: Span, + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub suggestion: Span, } #[derive(Diagnostic)] #[diag(parse_pattern_on_wrong_side_of_at)] pub(crate) struct PatternOnWrongSideOfAt { #[primary_span] - #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")] + #[suggestion(code = "{whole_pat}", applicability = "machine-applicable", style = "verbose")] pub whole_span: Span, pub whole_pat: String, #[label(parse_label_pattern)] @@ -2359,22 +2473,35 @@ pub(crate) struct ExpectedBindingLeftOfAt { pub rhs: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_ambiguous_range_pattern_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct ParenRangeSuggestion { + #[suggestion_part(code = "(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(parse_ambiguous_range_pattern)] pub(crate) struct AmbiguousRangePattern { #[primary_span] - #[suggestion(code = "({pat})", applicability = "maybe-incorrect")] pub span: Span, - pub pat: String, + #[subdiagnostic] + pub suggestion: ParenRangeSuggestion, } #[derive(Diagnostic)] #[diag(parse_unexpected_lifetime_in_pattern)] pub(crate) struct UnexpectedLifetimeInPattern { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, pub symbol: Symbol, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -2383,7 +2510,7 @@ pub(crate) enum InvalidMutInPattern { #[note(parse_note_mut_pattern_usage)] NestedIdent { #[primary_span] - #[suggestion(code = "{pat}", applicability = "machine-applicable")] + #[suggestion(code = "{pat}", applicability = "machine-applicable", style = "verbose")] span: Span, pat: String, }, @@ -2391,7 +2518,7 @@ pub(crate) enum InvalidMutInPattern { #[note(parse_note_mut_pattern_usage)] NonIdent { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] span: Span, }, } @@ -2400,7 +2527,7 @@ pub(crate) enum InvalidMutInPattern { #[diag(parse_repeated_mut_in_pattern)] pub(crate) struct RepeatedMutInPattern { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2408,7 +2535,7 @@ pub(crate) struct RepeatedMutInPattern { #[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)] pub(crate) struct DotDotDotRangeToPatternNotAllowed { #[primary_span] - #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "..=", applicability = "machine-applicable")] pub span: Span, } @@ -2472,8 +2599,9 @@ pub(crate) struct UnexpectedParenInRangePatSugg { #[diag(parse_return_types_use_thin_arrow)] pub(crate) struct ReturnTypesUseThinArrow { #[primary_span] - #[suggestion(style = "short", code = "->", applicability = "machine-applicable")] pub span: Span, + #[suggestion(style = "verbose", code = " -> ", applicability = "machine-applicable")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -2488,7 +2616,7 @@ pub(crate) struct NeedPlusAfterTraitObjectLifetime { pub(crate) struct ExpectedMutOrConstInRawPointerType { #[primary_span] pub span: Span, - #[suggestion(code("mut ", "const "), applicability = "has-placeholders")] + #[suggestion(code("mut ", "const "), applicability = "has-placeholders", style = "verbose")] pub after_asterisk: Span, } @@ -2497,7 +2625,7 @@ pub(crate) struct ExpectedMutOrConstInRawPointerType { pub(crate) struct LifetimeAfterMut { #[primary_span] pub span: Span, - #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")] + #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect", style = "verbose")] pub suggest_lifetime: Option, pub snippet: String, } @@ -2506,7 +2634,7 @@ pub(crate) struct LifetimeAfterMut { #[diag(parse_dyn_after_mut)] pub(crate) struct DynAfterMut { #[primary_span] - #[suggestion(code = "&mut dyn", applicability = "machine-applicable")] + #[suggestion(code = "&mut dyn", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2515,7 +2643,7 @@ pub(crate) struct DynAfterMut { pub(crate) struct FnPointerCannotBeConst { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, } @@ -2525,7 +2653,7 @@ pub(crate) struct FnPointerCannotBeConst { pub(crate) struct FnPointerCannotBeAsync { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, } @@ -2542,8 +2670,9 @@ pub(crate) struct NestedCVariadicType { #[help] pub(crate) struct InvalidDynKeyword { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub suggestion: Span, } #[derive(Subdiagnostic)] @@ -2584,7 +2713,7 @@ pub struct BoxSyntaxRemoved<'a> { #[diag(parse_bad_return_type_notation_output)] pub(crate) struct BadReturnTypeNotationOutput { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -2655,14 +2784,25 @@ pub(crate) struct ModifierLifetime { pub modifier: &'static str, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_parenthesized_lifetime_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct RemoveParens { + #[suggestion_part(code = "")] + pub lo: Span, + #[suggestion_part(code = "")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(parse_parenthesized_lifetime)] pub(crate) struct ParenthesizedLifetime { #[primary_span] pub span: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")] - pub sugg: Option, - pub snippet: String, + #[subdiagnostic] + pub sugg: RemoveParens, } #[derive(Diagnostic)] @@ -2677,7 +2817,7 @@ pub(crate) struct UnderscoreLiteralSuffix { pub(crate) struct ExpectedLabelFoundIdent { #[primary_span] pub span: Span, - #[suggestion(code = "'", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "'", applicability = "machine-applicable", style = "verbose")] pub start: Span, } @@ -2696,7 +2836,7 @@ pub(crate) struct InappropriateDefault { #[diag(parse_recover_import_as_use)] pub(crate) struct RecoverImportAsUse { #[primary_span] - #[suggestion(code = "use", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "use", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub token_name: String, } @@ -2706,7 +2846,7 @@ pub(crate) struct RecoverImportAsUse { #[note] pub(crate) struct SingleColonImportPath { #[primary_span] - #[suggestion(code = "::", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "::", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2733,7 +2873,7 @@ pub(crate) struct SingleColonStructType { #[diag(parse_equals_struct_default)] pub(crate) struct EqualsStructDefault { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2750,7 +2890,7 @@ pub(crate) struct MacroRulesMissingBang { #[diag(parse_macro_name_remove_bang)] pub(crate) struct MacroNameRemoveBang { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2758,7 +2898,7 @@ pub(crate) struct MacroNameRemoveBang { #[diag(parse_macro_rules_visibility)] pub(crate) struct MacroRulesVisibility<'a> { #[primary_span] - #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")] + #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, pub vis: &'a str, } @@ -2768,7 +2908,7 @@ pub(crate) struct MacroRulesVisibility<'a> { #[help] pub(crate) struct MacroInvocationVisibility<'a> { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub vis: &'a str, } @@ -2778,7 +2918,7 @@ pub(crate) struct MacroInvocationVisibility<'a> { pub(crate) struct NestedAdt<'a> { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub item: Span, pub keyword: &'a str, pub kw_str: Cow<'a, str>, @@ -2818,7 +2958,7 @@ pub(crate) struct BoxNotPat { #[diag(parse_unmatched_angle)] pub(crate) struct UnmatchedAngle { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub plural: bool, } @@ -2858,7 +2998,7 @@ pub(crate) struct IncorrectParensTraitBoundsSugg { #[diag(parse_kw_bad_case)] pub(crate) struct KwBadCase<'a> { #[primary_span] - #[suggestion(code = "{kw}", applicability = "machine-applicable")] + #[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")] pub span: Span, pub kw: &'a str, } @@ -2895,7 +3035,7 @@ pub(crate) struct MetaBadDelimSugg { #[note] pub(crate) struct MalformedCfgAttr { #[primary_span] - #[suggestion(code = "{sugg}")] + #[suggestion(style = "verbose", code = "{sugg}")] pub span: Span, pub sugg: &'static str, } @@ -3000,7 +3140,7 @@ pub(crate) struct AsyncImpl { #[help] pub(crate) struct ExprRArrowCall { #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = ".")] pub span: Span, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 81d5f0fca0ec..63e4d8a43523 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -3,8 +3,8 @@ use super::{ BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType, }; use crate::errors::{ - AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus, - BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, + BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, @@ -566,7 +566,10 @@ impl<'a> Parser<'a> { && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq))) { // Likely typo: `=` → `==` in let expr or enum item - return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); + return Err(self.dcx().create_err(UseEqInstead { + span: self.token.span, + suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)), + })); } if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { @@ -1151,7 +1154,7 @@ impl<'a> Parser<'a> { // Eat from where we started until the end token so that parsing can continue // as if we didn't have those extra angle brackets. self.eat_to_tokens(end); - let span = lo.until(self.token.span); + let span = lo.to(self.prev_token.span); let num_extra_brackets = number_of_gt + number_of_shr * 2; return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets })); @@ -1539,7 +1542,10 @@ impl<'a> Parser<'a> { pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) { if impl_dyn_multi { - self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span }); + self.dcx().emit_err(AmbiguousPlus { + span: ty.span, + suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() }, + }); } } @@ -1608,21 +1614,10 @@ impl<'a> Parser<'a> { let sum_span = ty.span.to(self.prev_token.span); let sub = match &ty.kind { - TyKind::Ref(lifetime, mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - s.s.word("&"); - s.print_opt_lifetime(lifetime); - s.print_mutability(mut_ty.mutbl, false); - s.popen(); - s.print_type(&mut_ty.ty); - if !bounds.is_empty() { - s.word(" + "); - s.print_type_bounds(&bounds); - } - s.pclose() - }); - - BadTypePlusSub::AddParen { sum_with_parens, span: sum_span } + TyKind::Ref(_lifetime, mut_ty) => { + let lo = mut_ty.ty.span.shrink_to_lo(); + let hi = self.prev_token.span.shrink_to_hi(); + BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } } TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, _ => BadTypePlusSub::ExpectPath { span: sum_span }, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b2df9a14eb01..4bd20be41712 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -714,7 +714,7 @@ impl<'a> Parser<'a> { type_err.cancel(); self.dcx().emit_err(errors::MalformedLoopLabel { span: label.ident.span, - correct_label: label.ident, + suggestion: label.ident.span.shrink_to_lo(), }); return Ok(expr); } @@ -856,7 +856,7 @@ impl<'a> Parser<'a> { let hi = self.interpolated_or_expr_span(&expr); let span = lo.to(hi); if let Some(lt) = lifetime { - self.error_remove_borrow_lifetime(span, lt.ident.span); + self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span)); } Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) } @@ -1653,6 +1653,7 @@ impl<'a> Parser<'a> { let lo = label_.ident.span; let label = Some(label_); let ate_colon = self.eat(&token::Colon); + let tok_sp = self.token.span; let expr = if self.eat_keyword(kw::While) { self.parse_expr_while(label, lo) } else if self.eat_keyword(kw::For) { @@ -1747,7 +1748,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::RequireColonAfterLabeledExpression { span: expr.span, label: lo, - label_end: lo.shrink_to_hi(), + label_end: lo.between(tok_sp), }); } @@ -2106,7 +2107,7 @@ impl<'a> Parser<'a> { self.bump(); self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart { span: token.span, - correct: pprust::token_to_string(token).into_owned(), + suggestion: token.span.shrink_to_lo(), }); } } @@ -2741,7 +2742,7 @@ impl<'a> Parser<'a> { if !attrs.is_empty() && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess) { - let attributes = x0.span.to(xn.span); + let attributes = x0.span.until(branch_span); let last = xn.span; let ctx = if is_ctx_else { "else" } else { "if" }; self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2c98feeece77..81e2ca2a4907 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2241,9 +2241,13 @@ impl<'a> Parser<'a> { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; + let mut item = item.unwrap().span; + if self.token == token::Comma { + item = item.to(self.token.span); + } self.dcx().emit_err(errors::NestedAdt { span: kw_token.span, - item: item.unwrap().span, + item, kw_str, keyword: keyword.as_str(), }); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 6f2b71771594..e4e89615d716 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -4,11 +4,11 @@ use crate::errors::{ DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, - PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, - TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, - UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, + SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -24,7 +24,7 @@ use rustc_errors::{Applicability, Diag, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -236,11 +236,15 @@ impl<'a> Parser<'a> { if let PatKind::Or(pats) = &pat.kind { let span = pat.span; - let pat = pprust::pat_to_string(&pat); let sub = if pats.len() == 1 { - Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat }) + Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { + span: span.with_hi(span.lo() + BytePos(1)), + }) } else { - Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) + Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { + span, + suggestion: WrapInParens { lo: span.shrink_to_lo(), hi: span.shrink_to_hi() }, + }) }; let err = self.dcx().create_err(match syntax_loc { @@ -599,7 +603,10 @@ impl<'a> Parser<'a> { self.bump(); // `...` // The user probably mistook `...` for a rest pattern `..`. - self.dcx().emit_err(DotDotDotRestPattern { span: lo }); + self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: lo.with_lo(lo.hi() - BytePos(1)), + }); PatKind::Rest } @@ -664,8 +671,13 @@ impl<'a> Parser<'a> { _ => return, } - self.dcx() - .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) }); + self.dcx().emit_err(AmbiguousRangePattern { + span: pat.span, + suggestion: ParenRangeSuggestion { + lo: pat.span.shrink_to_lo(), + hi: pat.span.shrink_to_hi(), + }, + }); } /// Parse `&pat` / `&mut pat`. @@ -674,8 +686,11 @@ impl<'a> Parser<'a> { if let token::Lifetime(name) = self.token.kind { self.bump(); // `'a` - self.dcx() - .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name }); + self.dcx().emit_err(UnexpectedLifetimeInPattern { + span: self.prev_token.span, + symbol: name, + suggestion: self.prev_token.span.until(self.token.span), + }); } let mutbl = self.parse_mutability(); @@ -913,10 +928,13 @@ impl<'a> Parser<'a> { self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }) } token::Gt if no_space => { - let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); + let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(); self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }) } - _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }), + _ => self.dcx().emit_err(InclusiveRangeNoEnd { + span, + suggestion: span.with_lo(span.hi() - BytePos(1)), + }), } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index d65f6ff68eee..70d41de00a7b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -430,8 +430,10 @@ impl<'a> Parser<'a> { let eq_consumed = match self.token.kind { token::BinOpEq(..) => { // Recover `let x = 1` as `let x = 1` - self.dcx() - .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span }); + self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet { + span: self.token.span, + suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)), + }); self.bump(); true } @@ -717,7 +719,7 @@ impl<'a> Parser<'a> { e.cancel(); self.dcx().emit_err(MalformedLoopLabel { span: label.ident.span, - correct_label: label.ident, + suggestion: label.ident.span.shrink_to_lo(), }); *expr = labeled_expr; break 'break_recover None; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1e5b227aaa9b..94321b1dddd9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -209,6 +209,7 @@ impl<'a> Parser<'a> { recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { + let lo = self.prev_token.span; Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( @@ -224,7 +225,10 @@ impl<'a> Parser<'a> { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); - self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span }); + self.dcx().emit_err(ReturnTypesUseThinArrow { + span: self.prev_token.span, + suggestion: lo.between(self.token.span), + }); let ty = self.parse_ty_common( allow_plus, AllowCVariadic::No, @@ -794,8 +798,11 @@ impl<'a> Parser<'a> { { if self.token.is_keyword(kw::Dyn) { // Account for `&dyn Trait + dyn Other`. - self.dcx().emit_err(InvalidDynKeyword { span: self.token.span }); self.bump(); + self.dcx().emit_err(InvalidDynKeyword { + span: self.prev_token.span, + suggestion: self.prev_token.span.until(self.token.span), + }); } bounds.push(self.parse_generic_bound()?); if allow_plus == AllowPlus::No || !self.eat_plus() { @@ -861,7 +868,7 @@ impl<'a> Parser<'a> { if has_parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P)`? - self.recover_paren_lifetime(lo, lt.ident.span)?; + self.recover_paren_lifetime(lo)?; } Ok(bound) } @@ -909,16 +916,12 @@ impl<'a> Parser<'a> { } /// Recover on `('lifetime)` with `(` already eaten. - fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> { + fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); - let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) { - (Some(span), snippet) - } else { - (None, String::new()) - }; + let sugg = errors::RemoveParens { lo, hi: self.prev_token.span }; - self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet }); + self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg }); Ok(()) } diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout index e288f8dfce65..9eb8b391e780 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout @@ -9,9 +9,14 @@ error: expected item, found `;` --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12 | LL | struct S {}; // unexpected semicolon after struct def - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - struct S {}; // unexpected semicolon after struct def +LL + struct S {} // unexpected semicolon after struct def + | error: aborting due to 1 previous error diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index a98bb0764c0e..ac1bc693fab9 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -2,115 +2,214 @@ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:8:13 | LL | let _ = await bar(); - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:12:13 | LL | let _ = await? bar(); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await?; + | ~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:16:13 | LL | let _ = await bar()?; - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar()?.await; + | ~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:20:13 | LL | let _ = await { bar() }; - | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = { bar() }.await; + | ~~~~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:24:13 | LL | let _ = await(bar()); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = (bar()).await; + | ~~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:28:13 | LL | let _ = await { bar() }?; - | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = { bar() }.await?; + | ~~~~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:32:14 | LL | let _ = (await bar())?; - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = (bar().await)?; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:36:24 | LL | let _ = bar().await(); - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:40:24 | LL | let _ = bar().await()?; - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await()?; +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:52:13 | LL | let _ = await bar(); - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:56:13 | LL | let _ = await? bar(); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await?; + | ~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:60:13 | LL | let _ = await bar()?; - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar()?.await; + | ~~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:64:14 | LL | let _ = (await bar())?; - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = (bar().await)?; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:68:24 | LL | let _ = bar().await(); - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:73:24 | LL | let _ = bar().await()?; - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await()?; +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:101:13 | LL | let _ = await!(bar()); - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:105:13 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await?; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:110:17 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await?; + | ~~~~~~~~~~~ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:117:17 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | let _ = bar().await?; + | ~~~~~~~~~~~ error: expected expression, found `=>` --> $DIR/incorrect-syntax-suggestions.rs:124:25 @@ -124,7 +223,12 @@ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:124:11 | LL | match await { await => () } - | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | match { await => () }.await + | ~~~~~~~~~~~~~~~~~~~~~ error: expected one of `.`, `?`, `{`, or an operator, found `}` --> $DIR/incorrect-syntax-suggestions.rs:127:1 diff --git a/tests/ui/attributes/issue-90873.stderr b/tests/ui/attributes/issue-90873.stderr index 5a8bbaf8ec19..444497538e8d 100644 --- a/tests/ui/attributes/issue-90873.stderr +++ b/tests/ui/attributes/issue-90873.stderr @@ -32,7 +32,12 @@ error: missing type for `static` item --> $DIR/issue-90873.rs:1:17 | LL | #![u=||{static d=||1;}] - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | #![u=||{static d: =||1;}] + | ++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 8084a6220456..759df3c90c6f 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -2,9 +2,13 @@ error: malformed `cfg_attr` attribute input --> $DIR/cfg-attr-parse.rs:4:1 | LL | #[cfg_attr()] - | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: expected `,`, found end of `cfg_attr` input --> $DIR/cfg-attr-parse.rs:8:17 diff --git a/tests/ui/consts/const-eval/issue-104390.stderr b/tests/ui/consts/const-eval/issue-104390.stderr index 865b9996ea39..4c425ecfc130 100644 --- a/tests/ui/consts/const-eval/issue-104390.stderr +++ b/tests/ui/consts/const-eval/issue-104390.stderr @@ -38,28 +38,43 @@ error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:3:25 | LL | fn f3() -> impl Sized { &'a 2E } - | ^--^^^ + | ^---^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f3() -> impl Sized { &'a 2E } +LL + fn f3() -> impl Sized { &2E } + | error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:5:25 | LL | fn f4() -> impl Sized { &'static 2E } - | ^-------^^^ + | ^--------^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f4() -> impl Sized { &'static 2E } +LL + fn f4() -> impl Sized { &2E } + | error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:8:25 | LL | fn f6() -> impl Sized { &'_ 2E } - | ^--^^^ + | ^---^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f6() -> impl Sized { &'_ 2E } +LL + fn f6() -> impl Sized { &2E } + | error: aborting due to 9 previous errors diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index a5868fcf19cf..2bcf54860eb8 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -106,10 +106,13 @@ error: expected identifier, found `,` --> $DIR/bad-syntax.rs:42:12 | LL | #[coverage(,off)] - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - #[coverage(,off)] +LL + #[coverage(off)] + | error: multiple `coverage` attributes --> $DIR/bad-syntax.rs:7:1 diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr index 58ac6e90823f..5f289da8a6c3 100644 --- a/tests/ui/did_you_mean/E0178.stderr +++ b/tests/ui/did_you_mean/E0178.stderr @@ -2,19 +2,34 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` --> $DIR/E0178.rs:6:8 | LL | w: &'a Foo + Copy, - | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)` + | ^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | w: &'a (Foo + Copy), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` --> $DIR/E0178.rs:7:8 | LL | x: &'a Foo + 'a, - | ^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + 'a)` + | ^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | x: &'a (Foo + 'a), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` --> $DIR/E0178.rs:8:8 | LL | y: &'a mut Foo + 'a, - | ^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'a mut (Foo + 'a)` + | ^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | y: &'a mut (Foo + 'a), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` --> $DIR/E0178.rs:9:8 diff --git a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr index 2a3242abea49..952ac76a003d 100644 --- a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr +++ b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr @@ -2,39 +2,56 @@ error: `~` cannot be used as a unary operator --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:4:14 | LL | let _x = ~1; - | ^ help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let _x = !1; + | ~ error: unexpected `1` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:5:18 | LL | let _y = not 1; - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let _y = !1; + | ~ error: unexpected keyword `false` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:6:18 | LL | let _z = not false; - | ----^^^^^ - | | - | help: use `!` to perform logical negation + | ^^^^^ + | +help: use `!` to perform logical negation + | +LL | let _z = !false; + | ~ error: unexpected keyword `true` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:7:18 | LL | let _a = not true; - | ----^^^^ - | | - | help: use `!` to perform logical negation + | ^^^^ + | +help: use `!` to perform logical negation + | +LL | let _a = !true; + | ~ error: unexpected `v` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:9:18 | LL | let _v = not v; - | ----^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | let _v = !v; + | ~ error: aborting due to 5 previous errors diff --git a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index 14918ba89532..6dea6a4fac8f 100644 --- a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -2,25 +2,34 @@ error: unexpected `for_you` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:3:12 | LL | if not for_you { - | ----^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | if !for_you { + | ~ error: unexpected `the_worst` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:11:15 | LL | while not the_worst { - | ----^^^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | while !the_worst { + | ~ error: unexpected `println` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:9 | -LL | if not // lack of braces is [sic] - | ----- help: use `!` to perform logical negation or bitwise not LL | println!("Then when?"); | ^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | if !// lack of braces is [sic] + | ~ error: expected `{`, found `;` --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31 @@ -40,17 +49,23 @@ error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 | LL | let resource = not 2; - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let resource = !2; + | ~ error: unexpected `be_smothered_out_before` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:32:27 | LL | let young_souls = not be_smothered_out_before; - | ----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | let young_souls = !be_smothered_out_before; + | ~ error: aborting due to 6 previous errors diff --git a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr index cbe59e8e0af7..c52102e2631d 100644 --- a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr +++ b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr @@ -2,65 +2,97 @@ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15 | LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | let _ = a && b; + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10 | LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15 | LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | let _ = a || b; + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10 | LL | if a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if a || b { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11 | LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if (a && b) { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11 | LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if (a || b) { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13 | LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | while a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13 | LL | while a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | while a || b { + | ~~ error[E0308]: mismatched types --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33 diff --git a/tests/ui/did_you_mean/issue-54109-without-witness.stderr b/tests/ui/did_you_mean/issue-54109-without-witness.stderr index 6455b0863f8f..ee6d9901fcf6 100644 --- a/tests/ui/did_you_mean/issue-54109-without-witness.stderr +++ b/tests/ui/did_you_mean/issue-54109-without-witness.stderr @@ -2,65 +2,97 @@ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:13:15 | LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | let _ = a && b; + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:15:10 | LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:24:15 | LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | let _ = a || b; + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:26:10 | LL | if a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if a || b { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:34:11 | LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if (a && b) { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:42:11 | LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if (a || b) { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:50:13 | LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | while a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:58:13 | LL | while a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | while a || b { + | ~~ error: aborting due to 8 previous errors diff --git a/tests/ui/did_you_mean/pub-macro-rules.stderr b/tests/ui/did_you_mean/pub-macro-rules.stderr index ba9020460cea..fb9148748ca1 100644 --- a/tests/ui/did_you_mean/pub-macro-rules.stderr +++ b/tests/ui/did_you_mean/pub-macro-rules.stderr @@ -2,7 +2,12 @@ error: can't qualify macro_rules invocation with `pub` --> $DIR/pub-macro-rules.rs:2:5 | LL | pub macro_rules! foo { - | ^^^ help: try exporting the macro: `#[macro_export]` + | ^^^ + | +help: try exporting the macro + | +LL | #[macro_export] macro_rules! foo { + | ~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 68734cd4ccd6..a33a8c776c8e 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -2,13 +2,23 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^^^^^^^^^^^ help: try adding parentheses: `&(Copy + 'static)` + | ^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &(Copy + 'static); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 | LL | let _: &'static Copy + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &'static (Copy + 'static); + | + + error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 diff --git a/tests/ui/did_you_mean/use_instead_of_import.stderr b/tests/ui/did_you_mean/use_instead_of_import.stderr index 2aac8f68c5eb..f8d6de8a1176 100644 --- a/tests/ui/did_you_mean/use_instead_of_import.stderr +++ b/tests/ui/did_you_mean/use_instead_of_import.stderr @@ -2,25 +2,45 @@ error: expected item, found `import` --> $DIR/use_instead_of_import.rs:3:1 | LL | import std::{ - | ^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::{ + | ~~~ error: expected item, found `require` --> $DIR/use_instead_of_import.rs:9:1 | LL | require std::time::Duration; - | ^^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::time::Duration; + | ~~~ error: expected item, found `include` --> $DIR/use_instead_of_import.rs:12:1 | LL | include std::time::Instant; - | ^^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::time::Instant; + | ~~~ error: expected item, found `using` --> $DIR/use_instead_of_import.rs:15:5 | LL | pub using std::io; - | ^^^^^ help: items are imported using the `use` keyword + | ^^^^^ + | +help: items are imported using the `use` keyword + | +LL | pub use std::io; + | ~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/enum/nested-enum.stderr b/tests/ui/enum/nested-enum.stderr index 7d6f57e88a82..0f9c8025c452 100644 --- a/tests/ui/enum/nested-enum.stderr +++ b/tests/ui/enum/nested-enum.stderr @@ -2,25 +2,37 @@ error: `enum` definition cannot be nested inside `enum` --> $DIR/nested-enum.rs:2:5 | LL | enum Bar { Baz }, - | ^^^^------------ - | | - | help: consider creating a new `enum` definition instead of nesting + | ^^^^ + | +help: consider creating a new `enum` definition instead of nesting + | +LL - enum Bar { Baz }, +LL + + | error: `struct` definition cannot be nested inside `enum` --> $DIR/nested-enum.rs:3:5 | LL | struct Quux { field: u8 }, - | ^^^^^^------------------- - | | - | help: consider creating a new `struct` definition instead of nesting + | ^^^^^^ + | +help: consider creating a new `struct` definition instead of nesting + | +LL - struct Quux { field: u8 }, +LL + + | error: `union` definition cannot be nested inside `enum` --> $DIR/nested-enum.rs:4:5 | LL | union Wibble { field: u8 }, - | ^^^^^--------------------- - | | - | help: consider creating a new `union` definition instead of nesting + | ^^^^^ + | +help: consider creating a new `union` definition instead of nesting + | +LL - union Wibble { field: u8 }, +LL + + | error: aborting due to 3 previous errors diff --git a/tests/ui/error-codes/E0586.stderr b/tests/ui/error-codes/E0586.stderr index f562e358cba1..b3e07220d3d4 100644 --- a/tests/ui/error-codes/E0586.stderr +++ b/tests/ui/error-codes/E0586.stderr @@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end --> $DIR/E0586.rs:3:19 | LL | let x = &tmp[1..=]; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - let x = &tmp[1..=]; +LL + let x = &tmp[1..]; + | error: aborting due to 1 previous error diff --git a/tests/ui/expr/if/attrs/else-attrs.stderr b/tests/ui/expr/if/attrs/else-attrs.stderr index 2733377054d7..c4e51406d57b 100644 --- a/tests/ui/expr/if/attrs/else-attrs.stderr +++ b/tests/ui/expr/if/attrs/else-attrs.stderr @@ -9,12 +9,17 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | } else #[attr] if false { | _______----_^^^^^^^_- - | | | | - | | | help: remove the attributes + | | | | | the branch belongs to this `else` LL | | } else { LL | | } | |_____- the attributes are attached to this branch + | +help: remove the attributes + | +LL - } else #[attr] if false { +LL + } else if false { + | error: expected expression, found keyword `else` --> $DIR/else-attrs.rs:20:15 diff --git a/tests/ui/extern/extern-const.stderr b/tests/ui/extern/extern-const.stderr index 31954ca2c843..441495866cd9 100644 --- a/tests/ui/extern/extern-const.stderr +++ b/tests/ui/extern/extern-const.stderr @@ -2,11 +2,13 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:14:11 | LL | const rust_dbg_static_mut: c_int; - | ------^^^^^^^^^^^^^^^^^^^ - | | - | help: try using a static value: `static` + | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static rust_dbg_static_mut: c_int; + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr index dfd24bf60ad5..d5fe4081ac81 100644 --- a/tests/ui/fmt/format-string-error-2.stderr +++ b/tests/ui/fmt/format-string-error-2.stderr @@ -2,7 +2,12 @@ error: incorrect unicode escape sequence --> $DIR/format-string-error-2.rs:77:20 | LL | println!("\x7B}\u8 {", 1); - | ^^^ help: format of unicode escape sequences uses braces: `\u{8}` + | ^^^ + | +help: format of unicode escape sequences uses braces + | +LL | println!("\x7B}\u{8} {", 1); + | ~~~~~ error: invalid format string: expected `'}'`, found `'a'` --> $DIR/format-string-error-2.rs:5:5 diff --git a/tests/ui/fn/fn-recover-return-sign.fixed b/tests/ui/fn/fn-recover-return-sign.fixed index 20dca91fdf41..1da10a6d8fe2 100644 --- a/tests/ui/fn/fn-recover-return-sign.fixed +++ b/tests/ui/fn/fn-recover-return-sign.fixed @@ -3,7 +3,7 @@ fn a() -> usize { 0 } //~^ ERROR return types are denoted using `->` -fn b()-> usize { 0 } +fn b() -> usize { 0 } //~^ ERROR return types are denoted using `->` fn bar(_: u32) {} @@ -22,7 +22,7 @@ fn main() { //~^ ERROR return types are denoted using `->` dbg!(foo(false)); - let bar = |a: bool|-> bool { a }; + let bar = |a: bool| -> bool { a }; //~^ ERROR return types are denoted using `->` dbg!(bar(false)); } diff --git a/tests/ui/fn/fn-recover-return-sign.stderr b/tests/ui/fn/fn-recover-return-sign.stderr index 983109730ff3..e6012f3f9502 100644 --- a/tests/ui/fn/fn-recover-return-sign.stderr +++ b/tests/ui/fn/fn-recover-return-sign.stderr @@ -2,25 +2,45 @@ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:3:8 | LL | fn a() => usize { 0 } - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | fn a() -> usize { 0 } + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:6:7 | LL | fn b(): usize { 0 } - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn b() -> usize { 0 } + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:21:25 | LL | let foo = |a: bool| => bool { a }; - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | let foo = |a: bool| -> bool { a }; + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:25:24 | LL | let bar = |a: bool|: bool { a }; - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | let bar = |a: bool| -> bool { a }; + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/fn/fn-recover-return-sign2.stderr b/tests/ui/fn/fn-recover-return-sign2.stderr index 25ee8dd0c5dc..fb88ff7b9504 100644 --- a/tests/ui/fn/fn-recover-return-sign2.stderr +++ b/tests/ui/fn/fn-recover-return-sign2.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign2.rs:4:10 | LL | fn foo() => impl Fn() => bool { - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | fn foo() -> impl Fn() => bool { + | ~~ error: expected one of `+`, `->`, `::`, `where`, or `{`, found `=>` --> $DIR/fn-recover-return-sign2.rs:4:23 diff --git a/tests/ui/generics/issue-95208-ignore-qself.stderr b/tests/ui/generics/issue-95208-ignore-qself.stderr index cf40e857d42b..7d91fbc14a18 100644 --- a/tests/ui/generics/issue-95208-ignore-qself.stderr +++ b/tests/ui/generics/issue-95208-ignore-qself.stderr @@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime --> $DIR/issue-95208-ignore-qself.rs:6:88 | LL | impl Struct where ::Item:: std::fmt::Display { - | --- ^ - | | - | help: use single colon: `:` + | ^ + | +help: use single colon + | +LL | impl Struct where ::Item: std::fmt::Display { + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/generics/issue-95208.stderr b/tests/ui/generics/issue-95208.stderr index 0d856d096aff..e047f1265e2e 100644 --- a/tests/ui/generics/issue-95208.stderr +++ b/tests/ui/generics/issue-95208.stderr @@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime --> $DIR/issue-95208.rs:6:46 | LL | impl Struct where T:: std::fmt::Display { - | --- ^ - | | - | help: use single colon: `:` + | ^ + | +help: use single colon + | +LL | impl Struct where T: std::fmt::Display { + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index d61562bb199f..06203b5e6fe7 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -4,9 +4,13 @@ error: path separator must be a double colon LL | pub struct Foo { | --- while parsing this struct LL | a: Vec, - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | a: Vec, + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr index 0d2aae689f03..0f60cd397b99 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr @@ -2,36 +2,60 @@ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:15:9 | LL | ...X => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=X => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:16:9 | LL | ...0 => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=0 => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9 | LL | ...'a' => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..='a' => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9 | LL | ...0.0f32 => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=0.0f32 => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17 | LL | let ...$e; - | ^^^ help: use `..=` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..=` instead + | +LL | let ..=$e; + | ~~~ error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17 diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr index 9ba0e09e1540..204ee373bc53 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr @@ -2,57 +2,87 @@ error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:8:13 | LL | if let 0... = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0... = 1 {} +LL + if let 0.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:9:13 | LL | if let 0..= = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0..= = 1 {} +LL + if let 0.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13 | LL | if let X... = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X... = 1 {} +LL + if let X.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:12:13 | LL | if let X..= = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X..= = 1 {} +LL + if let X.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:19 | LL | let $e...; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e...; +LL + let $e..; + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:19 | LL | let $e..=; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e..=; +LL + let $e..; + | error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:17 diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr index 111e81799625..83a374c3d65d 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr @@ -2,53 +2,93 @@ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:6:10 | LL | &0.. | _ => {} - | ^^^ help: add parentheses to clarify the precedence: `(0..)` + | ^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(0..) | _ => {} + | + + error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:11 | LL | &0..= | _ => {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - &0..= | _ => {} +LL + &0.. | _ => {} + | error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10 | LL | &0..= | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(0..=)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(0..=) | _ => {} + | + + error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:11:11 | LL | &0... | _ => {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - &0... | _ => {} +LL + &0.. | _ => {} + | error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:16:10 | LL | &..0 | _ => {} - | ^^^ help: add parentheses to clarify the precedence: `(..0)` + | ^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(..0) | _ => {} + | + + error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10 | LL | &..=0 | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(..=0)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(..=0) | _ => {} + | + + error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10 | LL | &...0 | _ => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | &..=0 | _ => {} + | ~~~ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10 | LL | &...0 | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(..=0)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(...0) | _ => {} + | + + error: aborting due to 8 previous errors diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr index 91c7da5a04fb..e4d14c4807c9 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -2,25 +2,35 @@ error: unexpected `impl` keyword --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { - | ^^^^^ help: remove the extra `impl` + | ^^^^^ | note: this is parsed as an `impl Trait` type, but a trait is expected at this position --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { | ^^^^^^^^^^^^ +help: remove the extra `impl` + | +LL - impl impl Default for S { +LL + impl Default for S { + | error: unexpected `impl` keyword --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { - | ^^^^^ help: remove the extra `impl` + | ^^^^^ | note: this is parsed as an `impl Trait` type, but a trait is expected at this position --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { | ^^^^^^^^^^^^ +help: remove the extra `impl` + | +LL - impl impl Default for S2 { +LL + impl Default for S2 { + | error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr index e0955faac7ca..94b6ffdd9123 100644 --- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr @@ -2,13 +2,23 @@ error: ambiguous `+` in a type --> $DIR/impl-fn-parsing-ambiguities.rs:4:27 | LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { - | ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)` + | ^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { + | + + error: ambiguous `+` in a type --> $DIR/impl-fn-parsing-ambiguities.rs:10:24 | LL | fn b() -> impl Fn() -> impl Debug + Send { - | ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)` + | ^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn b() -> impl Fn() -> (impl Debug + Send) { + | + + error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` --> $DIR/impl-fn-parsing-ambiguities.rs:4:40 diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr index 205d9b0b75ea..03e7910095a9 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr +++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr @@ -2,19 +2,34 @@ error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:23:18 | LL | type A = fn() -> impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:25:18 | LL | type A = fn() -> impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:27:18 | LL | type A = fn() -> dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (dyn A + B); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` --> $DIR/impl-trait-plus-priority.rs:29:10 @@ -26,43 +41,78 @@ error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:32:18 | LL | type A = Fn() -> impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:34:18 | LL | type A = Fn() -> impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:36:18 | LL | type A = Fn() -> dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (dyn A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:40:11 | LL | type A = &impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:42:11 | LL | type A = &impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:44:11 | LL | type A = &dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(dyn A + B); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&A` --> $DIR/impl-trait-plus-priority.rs:46:10 | LL | type A = &A + B; - | ^^^^^^ help: try adding parentheses: `&(A + B)` + | ^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(A + B); + | + + error: aborting due to 11 previous errors diff --git a/tests/ui/issues/issue-40782.stderr b/tests/ui/issues/issue-40782.stderr index 81f419bf687f..614980202385 100644 --- a/tests/ui/issues/issue-40782.stderr +++ b/tests/ui/issues/issue-40782.stderr @@ -2,13 +2,23 @@ error: missing `in` in `for` loop --> $DIR/issue-40782.rs:4:11 | LL | for _i 0..2 { - | ^ help: try adding `in` here + | ^ + | +help: try adding `in` here + | +LL | for _i in 0..2 { + | ++ error: missing `in` in `for` loop --> $DIR/issue-40782.rs:6:12 | LL | for _i of 0..2 { - | ^^ help: try using `in` here instead + | ^^ + | +help: try using `in` here instead + | +LL | for _i in 0..2 { + | ~~ error: aborting due to 2 previous errors diff --git a/tests/ui/label/label_misspelled_2.stderr b/tests/ui/label/label_misspelled_2.stderr index 960646d9894d..10b0e7b4e088 100644 --- a/tests/ui/label/label_misspelled_2.stderr +++ b/tests/ui/label/label_misspelled_2.stderr @@ -2,13 +2,23 @@ error: malformed loop label --> $DIR/label_misspelled_2.rs:10:5 | LL | c: for _ in 0..1 { - | ^ help: use the correct loop label format: `'c` + | ^ + | +help: use the correct loop label format + | +LL | 'c: for _ in 0..1 { + | + error: malformed loop label --> $DIR/label_misspelled_2.rs:13:5 | LL | d: for _ in 0..1 { - | ^ help: use the correct loop label format: `'d` + | ^ + | +help: use the correct loop label format + | +LL | 'd: for _ in 0..1 { + | + error[E0425]: cannot find value `b` in this scope --> $DIR/label_misspelled_2.rs:8:15 diff --git a/tests/ui/let-else/let-else-missing-semicolon.stderr b/tests/ui/let-else/let-else-missing-semicolon.stderr index 99029ff33fe0..778a0e244f81 100644 --- a/tests/ui/let-else/let-else-missing-semicolon.stderr +++ b/tests/ui/let-else/let-else-missing-semicolon.stderr @@ -2,17 +2,27 @@ error: expected `;`, found keyword `let` --> $DIR/let-else-missing-semicolon.rs:4:6 | LL | } - | ^ help: add `;` here + | ^ LL | let _ = ""; | --- unexpected token + | +help: add `;` here + | +LL | }; + | + error: expected `;`, found `}` --> $DIR/let-else-missing-semicolon.rs:8:6 | LL | } - | ^ help: add `;` here + | ^ LL | } | - unexpected token + | +help: add `;` here + | +LL | }; + | + error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr index 1a21fed63bde..da80991c727f 100644 --- a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr +++ b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr @@ -26,7 +26,12 @@ error: bare CR not allowed in string, use `\r` instead --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18 | LL | let _s = "foo bar"; - | ^ help: escape the character: `\r` + | ^ + | +help: escape the character + | +LL | let _s = "foo\rbar"; + | ++ error: bare CR not allowed in raw string --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19 diff --git a/tests/ui/macros/bang-after-name.stderr b/tests/ui/macros/bang-after-name.stderr index 27853161e4f3..8433c375c01b 100644 --- a/tests/ui/macros/bang-after-name.stderr +++ b/tests/ui/macros/bang-after-name.stderr @@ -2,7 +2,13 @@ error: macro names aren't followed by a `!` --> $DIR/bang-after-name.rs:4:17 | LL | macro_rules! foo! { - | ^ help: remove the `!` + | ^ + | +help: remove the `!` + | +LL - macro_rules! foo! { +LL + macro_rules! foo { + | error: aborting due to 1 previous error diff --git a/tests/ui/macros/missing-bang-in-decl.stderr b/tests/ui/macros/missing-bang-in-decl.stderr index aa78c9a69064..348a94ec2c05 100644 --- a/tests/ui/macros/missing-bang-in-decl.stderr +++ b/tests/ui/macros/missing-bang-in-decl.stderr @@ -24,7 +24,13 @@ error: macro names aren't followed by a `!` --> $DIR/missing-bang-in-decl.rs:10:16 | LL | macro_rules bar! { - | ^ help: remove the `!` + | ^ + | +help: remove the `!` + | +LL - macro_rules bar! { +LL + macro_rules bar { + | error: aborting due to 3 previous errors diff --git a/tests/ui/macros/recovery-allowed.stderr b/tests/ui/macros/recovery-allowed.stderr index 44689853dabc..825f7a8faf8e 100644 --- a/tests/ui/macros/recovery-allowed.stderr +++ b/tests/ui/macros/recovery-allowed.stderr @@ -2,9 +2,12 @@ error: unexpected `1` after identifier --> $DIR/recovery-allowed.rs:5:23 | LL | please_recover! { not 1 } - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | please_recover! { !1 } + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/malformed/malformed-special-attrs.stderr b/tests/ui/malformed/malformed-special-attrs.stderr index 1764c3969cfe..8f2ce20593f5 100644 --- a/tests/ui/malformed/malformed-special-attrs.stderr +++ b/tests/ui/malformed/malformed-special-attrs.stderr @@ -2,17 +2,25 @@ error: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:1:1 | LL | #[cfg_attr] - | ^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:4:1 | LL | #[cfg_attr = ""] - | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 diff --git a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr index 517f910080de..4ff45d7a8485 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/avoid-ice-on-warning.rs:4:23 | LL | fn call_this(f: F) : Fn(&str) + call_that {} - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn call_this(f: F) -> Fn(&str) + call_that {} + | ~~ error[E0405]: cannot find trait `call_that` in this scope --> $DIR/avoid-ice-on-warning.rs:4:36 diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr index 3939c06eabe5..de45ec8c405a 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/avoid-ice-on-warning.rs:4:23 | LL | fn call_this(f: F) : Fn(&str) + call_that {} - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn call_this(f: F) -> Fn(&str) + call_that {} + | ~~ error[E0405]: cannot find trait `call_that` in this scope --> $DIR/avoid-ice-on-warning.rs:4:36 diff --git a/tests/ui/operator-recovery/less-than-greater-than.stderr b/tests/ui/operator-recovery/less-than-greater-than.stderr index 21b2e77db9aa..36a4a81035f1 100644 --- a/tests/ui/operator-recovery/less-than-greater-than.stderr +++ b/tests/ui/operator-recovery/less-than-greater-than.stderr @@ -2,7 +2,12 @@ error: invalid comparison operator `<>` --> $DIR/less-than-greater-than.rs:2:22 | LL | println!("{}", 1 <> 2); - | ^^ help: `<>` is not a valid comparison operator, use `!=` + | ^^ + | +help: `<>` is not a valid comparison operator, use `!=` + | +LL | println!("{}", 1 != 2); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.stderr b/tests/ui/or-patterns/fn-param-wrap-parens.stderr index 1b9614a13782..da2832ef1ae4 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.stderr +++ b/tests/ui/or-patterns/fn-param-wrap-parens.stderr @@ -2,7 +2,12 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/fn-param-wrap-parens.rs:13:9 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun1((A | B): E) {} + | + + error: aborting due to 1 previous error diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr index 9b827794f5be..91db3d049f62 100644 --- a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr +++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr @@ -4,7 +4,13 @@ error: a trailing `|` is not allowed in an or-pattern LL | E::A | | ---- while parsing this or-pattern starting here LL | E::B | - | ^ help: remove the `|` + | ^ + | +help: remove the `|` + | +LL - E::B | +LL + E::B + | error[E0308]: mismatched types --> $DIR/issue-64879-trailing-before-guard.rs:12:42 diff --git a/tests/ui/or-patterns/multiple-pattern-typo.stderr b/tests/ui/or-patterns/multiple-pattern-typo.stderr index b0a82b3673b8..2e66f54979b0 100644 --- a/tests/ui/or-patterns/multiple-pattern-typo.stderr +++ b/tests/ui/or-patterns/multiple-pattern-typo.stderr @@ -2,55 +2,90 @@ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:7:15 | LL | 1 | 2 || 3 => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | 1 | 2 | 3 => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:12:16 | LL | (1 | 2 || 3) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | (1 | 2 | 3) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:17:16 | LL | (1 | 2 || 3,) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | (1 | 2 | 3,) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:24:18 | LL | TS(1 | 2 || 3) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | TS(1 | 2 | 3) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:31:23 | LL | NS { f: 1 | 2 || 3 } => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | NS { f: 1 | 2 | 3 } => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:36:16 | LL | [1 | 2 || 3] => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | [1 | 2 | 3] => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:41:9 | LL | || 1 | 2 | 3 => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | | 1 | 2 | 3 => (), + | ~ error: aborting due to 7 previous errors diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr index 5a63e621f4a3..f16d83ecaea9 100644 --- a/tests/ui/or-patterns/nested-undelimited-precedence.stderr +++ b/tests/ui/or-patterns/nested-undelimited-precedence.stderr @@ -2,31 +2,56 @@ error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:19:9 | LL | let b @ A | B: E = A; - | ^^^^^^^^^ help: wrap the pattern in parentheses: `(b @ A | B)` + | ^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (b @ A | B): E = A; + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:34:9 | LL | let &A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&A(_) | B(_))` + | ^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:36:9 | LL | let &&A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&A(_) | B(_))` + | ^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&&A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:38:9 | LL | let &mut A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&mut A(_) | B(_))` + | ^^^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&mut A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:40:9 | LL | let &&mut A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&mut A(_) | B(_))` + | ^^^^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&&mut A(_) | B(_)): F = A(3); + | + + error[E0408]: variable `b` is not bound in all patterns --> $DIR/nested-undelimited-precedence.rs:19:17 diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr index e09194d5d397..5608138078fb 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -16,25 +16,45 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/or-patterns-syntactic-fail.rs:18:13 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun1((A | B): E) {} + | + + error: top-level or-patterns are not allowed in function parameters --> $DIR/or-patterns-syntactic-fail.rs:21:13 | LL | fn fun2(| A | B: E) {} - | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun2((| A | B): E) {} + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/or-patterns-syntactic-fail.rs:26:9 | LL | let A | B: E = A; - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (A | B): E = A; + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/or-patterns-syntactic-fail.rs:29:9 | LL | let | A | B: E = A; - | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (| A | B): E = A; + | + + error: aborting due to 5 previous errors diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed index 8f7aab6a4991..3ec815c84684 100644 --- a/tests/ui/or-patterns/remove-leading-vert.fixed +++ b/tests/ui/or-patterns/remove-leading-vert.fixed @@ -8,7 +8,7 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed + fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter let ( | A): E; let ( | A): (E); //~ ERROR unexpected token `||` in pattern diff --git a/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr index af51c67e1c8b..5177e98f0d90 100644 --- a/tests/ui/or-patterns/remove-leading-vert.stderr +++ b/tests/ui/or-patterns/remove-leading-vert.stderr @@ -2,161 +2,279 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/remove-leading-vert.rs:11:14 | LL | fn fun1( | A: E) {} - | ^^^ help: remove the `|`: `A` + | ^^^ + | +help: remove the `|` + | +LL - fn fun1( | A: E) {} +LL + fn fun1( A: E) {} + | error: unexpected `||` before function parameter --> $DIR/remove-leading-vert.rs:12:14 | LL | fn fun2( || A: E) {} - | ^^ help: remove the `||` + | ^^ | = note: alternatives in or-patterns are separated with `|`, not `||` +help: remove the `||` + | +LL - fn fun2( || A: E) {} +LL + fn fun2( A: E) {} + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:14:11 | LL | let ( || A): (E); - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let ( | A): (E); + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:17:11 | LL | let [ || A ]: [E; 1]; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let [ | A ]: [E; 1]; + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:19:13 | LL | let TS( || A ): TS; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let TS( | A ): TS; + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:21:17 | LL | let NS { f: || A }: NS; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let NS { f: | A }: NS; + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:26:13 | LL | let ( A | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A | ): E; +LL + let ( A ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:27:12 | LL | let (a |,): (E,); - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let (a |,): (E,); +LL + let (a ,): (E,); + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:28:17 | LL | let ( A | B | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A | B | ): E; +LL + let ( A | B ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:29:17 | LL | let [ A | B | ]: [E; 1]; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let [ A | B | ]: [E; 1]; +LL + let [ A | B ]: [E; 1]; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:30:18 | LL | let S { f: B | }; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let S { f: B | }; +LL + let S { f: B }; + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:31:13 | LL | let ( A || B | ): E; - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let ( A | B | ): E; + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:31:18 | LL | let ( A || B | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A || B | ): E; +LL + let ( A || B ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:34:11 | LL | A | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - A | => {} +LL + A => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:35:11 | LL | A || => {} - | - ^^ help: remove the `||` + | - ^^ | | | while parsing this or-pattern starting here | = note: alternatives in or-patterns are separated with `|`, not `||` +help: remove the `||` + | +LL - A || => {} +LL + A => {} + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:36:11 | LL | A || B | => {} - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | A | B | => {} + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:36:16 | LL | A || B | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - A || B | => {} +LL + A || B => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:38:17 | LL | | A | B | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - | A | B | => {} +LL + | A | B => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:45:11 | LL | let a | : u8 = 0; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | : u8 = 0; +LL + let a : u8 = 0; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:46:11 | LL | let a | = 0; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | = 0; +LL + let a = 0; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:47:11 | LL | let a | ; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | ; +LL + let a ; + | error: aborting due to 21 previous errors diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index 3593c5182ce9..1ba130e20b57 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -154,9 +154,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:40:38 @@ -178,9 +183,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:46:46 @@ -196,18 +206,28 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | ---- ^^^^^^^ ------- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } + | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:50:50 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:52:51 @@ -223,9 +243,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:56:46 @@ -247,9 +272,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:62:54 @@ -265,18 +295,28 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } | ---- ^^^^^^^ --------------- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } + | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:66:66 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:68:67 @@ -361,9 +401,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:85:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:85:38 @@ -375,9 +420,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 @@ -395,9 +445,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:93:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:93:38 diff --git a/tests/ui/parser/bad-char-literals.stderr b/tests/ui/parser/bad-char-literals.stderr index a22ddbac1b93..89253d7d4aac 100644 --- a/tests/ui/parser/bad-char-literals.stderr +++ b/tests/ui/parser/bad-char-literals.stderr @@ -2,7 +2,12 @@ error: character constant must be escaped: `'` --> $DIR/bad-char-literals.rs:6:6 | LL | '''; - | ^ help: escape the character: `\'` + | ^ + | +help: escape the character + | +LL | '\''; + | ~~ error: character constant must be escaped: `\n` --> $DIR/bad-char-literals.rs:10:6 @@ -10,19 +15,34 @@ error: character constant must be escaped: `\n` LL | ' | ______^ LL | | '; - | |_ help: escape the character: `\n` + | |_ + | +help: escape the character + | +LL | '\n'; + | ++ error: character constant must be escaped: `\r` --> $DIR/bad-char-literals.rs:15:6 | LL | ' '; - | ^ help: escape the character: `\r` + | ^ + | +help: escape the character + | +LL | '\r'; + | ++ error: character constant must be escaped: `\t` --> $DIR/bad-char-literals.rs:18:6 | LL | ' '; - | ^^^^ help: escape the character: `\t` + | ^^^^ + | +help: escape the character + | +LL | '\t'; + | ++ error: aborting due to 4 previous errors diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr index 265e31329ca5..523ee47b0c94 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr @@ -5,7 +5,12 @@ LL | pub type T0 = const fn(); | -----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T0 = const fn(); +LL + pub type T0 = fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:6:15 @@ -14,7 +19,12 @@ LL | pub type T1 = const extern "C" fn(); | -----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T1 = const extern "C" fn(); +LL + pub type T1 = extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:7:15 @@ -23,7 +33,12 @@ LL | pub type T2 = const unsafe extern fn(); | -----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T2 = const unsafe extern fn(); +LL + pub type T2 = unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:8:15 @@ -32,7 +47,12 @@ LL | pub type T3 = async fn(); | -----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T3 = async fn(); +LL + pub type T3 = fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:9:15 @@ -41,7 +61,12 @@ LL | pub type T4 = async extern fn(); | -----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T4 = async extern fn(); +LL + pub type T4 = extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:10:15 @@ -50,7 +75,12 @@ LL | pub type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T5 = async unsafe extern "C" fn(); +LL + pub type T5 = unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:11:15 @@ -59,7 +89,12 @@ LL | pub type T6 = const async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T6 = const async unsafe extern "C" fn(); +LL + pub type T6 = async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:11:15 @@ -68,7 +103,12 @@ LL | pub type T6 = const async unsafe extern "C" fn(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T6 = const async unsafe extern "C" fn(); +LL + pub type T6 = const unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:15:17 @@ -77,7 +117,12 @@ LL | pub type FTT0 = for<'a> const fn(); | ^^^^^^^^-----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT0 = for<'a> const fn(); +LL + pub type FTT0 = for<'a> fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:16:17 @@ -86,7 +131,12 @@ LL | pub type FTT1 = for<'a> const extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT1 = for<'a> const extern "C" fn(); +LL + pub type FTT1 = for<'a> extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:17:17 @@ -95,7 +145,12 @@ LL | pub type FTT2 = for<'a> const unsafe extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT2 = for<'a> const unsafe extern fn(); +LL + pub type FTT2 = for<'a> unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:18:17 @@ -104,7 +159,12 @@ LL | pub type FTT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT3 = for<'a> async fn(); +LL + pub type FTT3 = for<'a> fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:19:17 @@ -113,7 +173,12 @@ LL | pub type FTT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT4 = for<'a> async extern fn(); +LL + pub type FTT4 = for<'a> extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:20:17 @@ -122,7 +187,12 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT5 = for<'a> async unsafe extern "C" fn(); +LL + pub type FTT5 = for<'a> unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:22:17 @@ -131,7 +201,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:22:17 @@ -140,7 +215,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); + | error: aborting due to 16 previous errors diff --git a/tests/ui/parser/byte-literals.stderr b/tests/ui/parser/byte-literals.stderr index 5b414c8927e2..25e319954418 100644 --- a/tests/ui/parser/byte-literals.stderr +++ b/tests/ui/parser/byte-literals.stderr @@ -24,13 +24,23 @@ error: byte constant must be escaped: `\t` --> $DIR/byte-literals.rs:8:7 | LL | b' '; - | ^^^^ help: escape the character: `\t` + | ^^^^ + | +help: escape the character + | +LL | b'\t'; + | ++ error: byte constant must be escaped: `'` --> $DIR/byte-literals.rs:9:7 | LL | b'''; - | ^ help: escape the character: `\'` + | ^ + | +help: escape the character + | +LL | b'\''; + | ~~ error: non-ASCII character in byte literal --> $DIR/byte-literals.rs:10:7 diff --git a/tests/ui/parser/char/whitespace-character-literal.stderr b/tests/ui/parser/char/whitespace-character-literal.stderr index 3bd048f8f622..f273b5d61d57 100644 --- a/tests/ui/parser/char/whitespace-character-literal.stderr +++ b/tests/ui/parser/char/whitespace-character-literal.stderr @@ -2,15 +2,17 @@ error: character literal may only contain one codepoint --> $DIR/whitespace-character-literal.rs:5:30 | LL | let _hair_space_around = ' x​'; - | ^--^ - | | - | help: consider removing the non-printing characters: `x` + | ^^^^ | note: there are non-printing characters, the full sequence is `\u{200a}x\u{200b}` --> $DIR/whitespace-character-literal.rs:5:31 | LL | let _hair_space_around = ' x​'; | ^^ +help: consider removing the non-printing characters + | +LL | let _hair_space_around = 'x​'; + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/default-on-wrong-item-kind.stderr b/tests/ui/parser/default-on-wrong-item-kind.stderr index af513f7617b0..392c85e0c43d 100644 --- a/tests/ui/parser/default-on-wrong-item-kind.stderr +++ b/tests/ui/parser/default-on-wrong-item-kind.stderr @@ -154,11 +154,13 @@ error: extern items cannot be `const` --> $DIR/default-on-wrong-item-kind.rs:38:19 | LL | default const foo: u8; - | --------------^^^ - | | - | help: try using a static value: `static` + | ^^^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static foo: u8; + | ~~~~~~ error: a module cannot be `default` --> $DIR/default-on-wrong-item-kind.rs:41:5 diff --git a/tests/ui/parser/do-catch-suggests-try.stderr b/tests/ui/parser/do-catch-suggests-try.stderr index cd8907b7eac9..fd3406ae29f8 100644 --- a/tests/ui/parser/do-catch-suggests-try.stderr +++ b/tests/ui/parser/do-catch-suggests-try.stderr @@ -2,9 +2,13 @@ error: found removed `do catch` syntax --> $DIR/do-catch-suggests-try.rs:4:25 | LL | let _: Option<()> = do catch {}; - | ^^^^^^^^ help: replace with the new syntax: `try` + | ^^^^^^^^ | = note: following RFC #2388, the new non-placeholder syntax is `try` +help: replace with the new syntax + | +LL | let _: Option<()> = try {}; + | ~~~ error[E0308]: mismatched types --> $DIR/do-catch-suggests-try.rs:9:33 diff --git a/tests/ui/parser/doc-comment-in-if-statement.stderr b/tests/ui/parser/doc-comment-in-if-statement.stderr index fc0bc507370a..37e0c398a61a 100644 --- a/tests/ui/parser/doc-comment-in-if-statement.stderr +++ b/tests/ui/parser/doc-comment-in-if-statement.stderr @@ -16,9 +16,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | if true /*!*/ {} | -- ^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - if true /*!*/ {} +LL + if true {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr index 90082f98cb5f..221e3a74d79f 100644 --- a/tests/ui/parser/expr-rarrow-call.stderr +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -2,41 +2,61 @@ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:14:10 | LL | named->foo; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | named.foo; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:18:12 | LL | unnamed->0; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | unnamed.0; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:22:6 | LL | t->0; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | t.0; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:23:6 | LL | t->1; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | t.1; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:30:8 | LL | foo->clone(); - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | foo.clone(); + | ~ error: aborting due to 5 previous errors diff --git a/tests/ui/parser/fn-colon-return-type.stderr b/tests/ui/parser/fn-colon-return-type.stderr index b61a62a17f7e..c1cdf4d4975a 100644 --- a/tests/ui/parser/fn-colon-return-type.stderr +++ b/tests/ui/parser/fn-colon-return-type.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/fn-colon-return-type.rs:1:15 | LL | fn foo(x: i32): i32 { - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn foo(x: i32) -> i32 { + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/foreign-const-semantic-fail.stderr b/tests/ui/parser/foreign-const-semantic-fail.stderr index 8dc66c0d012c..d317847f98ad 100644 --- a/tests/ui/parser/foreign-const-semantic-fail.stderr +++ b/tests/ui/parser/foreign-const-semantic-fail.stderr @@ -2,21 +2,25 @@ error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:4:11 | LL | const A: isize; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static A: isize; + | ~~~~~~ error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:6:11 | LL | const B: isize = 42; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static B: isize = 42; + | ~~~~~~ error: incorrect `static` inside `extern` block --> $DIR/foreign-const-semantic-fail.rs:6:11 diff --git a/tests/ui/parser/foreign-const-syntactic-fail.stderr b/tests/ui/parser/foreign-const-syntactic-fail.stderr index 9cf58fa95fb2..7da2c0190228 100644 --- a/tests/ui/parser/foreign-const-syntactic-fail.stderr +++ b/tests/ui/parser/foreign-const-syntactic-fail.stderr @@ -2,21 +2,25 @@ error: extern items cannot be `const` --> $DIR/foreign-const-syntactic-fail.rs:7:11 | LL | const A: isize; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static A: isize; + | ~~~~~~ error: extern items cannot be `const` --> $DIR/foreign-const-syntactic-fail.rs:8:11 | LL | const B: isize = 42; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static B: isize = 42; + | ~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr index e9a55026d124..83666014eb25 100644 --- a/tests/ui/parser/ident-recovery.stderr +++ b/tests/ui/parser/ident-recovery.stderr @@ -2,19 +2,25 @@ error: expected identifier, found `,` --> $DIR/ident-recovery.rs:1:4 | LL | fn ,comma() { - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - fn ,comma() { +LL + fn comma() { + | error: expected identifier, found `,` --> $DIR/ident-recovery.rs:4:16 | LL | x: i32,, - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - x: i32,, +LL + x: i32, + | error: expected identifier, found keyword `break` --> $DIR/ident-recovery.rs:10:4 diff --git a/tests/ui/parser/if-in-in.stderr b/tests/ui/parser/if-in-in.stderr index 6117370c0ce6..d8def76792e2 100644 --- a/tests/ui/parser/if-in-in.stderr +++ b/tests/ui/parser/if-in-in.stderr @@ -2,9 +2,13 @@ error: expected iterable, found keyword `in` --> $DIR/if-in-in.rs:4:14 | LL | for i in in 1..2 { - | ---^^ - | | - | help: remove the duplicated `in` + | ^^ + | +help: remove the duplicated `in` + | +LL - for i in in 1..2 { +LL + for i in 1..2 { + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr index a57cc075ccc9..6a24a9453e63 100644 --- a/tests/ui/parser/impl-parsing.stderr +++ b/tests/ui/parser/impl-parsing.stderr @@ -2,13 +2,23 @@ error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:4:11 | LL | impl Trait Type {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl Trait for Type {} + | +++ error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:5:11 | LL | impl Trait .. {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl Trait for .. {} + | +++ error: expected a trait, found type --> $DIR/impl-parsing.rs:6:6 diff --git a/tests/ui/parser/intersection-patterns-1.stderr b/tests/ui/parser/intersection-patterns-1.stderr index dc968656c91f..ed2466b21a75 100644 --- a/tests/ui/parser/intersection-patterns-1.stderr +++ b/tests/ui/parser/intersection-patterns-1.stderr @@ -6,7 +6,11 @@ LL | Some(x) @ y => {} | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `y @ Some(x)` + | +help: switch the order + | +LL | y @ Some(x) => {} + | ~~~~~~~~~~~ error: pattern on wrong side of `@` --> $DIR/intersection-patterns-1.rs:27:9 @@ -16,7 +20,11 @@ LL | 1 ..= 5 @ e => {} | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `e @ 1..=5` + | +help: switch the order + | +LL | e @ 1..=5 => {} + | ~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr index 9776677589f5..c0d85aa17d2a 100644 --- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr @@ -2,7 +2,13 @@ error: expected item, found `;` --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1 | LL | ; - | ^ help: remove this semicolon + | ^ + | +help: remove this semicolon + | +LL - ; +LL + + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-100197-mut-let.stderr b/tests/ui/parser/issues/issue-100197-mut-let.stderr index 07d136881408..252ed7d0715d 100644 --- a/tests/ui/parser/issues/issue-100197-mut-let.stderr +++ b/tests/ui/parser/issues/issue-100197-mut-let.stderr @@ -2,7 +2,12 @@ error: invalid variable declaration --> $DIR/issue-100197-mut-let.rs:4:5 | LL | mut let _x = 123; - | ^^^^^^^ help: switch the order of `mut` and `let`: `let mut` + | ^^^^^^^ + | +help: switch the order of `mut` and `let` + | +LL | let mut _x = 123; + | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-101477-enum.stderr b/tests/ui/parser/issues/issue-101477-enum.stderr index 94130671f1c9..c6dadeab8b33 100644 --- a/tests/ui/parser/issues/issue-101477-enum.stderr +++ b/tests/ui/parser/issues/issue-101477-enum.stderr @@ -2,9 +2,14 @@ error: unexpected `==` --> $DIR/issue-101477-enum.rs:6:7 | LL | B == 2 - | ^^ help: try using `=` instead + | ^^ | = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` +help: try using `=` instead + | +LL - B == 2 +LL + B = 2 + | error: expected item, found `==` --> $DIR/issue-101477-enum.rs:6:7 diff --git a/tests/ui/parser/issues/issue-101477-let.stderr b/tests/ui/parser/issues/issue-101477-let.stderr index 56348357397f..59e90c8102f7 100644 --- a/tests/ui/parser/issues/issue-101477-let.stderr +++ b/tests/ui/parser/issues/issue-101477-let.stderr @@ -2,7 +2,13 @@ error: unexpected `==` --> $DIR/issue-101477-let.rs:4:11 | LL | let x == 2; - | ^^ help: try using `=` instead + | ^^ + | +help: try using `=` instead + | +LL - let x == 2; +LL + let x = 2; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-103425.stderr b/tests/ui/parser/issues/issue-103425.stderr index 0efe3e3ca711..e7e1b7106b0b 100644 --- a/tests/ui/parser/issues/issue-103425.stderr +++ b/tests/ui/parser/issues/issue-103425.stderr @@ -2,28 +2,43 @@ error: expected `;`, found `5.0` --> $DIR/issue-103425.rs:2:6 | LL | 3 - | ^ help: add `;` here + | ^ LL | LL | 5.0 | --- unexpected token + | +help: add `;` here + | +LL | 3; + | + error: expected `;`, found `3_i8` --> $DIR/issue-103425.rs:8:10 | LL | 2_u32 - | ^ help: add `;` here + | ^ LL | LL | 3_i8 | ---- unexpected token + | +help: add `;` here + | +LL | 2_u32; + | + error: expected `;`, found `5.0` --> $DIR/issue-103425.rs:10:9 | LL | 3_i8 - | ^ help: add `;` here + | ^ LL | LL | 5.0 | --- unexpected token + | +help: add `;` here + | +LL | 3_i8; + | + error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr index 86d3449cc33b..e5c6ba27755e 100644 --- a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr +++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr @@ -2,13 +2,23 @@ error: missing parameters for function definition --> $DIR/issue-108109-fn-missing-params.rs:3:15 | LL | pub fn missing -> () {} - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | pub fn missing() -> () {} + | ++ error: missing parameters for function definition --> $DIR/issue-108109-fn-missing-params.rs:6:16 | LL | pub fn missing2 {} - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | pub fn missing2() {} + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-113203.stderr b/tests/ui/parser/issues/issue-113203.stderr index 5db628d59776..f9c8ad912805 100644 --- a/tests/ui/parser/issues/issue-113203.stderr +++ b/tests/ui/parser/issues/issue-113203.stderr @@ -2,7 +2,12 @@ error: incorrect use of `await` --> $DIR/issue-113203.rs:5:5 | LL | await {}() - | ^^^^^^^^ help: `await` is a postfix operation: `{}.await` + | ^^^^^^^^ + | +help: `await` is a postfix operation + | +LL | {}.await() + | ~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index 75c6a40c7445..a8a2327d0cee 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -30,16 +30,23 @@ LL | #[feature] | ---------- only `;` terminated statements or tail expressions are allowed after this attribute LL | attr::fn bar() -> String { | ^--- unexpected token - | | - | help: add `;` here + | +help: add `;` here + | +LL | attr::fn; bar() -> String { + | + error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | attr::fn bar() . String { + | ~ error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` --> $DIR/issue-118530-ice.rs:5:30 diff --git a/tests/ui/parser/issues/issue-17718-const-mut.stderr b/tests/ui/parser/issues/issue-17718-const-mut.stderr index a27f517086ef..54b819c3cfb8 100644 --- a/tests/ui/parser/issues/issue-17718-const-mut.stderr +++ b/tests/ui/parser/issues/issue-17718-const-mut.stderr @@ -1,10 +1,13 @@ error: const globals cannot be mutable --> $DIR/issue-17718-const-mut.rs:2:1 | -LL | const - | ----- help: you might want to declare a static instead: `static` LL | mut | ^^^ cannot be mutable + | +help: you might want to declare a static instead + | +LL | static + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr index 88d97c795fc2..4a3743579e7a 100644 --- a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr +++ b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr @@ -86,9 +86,12 @@ error: incorrect unicode escape sequence --> $DIR/issue-23620-invalid-escapes.rs:32:14 | LL | let _ = "\u8f"; - | ^^^- - | | - | help: format of unicode escape sequences uses braces: `\u{8f}` + | ^^^ + | +help: format of unicode escape sequences uses braces + | +LL | let _ = "\u{8f}"; + | ~~~~~~ error: aborting due to 13 previous errors diff --git a/tests/ui/parser/issues/issue-27255.stderr b/tests/ui/parser/issues/issue-27255.stderr index 391a23556c4e..2cd7ebd60b14 100644 --- a/tests/ui/parser/issues/issue-27255.stderr +++ b/tests/ui/parser/issues/issue-27255.stderr @@ -2,13 +2,23 @@ error: missing `for` in a trait impl --> $DIR/issue-27255.rs:3:7 | LL | impl A .. {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl A for .. {} + | +++ error: missing `for` in a trait impl --> $DIR/issue-27255.rs:7:7 | LL | impl A usize {} - | ^^^^^^ help: add `for` here + | ^^^^^^ + | +help: add `for` here + | +LL | impl A for usize {} + | +++ error: `impl Trait for .. {}` is an obsolete syntax --> $DIR/issue-27255.rs:3:1 diff --git a/tests/ui/parser/issues/issue-3036.stderr b/tests/ui/parser/issues/issue-3036.stderr index 3dd89b7e828d..62a9c1d9752a 100644 --- a/tests/ui/parser/issues/issue-3036.stderr +++ b/tests/ui/parser/issues/issue-3036.stderr @@ -2,9 +2,14 @@ error: expected `;`, found `}` --> $DIR/issue-3036.rs:6:15 | LL | let _x = 3 - | ^ help: add `;` here + | ^ LL | } | - unexpected token + | +help: add `;` here + | +LL | let _x = 3; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-32501.stderr b/tests/ui/parser/issues/issue-32501.stderr index c0513a64039e..b0ec135b784a 100644 --- a/tests/ui/parser/issues/issue-32501.stderr +++ b/tests/ui/parser/issues/issue-32501.stderr @@ -2,9 +2,14 @@ error: `mut` must be followed by a named binding --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut _ = 0; +LL + let _ = 0; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-46186.stderr b/tests/ui/parser/issues/issue-46186.stderr index c67c271e19ae..5ea3e1f49838 100644 --- a/tests/ui/parser/issues/issue-46186.stderr +++ b/tests/ui/parser/issues/issue-46186.stderr @@ -2,9 +2,14 @@ error: expected item, found `;` --> $DIR/issue-46186.rs:5:2 | LL | }; - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - }; +LL + } + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-48636.stderr b/tests/ui/parser/issues/issue-48636.stderr index 488a046a5490..c17a8ec2f899 100644 --- a/tests/ui/parser/issues/issue-48636.stderr +++ b/tests/ui/parser/issues/issue-48636.stderr @@ -4,11 +4,14 @@ error[E0585]: found a documentation comment that doesn't document anything LL | struct S { | - while parsing this struct LL | x: u8 - | - help: missing comma here: `,` LL | /// The ID of the parent core | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: doc comments must come before what they document, if a comment was intended use `//` +help: missing comma here + | +LL | x: u8, + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr index 11ef5e1aadfd..c25d5683ecfc 100644 --- a/tests/ui/parser/issues/issue-49040.stderr +++ b/tests/ui/parser/issues/issue-49040.stderr @@ -2,7 +2,13 @@ error: expected item, found `;` --> $DIR/issue-49040.rs:1:28 | LL | #![allow(unused_variables)]; - | ^ help: remove this semicolon + | ^ + | +help: remove this semicolon + | +LL - #![allow(unused_variables)]; +LL + #![allow(unused_variables)] + | error[E0601]: `main` function not found in crate `issue_49040` --> $DIR/issue-49040.rs:2:12 diff --git a/tests/ui/parser/issues/issue-52496.stderr b/tests/ui/parser/issues/issue-52496.stderr index 78c81bf5b0df..a97effb4e0cd 100644 --- a/tests/ui/parser/issues/issue-52496.stderr +++ b/tests/ui/parser/issues/issue-52496.stderr @@ -2,7 +2,12 @@ error: float literals must have an integer part --> $DIR/issue-52496.rs:4:24 | LL | let _ = Foo { bar: .5, baz: 42 }; - | ^^ help: must have an integer part: `0.5` + | ^^ + | +help: must have an integer part + | +LL | let _ = Foo { bar: 0.5, baz: 42 }; + | + error: expected one of `,`, `:`, or `}`, found `.` --> $DIR/issue-52496.rs:8:22 diff --git a/tests/ui/parser/issues/issue-54521-2.stderr b/tests/ui/parser/issues/issue-54521-2.stderr index 9556b83b730a..ad662ef1cca5 100644 --- a/tests/ui/parser/issues/issue-54521-2.stderr +++ b/tests/ui/parser/issues/issue-54521-2.stderr @@ -2,25 +2,49 @@ error: unmatched angle brackets --> $DIR/issue-54521-2.rs:11:25 | LL | let _ = Vec::>>>>::new(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle brackets --> $DIR/issue-54521-2.rs:14:25 | LL | let _ = Vec::>>>::new(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle brackets --> $DIR/issue-54521-2.rs:17:25 | LL | let _ = Vec::>>::new(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle bracket --> $DIR/issue-54521-2.rs:20:25 | LL | let _ = Vec::>::new(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = Vec::>::new(); +LL + let _ = Vec::::new(); + | error: aborting due to 4 previous errors diff --git a/tests/ui/parser/issues/issue-54521-3.stderr b/tests/ui/parser/issues/issue-54521-3.stderr index 0f23dd621075..bd468869b066 100644 --- a/tests/ui/parser/issues/issue-54521-3.stderr +++ b/tests/ui/parser/issues/issue-54521-3.stderr @@ -2,25 +2,49 @@ error: unmatched angle brackets --> $DIR/issue-54521-3.rs:11:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>>>(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-54521-3.rs:14:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-54521-3.rs:17:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle bracket --> $DIR/issue-54521-3.rs:20:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: aborting due to 4 previous errors diff --git a/tests/ui/parser/issues/issue-57684.stderr b/tests/ui/parser/issues/issue-57684.stderr index 514bbffde6b1..39e1c8cd7cc7 100644 --- a/tests/ui/parser/issues/issue-57684.stderr +++ b/tests/ui/parser/issues/issue-57684.stderr @@ -2,17 +2,23 @@ error: expected `:`, found `=` --> $DIR/issue-57684.rs:27:20 | LL | let _ = X { f1 = 5 }; - | -^ - | | - | help: replace equals symbol with a colon: `:` + | ^ + | +help: replace equals symbol with a colon + | +LL | let _ = X { f1: 5 }; + | ~ error: expected `:`, found `=` --> $DIR/issue-57684.rs:32:12 | LL | f1 = 5, - | -^ - | | - | help: replace equals symbol with a colon: `:` + | ^ + | +help: replace equals symbol with a colon + | +LL | f1: 5, + | ~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-57819.stderr b/tests/ui/parser/issues/issue-57819.stderr index 493e9835b1ca..a01625d9c4c3 100644 --- a/tests/ui/parser/issues/issue-57819.stderr +++ b/tests/ui/parser/issues/issue-57819.stderr @@ -2,43 +2,85 @@ error: unmatched angle brackets --> $DIR/issue-57819.rs:19:10 | LL | bar::<<<<::Output>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - bar::<<<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:22:10 | LL | bar::<<<::Output>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - bar::<<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle bracket --> $DIR/issue-57819.rs:25:10 | LL | bar::<<::Output>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - bar::<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:34:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:37:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<<>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:40:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle bracket --> $DIR/issue-57819.rs:43:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: aborting due to 7 previous errors diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr index 2bd87ee0c38f..76259b40a933 100644 --- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -2,13 +2,18 @@ error: `mut` must be followed by a named binding --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:6:13 | LL | let mut $eval = (); - | ^^^^ help: remove the `mut` prefix + | ^^^^ ... LL | mac1! { does_not_exist!() } | --------------------------- in this macro invocation | = note: `mut` may be followed by `variable` and `variable @ pattern` = note: this error originates in the macro `mac1` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the `mut` prefix + | +LL - let mut $eval = (); +LL + let $eval = (); + | error: expected identifier, found `does_not_exist!()` --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17 @@ -25,13 +30,18 @@ error: `mut` must be followed by a named binding --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13 | LL | let mut $eval = (); - | ^^^ help: remove the `mut` prefix + | ^^^ ... LL | mac2! { does_not_exist!() } | --------------------------- in this macro invocation | = note: `mut` may be followed by `variable` and `variable @ pattern` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the `mut` prefix + | +LL - let mut $eval = (); +LL + let $eval = (); + | error: cannot find macro `does_not_exist` in this scope --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 diff --git a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr index 0a88dd2c4d31..49d091cf3914 100644 --- a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr +++ b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr @@ -46,13 +46,23 @@ error: invalid variable declaration --> $DIR/issue-65257-invalid-var-decl-recovery.rs:14:5 | LL | mut n = 0; - | ^^^ help: missing keyword: `let mut` + | ^^^ + | +help: missing keyword + | +LL | let mut n = 0; + | ~~~~~~~ error: invalid variable declaration --> $DIR/issue-65257-invalid-var-decl-recovery.rs:16:5 | LL | mut var; - | ^^^ help: missing keyword: `let mut` + | ^^^ + | +help: missing keyword + | +LL | let mut var; + | ~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-65257-invalid-var-decl-recovery.rs:20:33 diff --git a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr index 4961e8fc0492..63131b474f00 100644 --- a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr +++ b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr @@ -2,19 +2,25 @@ error: unexpected `...` --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:4:13 | LL | let Foo(...) = Foo(0); - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let Foo(...) = Foo(0); +LL + let Foo(..) = Foo(0); + | error: unexpected `...` --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:5:13 | LL | let [_, ..., _] = [0, 1]; - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let [_, ..., _] = [0, 1]; +LL + let [_, .., _] = [0, 1]; + | error[E0308]: mismatched types --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:6:33 diff --git a/tests/ui/parser/issues/issue-70388-without-witness.stderr b/tests/ui/parser/issues/issue-70388-without-witness.stderr index b750ad4c626d..ed78377607d2 100644 --- a/tests/ui/parser/issues/issue-70388-without-witness.stderr +++ b/tests/ui/parser/issues/issue-70388-without-witness.stderr @@ -2,19 +2,25 @@ error: unexpected `...` --> $DIR/issue-70388-without-witness.rs:7:13 | LL | let Foo(...) = Foo(0); - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let Foo(...) = Foo(0); +LL + let Foo(..) = Foo(0); + | error: unexpected `...` --> $DIR/issue-70388-without-witness.rs:8:13 | LL | let [_, ..., _] = [0, 1]; - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let [_, ..., _] = [0, 1]; +LL + let [_, .., _] = [0, 1]; + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr index ec0af9a6caf1..79c574ead61c 100644 --- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr +++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr @@ -17,7 +17,13 @@ error: unexpected lifetime `'static` in pattern --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13 | LL | fn bar(&'static mur Self) {} - | ^^^^^^^ help: remove the lifetime + | ^^^^^^^ + | +help: remove the lifetime + | +LL - fn bar(&'static mur Self) {} +LL + fn bar(&mur Self) {} + | error: expected identifier, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25 diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr index 652aeff5dd44..2f8728bd78b4 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr @@ -2,24 +2,38 @@ error: lifetime must precede `mut` --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 | LL | fn x<'a>(x: &mut 'a i32){} - | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + | ^^^^^^^ + | +help: place the lifetime before `mut` + | +LL | fn x<'a>(x: &'a mut i32){} + | ~~~~~~~ error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 | LL | fn y<'a>(y: &mut 'a + Send) { - | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + | ^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn y<'a>(y: &mut ('a + Send)) { + | + + error: lifetime must precede `mut` --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 | LL | fn w<$lt>(w: &mut $lt i32) {} - | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` + | ^^^^^^^^ ... LL | mac!('a); | -------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: place the lifetime before `mut` + | +LL | fn w<$lt>(w: &$lt mut i32) {} + | ~~~~~~~~ error[E0423]: expected value, found trait `Send` --> $DIR/issue-73568-lifetime-after-mut.rs:17:28 diff --git a/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr b/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr index 57772de1e7a4..874e7b071630 100644 --- a/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr +++ b/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr @@ -2,25 +2,40 @@ error: expected `;`, found `println` --> $DIR/issue-87197-missing-semicolon.rs:6:16 | LL | let x = 100 - | ^ help: add `;` here + | ^ LL | println!("{}", x) | ------- unexpected token + | +help: add `;` here + | +LL | let x = 100; + | + error: expected `;`, found keyword `let` --> $DIR/issue-87197-missing-semicolon.rs:7:22 | LL | println!("{}", x) - | ^ help: add `;` here + | ^ LL | let y = 200 | --- unexpected token + | +help: add `;` here + | +LL | println!("{}", x); + | + error: expected `;`, found `println` --> $DIR/issue-87197-missing-semicolon.rs:8:16 | LL | let y = 200 - | ^ help: add `;` here + | ^ LL | println!("{}", y); | ------- unexpected token + | +help: add `;` here + | +LL | let y = 200; + | + error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/parser/issues/issue-89574.stderr index a0586d41e2e5..aa5e66b18a92 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/parser/issues/issue-89574.stderr @@ -8,7 +8,12 @@ error: missing type for `const` item --> $DIR/issue-89574.rs:2:22 | LL | const EMPTY_ARRAY = []; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const EMPTY_ARRAY: = []; + | ++++++++ error[E0282]: type annotations needed --> $DIR/issue-89574.rs:2:25 diff --git a/tests/ui/parser/issues/issue-90993.stderr b/tests/ui/parser/issues/issue-90993.stderr index ab6bce410e6c..a18e93f1f1a9 100644 --- a/tests/ui/parser/issues/issue-90993.stderr +++ b/tests/ui/parser/issues/issue-90993.stderr @@ -17,9 +17,13 @@ error: unexpected `=` after inclusive range --> $DIR/issue-90993.rs:2:5 | LL | ...=. - | ^^^^ help: use `..=` instead + | ^^^^ | = note: inclusive ranges end with a single equals sign (`..=`) +help: use `..=` instead + | +LL | ..=. + | ~~~ error: expected one of `-`, `;`, `}`, or path, found `.` --> $DIR/issue-90993.rs:2:9 diff --git a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr index c503bc3ccfcb..c98b8fa1f1ee 100644 --- a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr @@ -2,7 +2,12 @@ error: `enum` and `struct` are mutually exclusive --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5 | LL | pub enum struct Range { - | ^^^^^^^^^^^ help: replace `enum struct` with: `enum` + | ^^^^^^^^^^^ + | +help: replace `enum struct` with + | +LL | pub enum Range { + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr index 72377fc379ca..1ccf44a350d9 100644 --- a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr @@ -2,13 +2,23 @@ error: `const` and `let` are mutually exclusive --> $DIR/issue-99910-const-let-mutually-exclusive.rs:4:5 | LL | const let _FOO: i32 = 123; - | ^^^^^^^^^ help: remove `let`: `const` + | ^^^^^^^^^ + | +help: remove `let` + | +LL | const _FOO: i32 = 123; + | ~~~~~ error: `const` and `let` are mutually exclusive --> $DIR/issue-99910-const-let-mutually-exclusive.rs:6:5 | LL | let const _BAR: i32 = 123; - | ^^^^^^^^^ help: remove `let`: `const` + | ^^^^^^^^^ + | +help: remove `let` + | +LL | const _BAR: i32 = 123; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr index 2d7f540443d2..8d4f23683863 100644 --- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr @@ -2,9 +2,14 @@ error: expected item, found `;` --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1 | LL | ; - | ^ help: remove this semicolon + | ^ | = help: function declarations are not followed by a semicolon +help: remove this semicolon + | +LL - ; +LL + + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr index 5365b0a1f824..1ecf9912e9b1 100644 --- a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr +++ b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -18,7 +18,12 @@ error: missing type for `const` item --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8 | LL | const B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const B: ; + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr index 1b61e430546e..3af7c642468d 100644 --- a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr +++ b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -34,13 +34,23 @@ error: missing type for `static` item --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9 | LL | static B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static B: ; + | ++++++++ error: missing type for `static mut` item --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13 | LL | static mut D; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static mut D: ; + | ++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index ba59ea853633..0abc59e064a0 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -2,85 +2,155 @@ error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:7:1 | LL | Use std::ptr::read; - | ^^^ help: write it in the correct case (notice the capitalization): `use` + | ^^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | use std::ptr::read; + | ~~~ error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:8:1 | LL | USE std::ptr::write; - | ^^^ help: write it in the correct case: `use` + | ^^^ + | +help: write it in the correct case + | +LL | use std::ptr::write; + | ~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:10:7 | LL | async Fn _a() {} - | ^^ help: write it in the correct case (notice the capitalization): `fn` + | ^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | async fn _a() {} + | ~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:13:1 | LL | Fn _b() {} - | ^^ help: write it in the correct case (notice the capitalization): `fn` + | ^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | fn _b() {} + | ~~ error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:1 | LL | aSYNC fN _c() {} - | ^^^^^ help: write it in the correct case: `async` + | ^^^^^ + | +help: write it in the correct case + | +LL | async fN _c() {} + | ~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:7 | LL | aSYNC fN _c() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | aSYNC fn _c() {} + | ~~ error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:20:1 | LL | Async fn _d() {} - | ^^^^^ help: write it in the correct case: `async` + | ^^^^^ + | +help: write it in the correct case + | +LL | async fn _d() {} + | ~~~~~ error: keyword `const` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:1 | LL | CONST UNSAFE FN _e() {} - | ^^^^^ help: write it in the correct case: `const` + | ^^^^^ + | +help: write it in the correct case + | +LL | const UNSAFE FN _e() {} + | ~~~~~ error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:7 | LL | CONST UNSAFE FN _e() {} - | ^^^^^^ help: write it in the correct case: `unsafe` + | ^^^^^^ + | +help: write it in the correct case + | +LL | CONST unsafe FN _e() {} + | ~~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:14 | LL | CONST UNSAFE FN _e() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | CONST UNSAFE fn _e() {} + | ~~ error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:1 | LL | unSAFE EXTern fn _f() {} - | ^^^^^^ help: write it in the correct case: `unsafe` + | ^^^^^^ + | +help: write it in the correct case + | +LL | unsafe EXTern fn _f() {} + | ~~~~~~ error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:8 | LL | unSAFE EXTern fn _f() {} - | ^^^^^^ help: write it in the correct case: `extern` + | ^^^^^^ + | +help: write it in the correct case + | +LL | unSAFE extern fn _f() {} + | ~~~~~~ error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:1 | LL | EXTERN "C" FN _g() {} - | ^^^^^^ help: write it in the correct case: `extern` + | ^^^^^^ + | +help: write it in the correct case + | +LL | extern "C" FN _g() {} + | ~~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:12 | LL | EXTERN "C" FN _g() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | EXTERN "C" fn _g() {} + | ~~ error: aborting due to 14 previous errors diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr index 8ff50b124b32..be8c679d8ce3 100644 --- a/tests/ui/parser/label-after-block-like.stderr +++ b/tests/ui/parser/label-after-block-like.stderr @@ -2,12 +2,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:2:20 | LL | if let () = () 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | if let () = () 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:2:20 @@ -29,12 +32,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:8:13 | LL | if true 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | if true 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:8:13 @@ -56,12 +62,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:14:10 | LL | loop 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | loop 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:14:10 @@ -80,12 +89,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:20:16 | LL | while true 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | while true 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:20:16 @@ -105,12 +117,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:26:23 | LL | while let () = () 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | while let () = () 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:26:23 @@ -130,12 +145,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:32:19 | LL | for _ in 0..0 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | for _ in 0..0 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:32:19 @@ -152,12 +170,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:38:12 | LL | unsafe 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | unsafe 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:38:12 diff --git a/tests/ui/parser/labeled-no-colon-expr.stderr b/tests/ui/parser/labeled-no-colon-expr.stderr index 4d61d9c14034..247831928156 100644 --- a/tests/ui/parser/labeled-no-colon-expr.stderr +++ b/tests/ui/parser/labeled-no-colon-expr.stderr @@ -2,45 +2,57 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:2:5 | LL | 'l0 while false {} - | ----^^^^^^^^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l0: while false {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:3:5 | LL | 'l1 for _ in 0..1 {} - | ----^^^^^^^^^^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^^^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l1: for _ in 0..1 {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:4:5 | LL | 'l2 loop {} - | ----^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l2: loop {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:5:5 | LL | 'l3 {} - | ----^^ - | | | - | | help: add `:` after the label + | ---^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l3: {} + | + error: expected `while`, `for`, `loop` or `{` after a label --> $DIR/labeled-no-colon-expr.rs:6:9 @@ -58,12 +70,15 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:6:9 | LL | 'l4 0; - | ----^ - | | | - | | help: add `:` after the label + | --- ^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l4: 0; + | + error: cannot use a `block` macro fragment here --> $DIR/labeled-no-colon-expr.rs:11:17 @@ -86,14 +101,16 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:14:8 | LL | 'l5 $b; - | ---- help: add `:` after the label - | | - | the label + | --- the label ... LL | m!({}); | ^^ | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l5: $b; + | + error: aborting due to 8 previous errors diff --git a/tests/ui/parser/let-binop.stderr b/tests/ui/parser/let-binop.stderr index dd33e9157cfd..50ef14793cde 100644 --- a/tests/ui/parser/let-binop.stderr +++ b/tests/ui/parser/let-binop.stderr @@ -2,25 +2,40 @@ error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:4:15 | LL | let a: i8 *= 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let a: i8 *= 1; +LL + let a: i8 = 1; + | error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:6:11 | LL | let b += 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let b += 1; +LL + let b = 1; + | error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:8:11 | LL | let c *= 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let c *= 1; +LL + let c = 1; + | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/lifetime-in-pattern-recover.stderr b/tests/ui/parser/lifetime-in-pattern-recover.stderr index 4bf7f57bfb59..d0644da1dd18 100644 --- a/tests/ui/parser/lifetime-in-pattern-recover.stderr +++ b/tests/ui/parser/lifetime-in-pattern-recover.stderr @@ -2,13 +2,25 @@ error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern-recover.rs:2:10 | LL | let &'a x = &0; - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - let &'a x = &0; +LL + let &x = &0; + | error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern-recover.rs:3:10 | LL | let &'a mut y = &mut 0; - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - let &'a mut y = &mut 0; +LL + let &mut y = &mut 0; + | error[E0308]: mismatched types --> $DIR/lifetime-in-pattern-recover.rs:5:33 diff --git a/tests/ui/parser/lifetime-in-pattern.stderr b/tests/ui/parser/lifetime-in-pattern.stderr index a1d721e746ad..55f9e56a4292 100644 --- a/tests/ui/parser/lifetime-in-pattern.stderr +++ b/tests/ui/parser/lifetime-in-pattern.stderr @@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern.rs:1:10 | LL | fn test(&'a str) { - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - fn test(&'a str) { +LL + fn test(&str) { + | error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/lifetime-in-pattern.rs:1:16 diff --git a/tests/ui/parser/macro/pub-item-macro.stderr b/tests/ui/parser/macro/pub-item-macro.stderr index 9a2fffcced55..14f0b0908d1c 100644 --- a/tests/ui/parser/macro/pub-item-macro.stderr +++ b/tests/ui/parser/macro/pub-item-macro.stderr @@ -2,13 +2,18 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-item-macro.rs:10:5 | LL | pub priv_x!(); - | ^^^ help: remove the visibility + | ^^^ ... LL | pub_x!(); | -------- in this macro invocation | = help: try adjusting the macro to put `pub` inside the invocation = note: this error originates in the macro `pub_x` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the visibility + | +LL - pub priv_x!(); +LL + priv_x!(); + | error[E0603]: static `x` is private --> $DIR/pub-item-macro.rs:20:23 diff --git a/tests/ui/parser/macros-no-semicolon.stderr b/tests/ui/parser/macros-no-semicolon.stderr index f310662dbb0e..4cf01e457d70 100644 --- a/tests/ui/parser/macros-no-semicolon.stderr +++ b/tests/ui/parser/macros-no-semicolon.stderr @@ -2,17 +2,27 @@ error: expected `;`, found `assert_eq` --> $DIR/macros-no-semicolon.rs:2:21 | LL | assert_eq!(1, 2) - | ^ help: add `;` here + | ^ LL | assert_eq!(3, 4) | --------- unexpected token + | +help: add `;` here + | +LL | assert_eq!(1, 2); + | + error: expected `;`, found `println` --> $DIR/macros-no-semicolon.rs:3:21 | LL | assert_eq!(3, 4) - | ^ help: add `;` here + | ^ LL | println!("hello"); | ------- unexpected token + | +help: add `;` here + | +LL | assert_eq!(3, 4); + | + error: aborting due to 2 previous errors diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index a3f7e32c1773..53cf3480dbf9 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -56,7 +56,12 @@ error: expected `,` following `match` arm --> $DIR/match-arm-without-body.rs:66:15 | LL | pat!() - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | pat!(), + | + error: `match` arm with no body --> $DIR/match-arm-without-body.rs:7:9 diff --git a/tests/ui/parser/match-arm-without-braces.stderr b/tests/ui/parser/match-arm-without-braces.stderr index ee1c8e562fc3..4a4a154d8609 100644 --- a/tests/ui/parser/match-arm-without-braces.stderr +++ b/tests/ui/parser/match-arm-without-braces.stderr @@ -60,7 +60,12 @@ error: expected `,` following `match` arm --> $DIR/match-arm-without-braces.rs:48:29 | LL | Some(Val::Foo) => 17 - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(Val::Foo) => 17, + | + error: `match` arm body without braces --> $DIR/match-arm-without-braces.rs:53:11 diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr index 6559cf09cdfc..f4f11b88d361 100644 --- a/tests/ui/parser/mut-patterns.stderr +++ b/tests/ui/parser/mut-patterns.stderr @@ -2,53 +2,87 @@ error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:9:9 | LL | let mut _ = 0; - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut _ = 0; +LL + let _ = 0; + | error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:10:9 | LL | let mut (_, _) = (0, 0); - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut (_, _) = (0, 0); +LL + let (_, _) = (0, 0); + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:12:9 | LL | let mut (x @ y) = 0; - | ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)` + | ^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let (mut x @ mut y) = 0; + | ~~~~~~~~~~~~~~~ error: `mut` on a binding may not be repeated --> $DIR/mut-patterns.rs:14:13 | LL | let mut mut x = 0; - | ^^^ help: remove the additional `mut`s + | ^^^ + | +help: remove the additional `mut`s + | +LL - let mut mut x = 0; +LL + let mut x = 0; + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:19:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + | ^^^^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let Foo { x: mut x } = Foo { x: 3 }; + | ~~~~~~~~~~~~~~~~ error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:23:9 | LL | let mut Foo { x } = Foo { x: 3 }; - | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + | ^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let Foo { mut x } = Foo { x: 3 }; + | ~~~~~~~~~~~~~ error: `mut` on a binding may not be repeated --> $DIR/mut-patterns.rs:28:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); - | ^^^ help: remove the additional `mut`s + | ^^^ + | +help: remove the additional `mut`s + | +LL - let mut mut yield(become, await) = r#yield(0, 0); +LL + let mut yield(become, await) = r#yield(0, 0); + | error: expected identifier, found reserved keyword `yield` --> $DIR/mut-patterns.rs:28:17 @@ -87,17 +121,26 @@ error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:28:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); - | ^^^^^^^^ help: remove the `mut` prefix + | ^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut mut yield(become, await) = r#yield(0, 0); +LL + let yield(become, await) = r#yield(0, 0); + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:37:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f })))) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: expected identifier, found `x` --> $DIR/mut-patterns.rs:44:21 diff --git a/tests/ui/parser/not-a-pred.stderr b/tests/ui/parser/not-a-pred.stderr index bcc64a687fd0..6f6a332cb815 100644 --- a/tests/ui/parser/not-a-pred.stderr +++ b/tests/ui/parser/not-a-pred.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn f(a: isize, b: isize) -> lt(a, b) { } + | ~~ error[E0573]: expected type, found function `lt` --> $DIR/not-a-pred.rs:1:28 diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr index 2b0c9bbc5be8..e36ff237bb00 100644 --- a/tests/ui/parser/pat-recover-wildcards.stderr +++ b/tests/ui/parser/pat-recover-wildcards.stderr @@ -32,9 +32,14 @@ error[E0586]: inclusive range with no end --> $DIR/pat-recover-wildcards.rs:35:10 | LL | 0..._ => () - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - 0..._ => () +LL + 0.._ => () + | error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` --> $DIR/pat-recover-wildcards.rs:35:13 diff --git a/tests/ui/parser/pub-method-macro.stderr b/tests/ui/parser/pub-method-macro.stderr index 35cbf4230791..2e2c30dc6ad2 100644 --- a/tests/ui/parser/pub-method-macro.stderr +++ b/tests/ui/parser/pub-method-macro.stderr @@ -2,9 +2,14 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-method-macro.rs:17:9 | LL | pub defn!(f); - | ^^^ help: remove the visibility + | ^^^ | = help: try adjusting the macro to put `pub` inside the invocation +help: remove the visibility + | +LL - pub defn!(f); +LL + defn!(f); + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/range-inclusive-extra-equals.stderr b/tests/ui/parser/range-inclusive-extra-equals.stderr index 83df719dd3cc..a573cdf950cd 100644 --- a/tests/ui/parser/range-inclusive-extra-equals.stderr +++ b/tests/ui/parser/range-inclusive-extra-equals.stderr @@ -2,9 +2,13 @@ error: unexpected `=` after inclusive range --> $DIR/range-inclusive-extra-equals.rs:7:13 | LL | if let 1..==3 = 1 {} - | ^^^^ help: use `..=` instead + | ^^^^ | = note: inclusive ranges end with a single equals sign (`..=`) +help: use `..=` instead + | +LL | if let 1..=3 = 1 {} + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/range_inclusive.stderr b/tests/ui/parser/range_inclusive.stderr index 0fd7f28db317..014f95bcd84a 100644 --- a/tests/ui/parser/range_inclusive.stderr +++ b/tests/ui/parser/range_inclusive.stderr @@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end --> $DIR/range_inclusive.rs:5:15 | LL | for _ in 1..= {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - for _ in 1..= {} +LL + for _ in 1.. {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/raw/raw-str-unbalanced.stderr b/tests/ui/parser/raw/raw-str-unbalanced.stderr index eac8c06c1df5..d3a9c342c032 100644 --- a/tests/ui/parser/raw/raw-str-unbalanced.stderr +++ b/tests/ui/parser/raw/raw-str-unbalanced.stderr @@ -19,10 +19,15 @@ error: expected `;`, found `#` --> $DIR/raw-str-unbalanced.rs:10:28 | LL | const A: &'static str = r"" - | ^ help: add `;` here + | ^ ... LL | #[test] | - unexpected token + | +help: add `;` here + | +LL | const A: &'static str = r""; + | + error: too many `#` when terminating raw string --> $DIR/raw-str-unbalanced.rs:16:28 diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr index 7012096b6445..8e5b76163ade 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr @@ -5,7 +5,12 @@ LL | type T0 = const fn(); | -----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T0 = const fn(); +LL + type T0 = fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:4:11 @@ -14,7 +19,12 @@ LL | type T1 = const extern "C" fn(); | -----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T1 = const extern "C" fn(); +LL + type T1 = extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:5:11 @@ -23,7 +33,12 @@ LL | type T2 = const unsafe extern fn(); | -----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T2 = const unsafe extern fn(); +LL + type T2 = unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:6:11 @@ -32,7 +47,12 @@ LL | type T3 = async fn(); | -----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T3 = async fn(); +LL + type T3 = fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:7:11 @@ -41,7 +61,12 @@ LL | type T4 = async extern fn(); | -----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T4 = async extern fn(); +LL + type T4 = extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:8:11 @@ -50,7 +75,12 @@ LL | type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T5 = async unsafe extern "C" fn(); +LL + type T5 = unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:9:11 @@ -59,7 +89,12 @@ LL | type T6 = const async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T6 = const async unsafe extern "C" fn(); +LL + type T6 = async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:9:11 @@ -68,7 +103,12 @@ LL | type T6 = const async unsafe extern "C" fn(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T6 = const async unsafe extern "C" fn(); +LL + type T6 = const unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:13:12 @@ -77,7 +117,12 @@ LL | type FT0 = for<'a> const fn(); | ^^^^^^^^-----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT0 = for<'a> const fn(); +LL + type FT0 = for<'a> fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:14:12 @@ -86,7 +131,12 @@ LL | type FT1 = for<'a> const extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT1 = for<'a> const extern "C" fn(); +LL + type FT1 = for<'a> extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:15:12 @@ -95,7 +145,12 @@ LL | type FT2 = for<'a> const unsafe extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT2 = for<'a> const unsafe extern fn(); +LL + type FT2 = for<'a> unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:16:12 @@ -104,7 +159,12 @@ LL | type FT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT3 = for<'a> async fn(); +LL + type FT3 = for<'a> fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:17:12 @@ -113,7 +173,12 @@ LL | type FT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT4 = for<'a> async extern fn(); +LL + type FT4 = for<'a> extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:18:12 @@ -122,7 +187,12 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT5 = for<'a> async unsafe extern "C" fn(); +LL + type FT5 = for<'a> unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:19:12 @@ -131,7 +201,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT6 = for<'a> const async unsafe extern "C" fn(); +LL + type FT6 = for<'a> async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:19:12 @@ -140,7 +215,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT6 = for<'a> const async unsafe extern "C" fn(); +LL + type FT6 = for<'a> const unsafe extern "C" fn(); + | error[E0308]: mismatched types --> $DIR/recover-const-async-fn-ptr.rs:24:33 diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr index 2b56498c50d3..68d57f20bd77 100644 --- a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr +++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr @@ -1,11 +1,14 @@ error: unmatched angle bracket --> $DIR/recover-field-extra-angle-brackets-in-struct-with-a-field.rs:2:25 | -LL | next: Option> - | _________________________^ -LL | | -LL | | } - | |_ help: remove extra angle bracket +LL | next: Option> + | ^ + | +help: remove extra angle bracket + | +LL - next: Option> +LL + next: Option + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr index 628626926a78..45af63133918 100644 --- a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr +++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr @@ -2,7 +2,13 @@ error: unmatched angle bracket --> $DIR/recover-field-extra-angle-brackets.rs:5:19 | LL | first: Vec>, - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - first: Vec>, +LL + first: Vec, + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr index 61c43f2f1899..8a87d44c9591 100644 --- a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr +++ b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr @@ -2,82 +2,132 @@ error: expected `;`, found keyword `struct` --> $DIR/recover-missing-semi-before-item.rs:6:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | struct Foo; | ------ unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found `union` --> $DIR/recover-missing-semi-before-item.rs:11:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | union Foo { | ----- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `enum` --> $DIR/recover-missing-semi-before-item.rs:18:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | enum Foo { | ---- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `fn` --> $DIR/recover-missing-semi-before-item.rs:25:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | fn foo() {} | -- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `extern` --> $DIR/recover-missing-semi-before-item.rs:30:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | extern fn foo() {} | ------ unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `impl` --> $DIR/recover-missing-semi-before-item.rs:36:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | impl Foo {} | ---- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `pub` --> $DIR/recover-missing-semi-before-item.rs:41:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | pub use bar::Bar; | --- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `mod` --> $DIR/recover-missing-semi-before-item.rs:46:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | mod foo {} | --- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `type` --> $DIR/recover-missing-semi-before-item.rs:51:16 | LL | let foo = 3 - | ^ help: add `;` here + | ^ LL | type Foo = usize; | ---- unexpected token + | +help: add `;` here + | +LL | let foo = 3; + | + error: expected `;`, found keyword `fn` --> $DIR/recover-missing-semi-before-item.rs:59:19 | LL | const X: i32 = 123 - | ^ help: add `;` here + | ^ LL | LL | fn main() {} | -- unexpected token + | +help: add `;` here + | +LL | const X: i32 = 123; + | + error: aborting due to 10 previous errors diff --git a/tests/ui/parser/recover/recover-missing-semi.stderr b/tests/ui/parser/recover/recover-missing-semi.stderr index ba4798285387..3e8cb37160ec 100644 --- a/tests/ui/parser/recover/recover-missing-semi.stderr +++ b/tests/ui/parser/recover/recover-missing-semi.stderr @@ -2,19 +2,29 @@ error: expected `;`, found keyword `let` --> $DIR/recover-missing-semi.rs:2:22 | LL | let _: usize = () - | ^ help: add `;` here + | ^ ... LL | let _ = 3; | --- unexpected token + | +help: add `;` here + | +LL | let _: usize = (); + | + error: expected `;`, found keyword `return` --> $DIR/recover-missing-semi.rs:9:22 | LL | let _: usize = () - | ^ help: add `;` here + | ^ ... LL | return 3; | ------ unexpected token + | +help: add `;` here + | +LL | let _: usize = (); + | + error[E0308]: mismatched types --> $DIR/recover-missing-semi.rs:2:20 diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr index e29b6c1c666b..b8e91c2344af 100644 --- a/tests/ui/parser/recover/recover-range-pats.stderr +++ b/tests/ui/parser/recover/recover-range-pats.stderr @@ -2,196 +2,330 @@ error: float literals must have an integer part --> $DIR/recover-range-pats.rs:20:12 | LL | if let .0..Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:22:16 | LL | if let X.. .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X.. 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:33:12 | LL | if let .0..=Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..=Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:35:16 | LL | if let X..=.0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X..=0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:58:12 | LL | if let .0...Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0...Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:62:17 | LL | if let X... .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X... 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:73:12 | LL | if let .0.. = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0.. = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:79:13 | LL | if let 0..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0..= = 0 {} +LL + if let 0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:80:13 | LL | if let X..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X..= = 0 {} +LL + if let X.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:81:16 | LL | if let true..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let true..= = 0 {} +LL + if let true.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:83:12 | LL | if let .0..= = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..= = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:83:14 | LL | if let .0..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let .0..= = 0 {} +LL + if let .0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:89:13 | LL | if let 0... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0... = 0 {} +LL + if let 0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:90:13 | LL | if let X... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X... = 0 {} +LL + if let X.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:91:16 | LL | if let true... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let true... = 0 {} +LL + if let true.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:93:12 | LL | if let .0... = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0... = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:93:14 | LL | if let .0... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let .0... = 0 {} +LL + if let .0.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:103:15 | LL | if let .. .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let .. 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:113:15 | LL | if let ..=.0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let ..=0.0 = 0 {} + | + error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:119:12 | LL | if let ...3 = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=3 = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:121:12 | LL | if let ...Y = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=Y = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:123:12 | LL | if let ...true = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=true = 0 {} + | ~~~ error: float literals must have an integer part --> $DIR/recover-range-pats.rs:126:15 | LL | if let ....3 = 0 {} - | ^^ help: must have an integer part: `0.3` + | ^^ + | +help: must have an integer part + | +LL | if let ...0.3 = 0 {} + | + error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:126:12 | LL | if let ....3 = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=.3 = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:152:17 | LL | let ...$e; - | ^^^ help: use `..=` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..=` instead + | +LL | let ..=$e; + | ~~~ error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:159:19 | LL | let $e...; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e...; +LL + let $e..; + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:161:19 | LL | let $e..=; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e..=; +LL + let $e..; + | error: `...` range patterns are deprecated --> $DIR/recover-range-pats.rs:40:13 diff --git a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr index c048c8ea1b0d..bb0f0b0214c4 100644 --- a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr +++ b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr @@ -2,7 +2,12 @@ error: `mut` must precede `dyn` --> $DIR/recover-ref-dyn-mut.rs:5:12 | LL | let r: &dyn mut Trait; - | ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn` + | ^^^^^^^^ + | +help: place `mut` before `dyn` + | +LL | let r: &mut dyn Trait; + | ~~~~~~~~ error[E0405]: cannot find trait `Trait` in this scope --> $DIR/recover-ref-dyn-mut.rs:5:21 diff --git a/tests/ui/parser/recover/recover-unticked-labels.stderr b/tests/ui/parser/recover/recover-unticked-labels.stderr index fbd108ca613c..5cf463677af1 100644 --- a/tests/ui/parser/recover/recover-unticked-labels.stderr +++ b/tests/ui/parser/recover/recover-unticked-labels.stderr @@ -2,17 +2,23 @@ error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:5:26 | LL | 'label: loop { break label 0 }; - | -^^^^ - | | - | help: labels start with a tick + | ^^^^^ + | +help: labels start with a tick + | +LL | 'label: loop { break 'label 0 }; + | + error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:6:29 | LL | 'label: loop { continue label }; - | -^^^^ - | | - | help: labels start with a tick + | ^^^^^ + | +help: labels start with a tick + | +LL | 'label: loop { continue 'label }; + | + error[E0425]: cannot find value `label` in this scope --> $DIR/recover-unticked-labels.rs:4:26 diff --git a/tests/ui/parser/regions-out-of-scope-slice.stderr b/tests/ui/parser/regions-out-of-scope-slice.stderr index 5d8f6af166bd..838dcde2850c 100644 --- a/tests/ui/parser/regions-out-of-scope-slice.stderr +++ b/tests/ui/parser/regions-out-of-scope-slice.stderr @@ -2,10 +2,15 @@ error: borrow expressions cannot be annotated with lifetimes --> $DIR/regions-out-of-scope-slice.rs:7:13 | LL | x = &'blk [1,2,3]; - | ^----^^^^^^^^ + | ^-----^^^^^^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - x = &'blk [1,2,3]; +LL + x = &[1,2,3]; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr index c089e0ba9693..0cdee1d51eac 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr @@ -2,7 +2,12 @@ error: missing parameters for function definition --> $DIR/removed-syntax-fn-sigil.rs:2:14 | LL | let x: fn~() = || (); - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | let x: fn()~() = || (); + | ++ error: expected one of `->`, `;`, or `=`, found `~` --> $DIR/removed-syntax-fn-sigil.rs:2:14 diff --git a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr index 52e0658949d3..d3ed7fc6376d 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr @@ -19,7 +19,12 @@ error: missing type for `static` item --> $DIR/removed-syntax-static-fn.rs:4:14 | LL | static fn f() {} - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static fn: f() {} + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr index 7f16ebcfc3ac..1fb57ab11f9f 100644 --- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr +++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr @@ -2,37 +2,73 @@ error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16 | LL | field1: i32 = 42, - | ^^^^^ help: remove this unsupported default value + | ^^^^^ + | +help: remove this unsupported default value + | +LL - field1: i32 = 42, +LL + field1: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14 | LL | field2: E = E::A, - | ^^^^^^^ help: remove this unsupported default value + | ^^^^^^^ + | +help: remove this unsupported default value + | +LL - field2: E = E::A, +LL + field2: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16 | LL | field3: i32 = 1 + 2, - | ^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field3: i32 = 1 + 2, +LL + field3: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16 | LL | field4: i32 = { 1 + 2 }, - | ^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field4: i32 = { 1 + 2 }, +LL + field4: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14 | LL | field5: E = foo(42), - | ^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field5: E = foo(42), +LL + field5: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14 | LL | field6: E = { foo(42) }, - | ^^^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field6: E = { foo(42) }, +LL + field6: E, + | error: expected `,`, or `}`, found `field2` --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16 @@ -50,25 +86,49 @@ error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16 | LL | field3: i32 = 1 + 2, - | ^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field3: i32 = 1 + 2, +LL + field3: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16 | LL | field4: i32 = { 1 + 2 }, - | ^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field4: i32 = { 1 + 2 }, +LL + field4: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14 | LL | field5: E = foo(42), - | ^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field5: E = foo(42), +LL + field5: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14 | LL | field6: E = { foo(42) }, - | ^^^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field6: E = { foo(42) }, +LL + field6: E, + | error: expected `:`, found `=` --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12 diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 5f175e86545a..be130ac7ab23 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -2,7 +2,12 @@ error: ambiguous `+` in a type --> $DIR/trait-object-delimiters.rs:3:13 | LL | fn foo1(_: &dyn Drop + AsRef) {} - | ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn foo1(_: &(dyn Drop + AsRef)) {} + | + + error: incorrect parentheses around trait bounds --> $DIR/trait-object-delimiters.rs:6:17 @@ -52,9 +57,14 @@ error: invalid `dyn` keyword --> $DIR/trait-object-delimiters.rs:16:25 | LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} - | ^^^ help: remove this keyword + | ^^^ | = help: `dyn` is only needed at the start of a trait `+`-separated list +help: remove this keyword + | +LL - fn foo5(_: &(dyn Drop + dyn AsRef)) {} +LL + fn foo5(_: &(dyn Drop + AsRef)) {} + | error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-object-delimiters.rs:3:24 diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.stderr index 9c7a9662c402..280c0e40c640 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.stderr +++ b/tests/ui/parser/trait-object-lifetime-parens.stderr @@ -2,13 +2,25 @@ error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:5:21 | LL | fn f<'a, T: Trait + ('a)>() {} - | ^^^^ help: remove the parentheses + | ^^^^ + | +help: remove the parentheses + | +LL - fn f<'a, T: Trait + ('a)>() {} +LL + fn f<'a, T: Trait + 'a>() {} + | error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:8:24 | LL | let _: Box; - | ^^^^ help: remove the parentheses + | ^^^^ + | +help: remove the parentheses + | +LL - let _: Box; +LL + let _: Box; + | error: lifetime in trait object type must be followed by `+` --> $DIR/trait-object-lifetime-parens.rs:10:17 diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs index 63425f3e2018..e7f085104ae9 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.rs +++ b/tests/ui/parser/trait-object-polytrait-priority.rs @@ -6,5 +6,4 @@ fn main() { let _: &for<'a> Trait<'a> + 'static; //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` //~| HELP try adding parentheses - //~| SUGGESTION &(for<'a> Trait<'a> + 'static) } diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr index 23ec1e9cf3d4..8cb564e79300 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.stderr +++ b/tests/ui/parser/trait-object-polytrait-priority.stderr @@ -2,7 +2,12 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait< --> $DIR/trait-object-polytrait-priority.rs:6:12 | LL | let _: &for<'a> Trait<'a> + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&(for<'a> Trait<'a> + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &(for<'a> Trait<'a> + 'static); + | + + error: aborting due to 1 previous error diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 726cde2b413e..a1561e7f04b0 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -34,15 +34,17 @@ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:17:14 | LL | let _a = 'Å'; - | ^-^ - | | - | help: consider using the normalized form `\u{c5}` of this character: `Å` + | ^^^ | note: this `A` is followed by the combining mark `\u{30a}` --> $DIR/unicode-character-literal.rs:17:15 | LL | let _a = 'Å'; | ^ +help: consider using the normalized form `\u{c5}` of this character + | +LL | let _a = 'Å'; + | ~ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unmatched-langle-1.stderr b/tests/ui/parser/unmatched-langle-1.stderr index cdf74bdedc2e..3411a05fb589 100644 --- a/tests/ui/parser/unmatched-langle-1.stderr +++ b/tests/ui/parser/unmatched-langle-1.stderr @@ -2,7 +2,13 @@ error: unmatched angle brackets --> $DIR/unmatched-langle-1.rs:5:10 | LL | foo::<<<>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - foo::<<<>(); +LL + foo::>(); + | error[E0412]: cannot find type `Ty` in this scope --> $DIR/unmatched-langle-1.rs:5:14 diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr index 952119cae3e2..c6ac0d562f82 100644 --- a/tests/ui/parser/unnecessary-let.stderr +++ b/tests/ui/parser/unnecessary-let.stderr @@ -2,19 +2,36 @@ error: expected pattern, found `let` --> $DIR/unnecessary-let.rs:2:9 | LL | for let x of [1, 2, 3] {} - | ^^^ help: remove the unnecessary `let` keyword + | ^^^ + | +help: remove the unnecessary `let` keyword + | +LL - for let x of [1, 2, 3] {} +LL + for x of [1, 2, 3] {} + | error: missing `in` in `for` loop --> $DIR/unnecessary-let.rs:2:15 | LL | for let x of [1, 2, 3] {} - | ^^ help: try using `in` here instead + | ^^ + | +help: try using `in` here instead + | +LL | for let x in [1, 2, 3] {} + | ~~ error: expected pattern, found `let` --> $DIR/unnecessary-let.rs:7:9 | LL | let 1 => {} - | ^^^ help: remove the unnecessary `let` keyword + | ^^^ + | +help: remove the unnecessary `let` keyword + | +LL - let 1 => {} +LL + 1 => {} + | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/use-colon-as-mod-sep.stderr b/tests/ui/parser/use-colon-as-mod-sep.stderr index bfc5374ef9d2..347b271df990 100644 --- a/tests/ui/parser/use-colon-as-mod-sep.stderr +++ b/tests/ui/parser/use-colon-as-mod-sep.stderr @@ -2,33 +2,49 @@ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:3:17 | LL | use std::process:Command; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::process::Command; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:5:8 | LL | use std:fs::File; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::fs::File; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:8 | LL | use std:collections:HashMap; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::collections:HashMap; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:20 | LL | use std:collections:HashMap; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std:collections::HashMap; + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr index 2f45415844d8..1599edd7a992 100644 --- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr +++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr @@ -6,7 +6,11 @@ LL | let _ @ a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `a @ _` + | +help: switch the order + | +LL | let a @ _ = 0; + | ~~~~~ error: pattern on wrong side of `@` --> $DIR/wild-before-at-syntactically-rejected.rs:10:9 @@ -16,7 +20,11 @@ LL | let _ @ ref a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `ref a @ _` + | +help: switch the order + | +LL | let ref a @ _ = 0; + | ~~~~~~~~~ error: pattern on wrong side of `@` --> $DIR/wild-before-at-syntactically-rejected.rs:12:9 @@ -26,7 +34,11 @@ LL | let _ @ ref mut a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `ref mut a @ _` + | +help: switch the order + | +LL | let ref mut a @ _ = 0; + | ~~~~~~~~~~~~~ error: left-hand side of `@` must be a binding --> $DIR/wild-before-at-syntactically-rejected.rs:14:9 diff --git a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr index 167016397d21..622358126b09 100644 --- a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr +++ b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr @@ -2,9 +2,13 @@ error: `mut` must be attached to each individual binding --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9 | LL | let mut &x = &0; - | ^^^^^^ help: add `mut` to each binding: `&(mut x)` + | ^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let &(mut x) = &0; + | ~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.stderr b/tests/ui/pattern/pattern-bad-ref-box-order.stderr index a49f05c1028d..a89d3ed21b62 100644 --- a/tests/ui/pattern/pattern-bad-ref-box-order.stderr +++ b/tests/ui/pattern/pattern-bad-ref-box-order.stderr @@ -2,7 +2,12 @@ error: switch the order of `ref` and `box` --> $DIR/pattern-bad-ref-box-order.rs:8:14 | LL | Some(ref box _i) => {}, - | ^^^^^^^ help: swap them: `box ref` + | ^^^^^^^ + | +help: swap them + | +LL | Some(box ref _i) => {}, + | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr index 37c02eb6ada9..9d642b9245a2 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr @@ -2,7 +2,12 @@ error: range-to patterns with `...` are not allowed --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:13 | LL | [_, ...tail] => println!("{tail}"), - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | [_, ..=tail] => println!("{tail}"), + | ~~~ error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 diff --git a/tests/ui/pub/pub-restricted.stderr b/tests/ui/pub/pub-restricted.stderr index 4694530e5486..fc177aa2033e 100644 --- a/tests/ui/pub/pub-restricted.stderr +++ b/tests/ui/pub/pub-restricted.stderr @@ -2,56 +2,76 @@ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:3:6 | LL | pub (a) fn afn() {} - | ^ help: make this visible only to module `a` with `in`: `in a` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `a` with `in` + | +LL | pub (in a) fn afn() {} + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:4:6 | LL | pub (b) fn bfn() {} - | ^ help: make this visible only to module `b` with `in`: `in b` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `b` with `in` + | +LL | pub (in b) fn bfn() {} + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:5:6 | LL | pub (crate::a) fn cfn() {} - | ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a` + | ^^^^^^^^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `crate::a` with `in` + | +LL | pub (in crate::a) fn cfn() {} + | ~~~~~~~~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:22:14 | LL | pub (a) invalid: usize, - | ^ help: make this visible only to module `a` with `in`: `in a` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `a` with `in` + | +LL | pub (in a) invalid: usize, + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:31:6 | LL | pub (xyz) fn xyz() {} - | ^^^ help: make this visible only to module `xyz` with `in`: `in xyz` + | ^^^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `xyz` with `in` + | +LL | pub (in xyz) fn xyz() {} + | ~~~~~~ error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/pub-restricted.rs:23:17 diff --git a/tests/ui/range/impossible_range.stderr b/tests/ui/range/impossible_range.stderr index 53c56065c2a3..17dd264e3660 100644 --- a/tests/ui/range/impossible_range.stderr +++ b/tests/ui/range/impossible_range.stderr @@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:11:5 | LL | ..=; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - ..=; +LL + ..; + | error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:18:6 | LL | 0..=; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - 0..=; +LL + 0..; + | error: aborting due to 2 previous errors diff --git a/tests/ui/range/range-inclusive-pattern-precedence.stderr b/tests/ui/range/range-inclusive-pattern-precedence.stderr index 2e2d7983c03a..9df20fc45456 100644 --- a/tests/ui/range/range-inclusive-pattern-precedence.stderr +++ b/tests/ui/range/range-inclusive-pattern-precedence.stderr @@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence.rs:15:10 | LL | &10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` + | ^^^^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(10..=15) => {} + | + + warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence.rs:11:9 diff --git a/tests/ui/range/range-inclusive-pattern-precedence2.stderr b/tests/ui/range/range-inclusive-pattern-precedence2.stderr index 84294604c80f..fd2fa78e92b5 100644 --- a/tests/ui/range/range-inclusive-pattern-precedence2.stderr +++ b/tests/ui/range/range-inclusive-pattern-precedence2.stderr @@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence2.rs:14:13 | LL | box 10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` + | ^^^^^^^ + | +help: add parentheses to clarify the precedence + | +LL | box (10..=15) => {} + | + + warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence2.rs:10:14 diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr index 17d1b7e0d43b..05980510f1cd 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr @@ -2,13 +2,23 @@ error: expected `,` following `match` arm --> $DIR/parse.rs:26:16 | LL | Some(!) - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(!), + | + error: expected `,` following `match` arm --> $DIR/parse.rs:31:24 | LL | Some(!) if true - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(!) if true, + | + error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=` --> $DIR/parse.rs:42:17 @@ -20,7 +30,12 @@ error: top-level or-patterns are not allowed in `let` bindings --> $DIR/parse.rs:67:9 | LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048. - | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))` + | ^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (Ok(_) | Err(!)) = &res; // Disallowed; see #82048. + | + + error: never patterns cannot contain variable bindings --> $DIR/parse.rs:73:9 diff --git a/tests/ui/self/self-vs-path-ambiguity.stderr b/tests/ui/self/self-vs-path-ambiguity.stderr index 9e140e21023f..557a63a2af16 100644 --- a/tests/ui/self/self-vs-path-ambiguity.stderr +++ b/tests/ui/self/self-vs-path-ambiguity.stderr @@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern --> $DIR/self-vs-path-ambiguity.rs:9:11 | LL | fn i(&'a self::S: &S) {} - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - fn i(&'a self::S: &S) {} +LL + fn i(&self::S: &S) {} + | error: aborting due to 1 previous error diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index 4909a9cdc7f5..8298293a8cbb 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -14,9 +14,14 @@ error: `mut` must be followed by a named binding --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - mut Self => (), +LL + Self => (), + | error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:19:17 diff --git a/tests/ui/structs/struct-duplicate-comma.stderr b/tests/ui/structs/struct-duplicate-comma.stderr index 4ac3fc9fe6b2..dc1c6ae87165 100644 --- a/tests/ui/structs/struct-duplicate-comma.stderr +++ b/tests/ui/structs/struct-duplicate-comma.stderr @@ -4,10 +4,13 @@ error: expected identifier, found `,` LL | let _ = Foo { | --- while parsing this struct LL | a: 0,, - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - a: 0,, +LL + a: 0, + | error: aborting due to 1 previous error diff --git a/tests/ui/structs/struct-field-init-syntax.stderr b/tests/ui/structs/struct-field-init-syntax.stderr index 0b72c5cf734c..66098d5f610e 100644 --- a/tests/ui/structs/struct-field-init-syntax.stderr +++ b/tests/ui/structs/struct-field-init-syntax.stderr @@ -2,17 +2,27 @@ error: cannot use a comma after the base struct --> $DIR/struct-field-init-syntax.rs:11:9 | LL | ..Foo::default(), - | ^^^^^^^^^^^^^^^^- help: remove this comma + | ^^^^^^^^^^^^^^^^ | = note: the base struct must always be the last field +help: remove this comma + | +LL - ..Foo::default(), +LL + ..Foo::default() + | error: cannot use a comma after the base struct --> $DIR/struct-field-init-syntax.rs:16:9 | LL | ..Foo::default(), - | ^^^^^^^^^^^^^^^^- help: remove this comma + | ^^^^^^^^^^^^^^^^ | = note: the base struct must always be the last field +help: remove this comma + | +LL - ..Foo::default(), +LL + ..Foo::default() + | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/const-no-type.stderr b/tests/ui/suggestions/const-no-type.stderr index bd703992fd4a..c85c58989073 100644 --- a/tests/ui/suggestions/const-no-type.stderr +++ b/tests/ui/suggestions/const-no-type.stderr @@ -26,19 +26,34 @@ error: missing type for `const` item --> $DIR/const-no-type.rs:14:9 | LL | const C2 = 42; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const C2: = 42; + | ++++++++ error: missing type for `static` item --> $DIR/const-no-type.rs:20:10 | LL | static S2 = "abc"; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static S2: = "abc"; + | ++++++++ error: missing type for `static mut` item --> $DIR/const-no-type.rs:26:15 | LL | static mut SM2 = "abc"; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static mut SM2: = "abc"; + | ++++++++ error: aborting due to 7 previous errors diff --git a/tests/ui/suggestions/js-style-comparison-op.stderr b/tests/ui/suggestions/js-style-comparison-op.stderr index 33f7a0844fd2..58b1fddd3ddd 100644 --- a/tests/ui/suggestions/js-style-comparison-op.stderr +++ b/tests/ui/suggestions/js-style-comparison-op.stderr @@ -2,13 +2,23 @@ error: invalid comparison operator `===` --> $DIR/js-style-comparison-op.rs:3:10 | LL | if 1 === 1 { - | ^^^ help: `===` is not a valid comparison operator, use `==` + | ^^^ + | +help: `===` is not a valid comparison operator, use `==` + | +LL | if 1 == 1 { + | ~~ error: invalid comparison operator `!==` --> $DIR/js-style-comparison-op.rs:5:17 | LL | } else if 1 !== 1 { - | ^^^ help: `!==` is not a valid comparison operator, use `!=` + | ^^^ + | +help: `!==` is not a valid comparison operator, use `!=` + | +LL | } else if 1 != 1 { + | ~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/missing-semicolon.stderr b/tests/ui/suggestions/missing-semicolon.stderr index 54a64f664b50..86404e4511c2 100644 --- a/tests/ui/suggestions/missing-semicolon.stderr +++ b/tests/ui/suggestions/missing-semicolon.stderr @@ -2,17 +2,27 @@ error: expected `;`, found `}` --> $DIR/missing-semicolon.rs:6:7 | LL | () - | ^ help: add `;` here + | ^ LL | } | - unexpected token + | +help: add `;` here + | +LL | (); + | + error: expected `;`, found `}` --> $DIR/missing-semicolon.rs:32:7 | LL | () - | ^ help: add `;` here + | ^ LL | } | - unexpected token + | +help: add `;` here + | +LL | (); + | + error[E0618]: expected function, found `{integer}` --> $DIR/missing-semicolon.rs:5:13 diff --git a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr index e068fdb5abac..dd8f896d88e7 100644 --- a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr +++ b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr @@ -2,25 +2,40 @@ error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:2:9 | LL | mod M {}; - | ^ help: remove this semicolon + | ^ | = help: module declarations are not followed by a semicolon +help: remove this semicolon + | +LL - mod M {}; +LL + mod M {} + | error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:4:12 | LL | struct S {}; - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - struct S {}; +LL + struct S {} + | error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:6:20 | LL | fn foo(a: usize) {}; - | ^ help: remove this semicolon + | ^ | = help: function declarations are not followed by a semicolon +help: remove this semicolon + | +LL - fn foo(a: usize) {}; +LL + fn foo(a: usize) {} + | error[E0308]: mismatched types --> $DIR/recover-from-semicolon-trailing-item.rs:10:20 diff --git a/tests/ui/suggestions/recover-invalid-float.stderr b/tests/ui/suggestions/recover-invalid-float.stderr index dd24746eab80..9e4ea6d3089a 100644 --- a/tests/ui/suggestions/recover-invalid-float.stderr +++ b/tests/ui/suggestions/recover-invalid-float.stderr @@ -2,19 +2,34 @@ error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:4:18 | LL | let _: f32 = .3; - | ^^ help: must have an integer part: `0.3` + | ^^ + | +help: must have an integer part + | +LL | let _: f32 = 0.3; + | + error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:6:18 | LL | let _: f32 = .42f32; - | ^^^^^^ help: must have an integer part: `0.42f32` + | ^^^^^^ + | +help: must have an integer part + | +LL | let _: f32 = 0.42f32; + | + error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:8:18 | LL | let _: f64 = .5f64; - | ^^^^^ help: must have an integer part: `0.5f64` + | ^^^^^ + | +help: must have an integer part + | +LL | let _: f64 = 0.5f64; + | + error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr b/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr index 12da91c20b3c..3d6983ec8f98 100644 --- a/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr +++ b/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr @@ -2,9 +2,14 @@ error: expected `;`, found `}` --> $DIR/suggest-semicolon-for-fn-in-extern-block.rs:6:11 | LL | fn foo() - | ^ help: add `;` here + | ^ LL | } | - unexpected token + | +help: add `;` here + | +LL | fn foo(); + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr index 3242b028d5d3..06f806b90163 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-method.rs:3:16 | LL | let _ = Box:new("foo".to_string()); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Box::new("foo".to_string()); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr index 566b036e53e4..9b09a60c1617 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-path.rs:2:8 | LL | std:io::stdin(); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | std::io::stdin(); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr index 6fea7f940523..0ecdc82b5412 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-variant.rs:3:19 | LL | let _ = Option:Some(""); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Option::Some(""); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr index 562ce53052bd..d76d591ec33f 100644 --- a/tests/ui/type/ascription/issue-47666.stderr +++ b/tests/ui/type/ascription/issue-47666.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-47666.rs:3:19 | LL | let _ = Option:Some(vec![0, 1]); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Option::Some(vec![0, 1]); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr index 2c567a1a0ff6..bea2c0d85b3a 100644 --- a/tests/ui/type/ascription/issue-54516.stderr +++ b/tests/ui/type/ascription/issue-54516.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-54516.rs:5:28 | LL | println!("{}", std::mem:size_of::>()); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | println!("{}", std::mem::size_of::>()); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr index cd184ceba331..a81238bd5400 100644 --- a/tests/ui/type/ascription/issue-60933.stderr +++ b/tests/ui/type/ascription/issue-60933.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-60933.rs:3:28 | LL | let _: usize = std::mem:size_of::(); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _: usize = std::mem::size_of::(); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr index 2abf27100c1d..f5cf7930c832 100644 --- a/tests/ui/type/pattern_types/bad_pat.stderr +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end --> $DIR/bad_pat.rs:7:43 | LL | type NonNullU32_2 = pattern_type!(u32 is 1..=); - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - type NonNullU32_2 = pattern_type!(u32 is 1..=); +LL + type NonNullU32_2 = pattern_type!(u32 is 1..); + | error[E0586]: inclusive range with no end --> $DIR/bad_pat.rs:9:40 | LL | type Positive2 = pattern_type!(i32 is 0..=); - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - type Positive2 = pattern_type!(i32 is 0..=); +LL + type Positive2 = pattern_type!(i32 is 0..); + | error: wildcard patterns are not permitted for pattern types --> $DIR/bad_pat.rs:11:33 diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr index 8c09e78bc5fb..34c886423239 100644 --- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr +++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr @@ -2,9 +2,13 @@ error: statements are terminated with a semicolon --> $DIR/type-ascription-instead-of-statement-end.rs:2:21 | LL | println!("test"): - | ^ help: use a semicolon instead: `;` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a semicolon instead + | +LL | println!("test"); + | ~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` --> $DIR/type-ascription-instead-of-statement-end.rs:7:21 diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr index 2ae5873c8242..2691f10cf3ed 100644 --- a/tests/ui/type/type-ascription-with-fn-call.stderr +++ b/tests/ui/type/type-ascription-with-fn-call.stderr @@ -2,9 +2,13 @@ error: statements are terminated with a semicolon --> $DIR/type-ascription-with-fn-call.rs:3:10 | LL | f() : - | ^ help: use a semicolon instead: `;` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a semicolon instead + | +LL | f() ; + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr index 8982d6285617..4450aa66c132 100644 --- a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr +++ b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr @@ -8,13 +8,23 @@ error: missing type for `const` item --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:2:12 | LL | const A; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const A: ; + | ++++++++ error: missing type for `static` item --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:3:13 | LL | static B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static B: ; + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/typeck/issue-79040.stderr index ce6a4b362170..39636db85a78 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/typeck/issue-79040.stderr @@ -10,7 +10,12 @@ error: missing type for `const` item --> $DIR/issue-79040.rs:2:14 | LL | const FOO = "hello" + 1; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const FOO: = "hello" + 1; + | ++++++++ error[E0369]: cannot add `{integer}` to `&str` --> $DIR/issue-79040.rs:2:25 From c2b3287483fb7fc1be7fdfbfd25044dd7a0320c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 11 Jul 2024 21:04:01 +0000 Subject: [PATCH 233/361] Make `impl` and `!` removal suggestion `short` --- compiler/rustc_parse/src/errors.rs | 4 ++-- .../ui/impl-trait/extra-impl-in-trait-impl.stderr | 14 ++------------ tests/ui/macros/bang-after-name.stderr | 8 +------- tests/ui/macros/missing-bang-in-decl.stderr | 8 +------- 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0f13a8e5e141..d2a765247ad6 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1784,7 +1784,7 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { #[diag(parse_extra_impl_keyword_in_trait_impl)] pub(crate) struct ExtraImplKeywordInTraitImpl { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "short")] pub extra_impl_kw: Span, #[note] pub impl_trait_span: Span, @@ -2890,7 +2890,7 @@ pub(crate) struct MacroRulesMissingBang { #[diag(parse_macro_name_remove_bang)] pub(crate) struct MacroNameRemoveBang { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + #[suggestion(code = "", applicability = "machine-applicable", style = "short")] pub span: Span, } diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr index e4d14c4807c9..91c7da5a04fb 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -2,35 +2,25 @@ error: unexpected `impl` keyword --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { - | ^^^^^ + | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { | ^^^^^^^^^^^^ -help: remove the extra `impl` - | -LL - impl impl Default for S { -LL + impl Default for S { - | error: unexpected `impl` keyword --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { - | ^^^^^ + | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { | ^^^^^^^^^^^^ -help: remove the extra `impl` - | -LL - impl impl Default for S2 { -LL + impl Default for S2 { - | error: aborting due to 2 previous errors diff --git a/tests/ui/macros/bang-after-name.stderr b/tests/ui/macros/bang-after-name.stderr index 8433c375c01b..27853161e4f3 100644 --- a/tests/ui/macros/bang-after-name.stderr +++ b/tests/ui/macros/bang-after-name.stderr @@ -2,13 +2,7 @@ error: macro names aren't followed by a `!` --> $DIR/bang-after-name.rs:4:17 | LL | macro_rules! foo! { - | ^ - | -help: remove the `!` - | -LL - macro_rules! foo! { -LL + macro_rules! foo { - | + | ^ help: remove the `!` error: aborting due to 1 previous error diff --git a/tests/ui/macros/missing-bang-in-decl.stderr b/tests/ui/macros/missing-bang-in-decl.stderr index 348a94ec2c05..aa78c9a69064 100644 --- a/tests/ui/macros/missing-bang-in-decl.stderr +++ b/tests/ui/macros/missing-bang-in-decl.stderr @@ -24,13 +24,7 @@ error: macro names aren't followed by a `!` --> $DIR/missing-bang-in-decl.rs:10:16 | LL | macro_rules bar! { - | ^ - | -help: remove the `!` - | -LL - macro_rules bar! { -LL + macro_rules bar { - | + | ^ help: remove the `!` error: aborting due to 3 previous errors From dd40e0b4eeef38d62e7053733ac7c2a327b135de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 11 Jul 2024 21:42:15 +0000 Subject: [PATCH 234/361] Tweak tests to avoid confusing suggestion output --- tests/ui/enum/nested-enum.rs | 9 ++++++--- tests/ui/enum/nested-enum.stderr | 7 ++----- .../fn-no-semicolon-issue-124935-semi-after-item.rs | 3 ++- .../fn-no-semicolon-issue-124935-semi-after-item.stderr | 1 - .../issues/missing-main-issue-124935-semi-after-item.rs | 3 ++- .../missing-main-issue-124935-semi-after-item.stderr | 1 - 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/ui/enum/nested-enum.rs b/tests/ui/enum/nested-enum.rs index 80957b8a14c2..ff39fdee6bc6 100644 --- a/tests/ui/enum/nested-enum.rs +++ b/tests/ui/enum/nested-enum.rs @@ -1,7 +1,10 @@ enum Foo { - enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum` - struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum` - union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum` + enum Bar { Baz }, + //~^ ERROR `enum` definition cannot be nested inside `enum` + struct Quux { field: u8 }, + //~^ ERROR `struct` definition cannot be nested inside `enum` + union Wibble { field: u8 }, + //~^ ERROR `union` definition cannot be nested inside `enum` Bat, } diff --git a/tests/ui/enum/nested-enum.stderr b/tests/ui/enum/nested-enum.stderr index 0f9c8025c452..78df333abb31 100644 --- a/tests/ui/enum/nested-enum.stderr +++ b/tests/ui/enum/nested-enum.stderr @@ -7,11 +7,10 @@ LL | enum Bar { Baz }, help: consider creating a new `enum` definition instead of nesting | LL - enum Bar { Baz }, -LL + | error: `struct` definition cannot be nested inside `enum` - --> $DIR/nested-enum.rs:3:5 + --> $DIR/nested-enum.rs:4:5 | LL | struct Quux { field: u8 }, | ^^^^^^ @@ -19,11 +18,10 @@ LL | struct Quux { field: u8 }, help: consider creating a new `struct` definition instead of nesting | LL - struct Quux { field: u8 }, -LL + | error: `union` definition cannot be nested inside `enum` - --> $DIR/nested-enum.rs:4:5 + --> $DIR/nested-enum.rs:6:5 | LL | union Wibble { field: u8 }, | ^^^^^ @@ -31,7 +29,6 @@ LL | union Wibble { field: u8 }, help: consider creating a new `union` definition instead of nesting | LL - union Wibble { field: u8 }, -LL + | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs index 3c0059ba3e3e..c9fb08506ddb 100644 --- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs @@ -2,5 +2,6 @@ // Tests that we do not erroneously emit an error about // missing main function when the mod starts with a `;` -; //~ ERROR expected item, found `;` +; +//~^ ERROR expected item, found `;` fn main() { } diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr index c0d85aa17d2a..002dc028cf55 100644 --- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr @@ -7,7 +7,6 @@ LL | ; help: remove this semicolon | LL - ; -LL + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs index 3fbac5fae232..a8a608c191a8 100644 --- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs @@ -2,4 +2,5 @@ // Tests that we still emit an error after an item. fn main() { } -; //~ ERROR expected item, found `;` +; +//~^ ERROR expected item, found `;` diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr index 8d4f23683863..aae5c1e1b22f 100644 --- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr @@ -8,7 +8,6 @@ LL | ; help: remove this semicolon | LL - ; -LL + | error: aborting due to 1 previous error From b5f94c61f72cc85151dbd9bb1081fde2ab78f806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 11 Jul 2024 22:03:08 +0000 Subject: [PATCH 235/361] Use more accurate span for `:` to `::` suggestion --- compiler/rustc_parse/src/errors.rs | 4 +++- compiler/rustc_parse/src/parser/path.rs | 2 ++ tests/ui/generics/single-colon-path-not-const-generics.stderr | 2 +- tests/ui/suggestions/type-ascription-instead-of-method.stderr | 2 +- tests/ui/suggestions/type-ascription-instead-of-path.stderr | 2 +- .../ui/suggestions/type-ascription-instead-of-variant.stderr | 2 +- tests/ui/type/ascription/issue-47666.stderr | 2 +- tests/ui/type/ascription/issue-54516.stderr | 2 +- tests/ui/type/ascription/issue-60933.stderr | 2 +- 9 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index d2a765247ad6..18a3153bcd43 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1562,9 +1562,11 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { #[diag(parse_path_single_colon)] pub(crate) struct PathSingleColon { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "::", style = "verbose")] pub span: Span, + #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] + pub suggestion: Span, + #[note(parse_type_ascription_removed)] pub type_ascription: Option<()>, } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 03c647dd5278..b9014dea7266 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -258,6 +258,7 @@ impl<'a> Parser<'a> { self.bump(); // bump past the colon self.dcx().emit_err(PathSingleColon { span: self.prev_token.span, + suggestion: self.prev_token.span.shrink_to_hi(), type_ascription: self .psess .unstable_features @@ -329,6 +330,7 @@ impl<'a> Parser<'a> { err.cancel(); err = self.dcx().create_err(PathSingleColon { span: self.token.span, + suggestion: self.prev_token.span.shrink_to_hi(), type_ascription: self .psess .unstable_features diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index 06203b5e6fe7..4e695b2dcd6d 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -10,7 +10,7 @@ LL | a: Vec, help: use a double colon instead | LL | a: Vec, - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr index 06f806b90163..0bef1c185db6 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr @@ -8,7 +8,7 @@ LL | let _ = Box:new("foo".to_string()); help: use a double colon instead | LL | let _ = Box::new("foo".to_string()); - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr index 9b09a60c1617..8c16acff7994 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr @@ -8,7 +8,7 @@ LL | std:io::stdin(); help: use a double colon instead | LL | std::io::stdin(); - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr index 0ecdc82b5412..f0b31722e40e 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -8,7 +8,7 @@ LL | let _ = Option:Some(""); help: use a double colon instead | LL | let _ = Option::Some(""); - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr index d76d591ec33f..fd825e86675d 100644 --- a/tests/ui/type/ascription/issue-47666.stderr +++ b/tests/ui/type/ascription/issue-47666.stderr @@ -8,7 +8,7 @@ LL | let _ = Option:Some(vec![0, 1]); help: use a double colon instead | LL | let _ = Option::Some(vec![0, 1]); - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr index bea2c0d85b3a..64fdc1fa24a6 100644 --- a/tests/ui/type/ascription/issue-54516.stderr +++ b/tests/ui/type/ascription/issue-54516.stderr @@ -8,7 +8,7 @@ LL | println!("{}", std::mem:size_of::>()); help: use a double colon instead | LL | println!("{}", std::mem::size_of::>()); - | ~~ + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr index a81238bd5400..c68394d0504a 100644 --- a/tests/ui/type/ascription/issue-60933.stderr +++ b/tests/ui/type/ascription/issue-60933.stderr @@ -8,7 +8,7 @@ LL | let _: usize = std::mem:size_of::(); help: use a double colon instead | LL | let _: usize = std::mem::size_of::(); - | ~~ + | + error: aborting due to 1 previous error From 377d14be88200d122f699aa989e4d1256f2173d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 11 Jul 2024 22:07:11 +0000 Subject: [PATCH 236/361] More accurate incorrect use of `await` suggestion --- compiler/rustc_parse/messages.ftl | 6 +- compiler/rustc_parse/src/errors.rs | 23 ++++-- .../rustc_parse/src/parser/diagnostics.rs | 18 ++--- .../incorrect-syntax-suggestions.stderr | 80 +++++++++++-------- tests/ui/parser/issues/issue-113203.stderr | 5 +- 5 files changed, 76 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index fd96d95bc2e5..c2201b1c41ec 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -323,10 +323,10 @@ parse_incorrect_semicolon = .suggestion = remove this semicolon .help = {$name} declarations are not followed by a semicolon -parse_incorrect_use_of_await = - incorrect use of `await` +parse_incorrect_use_of_await = incorrect use of `await` .parentheses_suggestion = `await` is not a method call, remove the parentheses - .postfix_suggestion = `await` is a postfix operation + +parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 18a3153bcd43..eee17a73acf3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -103,19 +103,26 @@ pub(crate) struct IncorrectUseOfAwait { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_incorrect_use_of_await_postfix_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct AwaitSuggestion { + #[suggestion_part(code = "")] + pub removal: Span, + #[suggestion_part(code = ".await{question_mark}")] + pub dot_await: Span, + pub question_mark: &'static str, +} + #[derive(Diagnostic)] #[diag(parse_incorrect_use_of_await)] pub(crate) struct IncorrectAwait { #[primary_span] pub span: Span, - #[suggestion( - parse_postfix_suggestion, - style = "verbose", - code = "{expr}.await{question_mark}" - )] - pub sugg_span: (Span, Applicability), - pub expr: String, - pub question_mark: &'static str, + #[subdiagnostic] + pub suggestion: AwaitSuggestion, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 63e4d8a43523..39f1d4e89ec4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -3,8 +3,8 @@ use super::{ BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType, }; use crate::errors::{ - AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, - BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, + BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, @@ -1959,18 +1959,14 @@ impl<'a> Parser<'a> { is_question: bool, ) -> (Span, ErrorGuaranteed) { let span = lo.to(hi); - let applicability = match expr.kind { - ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` - _ => Applicability::MachineApplicable, - }; - let guar = self.dcx().emit_err(IncorrectAwait { span, - sugg_span: (span, applicability), - expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)), - question_mark: if is_question { "?" } else { "" }, + suggestion: AwaitSuggestion { + removal: lo.until(expr.span), + dot_await: expr.span.shrink_to_hi(), + question_mark: if is_question { "?" } else { "" }, + }, }); - (span, guar) } diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index ac1bc693fab9..0ccde7d8709f 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -6,8 +6,9 @@ LL | let _ = await bar(); | help: `await` is a postfix operation | -LL | let _ = bar().await; - | ~~~~~~~~~~~ +LL - let _ = await bar(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:12:13 @@ -17,8 +18,9 @@ LL | let _ = await? bar(); | help: `await` is a postfix operation | -LL | let _ = bar().await?; - | ~~~~~~~~~~~~ +LL - let _ = await? bar(); +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:16:13 @@ -28,8 +30,9 @@ LL | let _ = await bar()?; | help: `await` is a postfix operation | -LL | let _ = bar()?.await; - | ~~~~~~~~~~~~ +LL - let _ = await bar()?; +LL + let _ = bar()?.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:20:13 @@ -39,8 +42,9 @@ LL | let _ = await { bar() }; | help: `await` is a postfix operation | -LL | let _ = { bar() }.await; - | ~~~~~~~~~~~~~~~ +LL - let _ = await { bar() }; +LL + let _ = { bar() }.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:24:13 @@ -50,8 +54,9 @@ LL | let _ = await(bar()); | help: `await` is a postfix operation | -LL | let _ = (bar()).await; - | ~~~~~~~~~~~~~ +LL - let _ = await(bar()); +LL + let _ = (bar()).await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:28:13 @@ -61,8 +66,9 @@ LL | let _ = await { bar() }?; | help: `await` is a postfix operation | -LL | let _ = { bar() }.await?; - | ~~~~~~~~~~~~~~~ +LL - let _ = await { bar() }?; +LL + let _ = { bar() }.await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:32:14 @@ -72,8 +78,9 @@ LL | let _ = (await bar())?; | help: `await` is a postfix operation | -LL | let _ = (bar().await)?; - | ~~~~~~~~~~~ +LL - let _ = (await bar())?; +LL + let _ = (bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:36:24 @@ -107,8 +114,9 @@ LL | let _ = await bar(); | help: `await` is a postfix operation | -LL | let _ = bar().await; - | ~~~~~~~~~~~ +LL - let _ = await bar(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:56:13 @@ -118,8 +126,9 @@ LL | let _ = await? bar(); | help: `await` is a postfix operation | -LL | let _ = bar().await?; - | ~~~~~~~~~~~~ +LL - let _ = await? bar(); +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:60:13 @@ -129,8 +138,9 @@ LL | let _ = await bar()?; | help: `await` is a postfix operation | -LL | let _ = bar()?.await; - | ~~~~~~~~~~~~ +LL - let _ = await bar()?; +LL + let _ = bar()?.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:64:14 @@ -140,8 +150,9 @@ LL | let _ = (await bar())?; | help: `await` is a postfix operation | -LL | let _ = (bar().await)?; - | ~~~~~~~~~~~ +LL - let _ = (await bar())?; +LL + let _ = (bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:68:24 @@ -175,8 +186,9 @@ LL | let _ = await!(bar()); | help: `await` is a postfix operation | -LL | let _ = bar().await; - | ~~~~~~~~~~~ +LL - let _ = await!(bar()); +LL + let _ = bar().await); + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:105:13 @@ -186,8 +198,9 @@ LL | let _ = await!(bar())?; | help: `await` is a postfix operation | -LL | let _ = bar().await?; - | ~~~~~~~~~~~ +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:110:17 @@ -197,8 +210,9 @@ LL | let _ = await!(bar())?; | help: `await` is a postfix operation | -LL | let _ = bar().await?; - | ~~~~~~~~~~~ +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:117:17 @@ -208,8 +222,9 @@ LL | let _ = await!(bar())?; | help: `await` is a postfix operation | -LL | let _ = bar().await?; - | ~~~~~~~~~~~ +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: expected expression, found `=>` --> $DIR/incorrect-syntax-suggestions.rs:124:25 @@ -227,8 +242,9 @@ LL | match await { await => () } | help: `await` is a postfix operation | -LL | match { await => () }.await - | ~~~~~~~~~~~~~~~~~~~~~ +LL - match await { await => () } +LL + match { await => () }.await + | error: expected one of `.`, `?`, `{`, or an operator, found `}` --> $DIR/incorrect-syntax-suggestions.rs:127:1 diff --git a/tests/ui/parser/issues/issue-113203.stderr b/tests/ui/parser/issues/issue-113203.stderr index f9c8ad912805..1ef20ddf7261 100644 --- a/tests/ui/parser/issues/issue-113203.stderr +++ b/tests/ui/parser/issues/issue-113203.stderr @@ -6,8 +6,9 @@ LL | await {}() | help: `await` is a postfix operation | -LL | {}.await() - | ~~~~~~~~ +LL - await {}() +LL + {}.await() + | error: aborting due to 1 previous error From b6f518877f910aae9e4a22f2df4fe55ea838cd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Jul 2024 03:04:06 +0000 Subject: [PATCH 237/361] fix unused binding --- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 39f1d4e89ec4..0da7fefe6ed2 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1610,7 +1610,7 @@ impl<'a> Parser<'a> { } self.bump(); // `+` - let bounds = self.parse_generic_bounds()?; + let _bounds = self.parse_generic_bounds()?; let sum_span = ty.span.to(self.prev_token.span); let sub = match &ty.kind { From 71f16bdb32feb33762e5245efa37edac2bde724b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Jul 2024 03:22:32 +0000 Subject: [PATCH 238/361] Make `;` suggestions inline --- compiler/rustc_parse/src/errors.rs | 6 +- .../let-else-missing-semicolon.stderr | 14 +--- tests/ui/parser/issues/issue-103425.stderr | 21 +----- .../ui/parser/issues/issue-118530-ice.stderr | 7 +- tests/ui/parser/issues/issue-3036.stderr | 7 +- .../issue-87197-missing-semicolon.stderr | 21 +----- tests/ui/parser/macros-no-semicolon.stderr | 14 +--- tests/ui/parser/raw/raw-str-unbalanced.stderr | 7 +- .../recover-missing-semi-before-item.stderr | 70 +++---------------- .../recover/recover-missing-semi.stderr | 14 +--- tests/ui/suggestions/missing-semicolon.stderr | 14 +--- ...st-semicolon-for-fn-in-extern-block.stderr | 7 +- 12 files changed, 32 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index eee17a73acf3..092a2a10ab7b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1215,14 +1215,14 @@ pub(crate) enum ExpectedSemiSugg { parse_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable", - style = "verbose" + style = "short" )] ChangeToSemi(#[primary_span] Span), #[suggestion( parse_sugg_add_semi, - style = "verbose", code = ";", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "short" )] AddSemi(#[primary_span] Span), } diff --git a/tests/ui/let-else/let-else-missing-semicolon.stderr b/tests/ui/let-else/let-else-missing-semicolon.stderr index 778a0e244f81..99029ff33fe0 100644 --- a/tests/ui/let-else/let-else-missing-semicolon.stderr +++ b/tests/ui/let-else/let-else-missing-semicolon.stderr @@ -2,27 +2,17 @@ error: expected `;`, found keyword `let` --> $DIR/let-else-missing-semicolon.rs:4:6 | LL | } - | ^ + | ^ help: add `;` here LL | let _ = ""; | --- unexpected token - | -help: add `;` here - | -LL | }; - | + error: expected `;`, found `}` --> $DIR/let-else-missing-semicolon.rs:8:6 | LL | } - | ^ + | ^ help: add `;` here LL | } | - unexpected token - | -help: add `;` here - | -LL | }; - | + error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-103425.stderr b/tests/ui/parser/issues/issue-103425.stderr index e7e1b7106b0b..0efe3e3ca711 100644 --- a/tests/ui/parser/issues/issue-103425.stderr +++ b/tests/ui/parser/issues/issue-103425.stderr @@ -2,43 +2,28 @@ error: expected `;`, found `5.0` --> $DIR/issue-103425.rs:2:6 | LL | 3 - | ^ + | ^ help: add `;` here LL | LL | 5.0 | --- unexpected token - | -help: add `;` here - | -LL | 3; - | + error: expected `;`, found `3_i8` --> $DIR/issue-103425.rs:8:10 | LL | 2_u32 - | ^ + | ^ help: add `;` here LL | LL | 3_i8 | ---- unexpected token - | -help: add `;` here - | -LL | 2_u32; - | + error: expected `;`, found `5.0` --> $DIR/issue-103425.rs:10:9 | LL | 3_i8 - | ^ + | ^ help: add `;` here LL | LL | 5.0 | --- unexpected token - | -help: add `;` here - | -LL | 3_i8; - | + error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index a8a2327d0cee..3519fb8777f4 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -30,11 +30,8 @@ LL | #[feature] | ---------- only `;` terminated statements or tail expressions are allowed after this attribute LL | attr::fn bar() -> String { | ^--- unexpected token - | -help: add `;` here - | -LL | attr::fn; bar() -> String { - | + + | | + | help: add `;` here error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 diff --git a/tests/ui/parser/issues/issue-3036.stderr b/tests/ui/parser/issues/issue-3036.stderr index 62a9c1d9752a..3dd89b7e828d 100644 --- a/tests/ui/parser/issues/issue-3036.stderr +++ b/tests/ui/parser/issues/issue-3036.stderr @@ -2,14 +2,9 @@ error: expected `;`, found `}` --> $DIR/issue-3036.rs:6:15 | LL | let _x = 3 - | ^ + | ^ help: add `;` here LL | } | - unexpected token - | -help: add `;` here - | -LL | let _x = 3; - | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr b/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr index 874e7b071630..57772de1e7a4 100644 --- a/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr +++ b/tests/ui/parser/issues/issue-87197-missing-semicolon.stderr @@ -2,40 +2,25 @@ error: expected `;`, found `println` --> $DIR/issue-87197-missing-semicolon.rs:6:16 | LL | let x = 100 - | ^ + | ^ help: add `;` here LL | println!("{}", x) | ------- unexpected token - | -help: add `;` here - | -LL | let x = 100; - | + error: expected `;`, found keyword `let` --> $DIR/issue-87197-missing-semicolon.rs:7:22 | LL | println!("{}", x) - | ^ + | ^ help: add `;` here LL | let y = 200 | --- unexpected token - | -help: add `;` here - | -LL | println!("{}", x); - | + error: expected `;`, found `println` --> $DIR/issue-87197-missing-semicolon.rs:8:16 | LL | let y = 200 - | ^ + | ^ help: add `;` here LL | println!("{}", y); | ------- unexpected token - | -help: add `;` here - | -LL | let y = 200; - | + error: aborting due to 3 previous errors diff --git a/tests/ui/parser/macros-no-semicolon.stderr b/tests/ui/parser/macros-no-semicolon.stderr index 4cf01e457d70..f310662dbb0e 100644 --- a/tests/ui/parser/macros-no-semicolon.stderr +++ b/tests/ui/parser/macros-no-semicolon.stderr @@ -2,27 +2,17 @@ error: expected `;`, found `assert_eq` --> $DIR/macros-no-semicolon.rs:2:21 | LL | assert_eq!(1, 2) - | ^ + | ^ help: add `;` here LL | assert_eq!(3, 4) | --------- unexpected token - | -help: add `;` here - | -LL | assert_eq!(1, 2); - | + error: expected `;`, found `println` --> $DIR/macros-no-semicolon.rs:3:21 | LL | assert_eq!(3, 4) - | ^ + | ^ help: add `;` here LL | println!("hello"); | ------- unexpected token - | -help: add `;` here - | -LL | assert_eq!(3, 4); - | + error: aborting due to 2 previous errors diff --git a/tests/ui/parser/raw/raw-str-unbalanced.stderr b/tests/ui/parser/raw/raw-str-unbalanced.stderr index d3a9c342c032..eac8c06c1df5 100644 --- a/tests/ui/parser/raw/raw-str-unbalanced.stderr +++ b/tests/ui/parser/raw/raw-str-unbalanced.stderr @@ -19,15 +19,10 @@ error: expected `;`, found `#` --> $DIR/raw-str-unbalanced.rs:10:28 | LL | const A: &'static str = r"" - | ^ + | ^ help: add `;` here ... LL | #[test] | - unexpected token - | -help: add `;` here - | -LL | const A: &'static str = r""; - | + error: too many `#` when terminating raw string --> $DIR/raw-str-unbalanced.rs:16:28 diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr index 8a87d44c9591..61c43f2f1899 100644 --- a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr +++ b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr @@ -2,132 +2,82 @@ error: expected `;`, found keyword `struct` --> $DIR/recover-missing-semi-before-item.rs:6:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | struct Foo; | ------ unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found `union` --> $DIR/recover-missing-semi-before-item.rs:11:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | union Foo { | ----- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `enum` --> $DIR/recover-missing-semi-before-item.rs:18:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | enum Foo { | ---- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `fn` --> $DIR/recover-missing-semi-before-item.rs:25:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | fn foo() {} | -- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `extern` --> $DIR/recover-missing-semi-before-item.rs:30:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | extern fn foo() {} | ------ unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `impl` --> $DIR/recover-missing-semi-before-item.rs:36:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | impl Foo {} | ---- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `pub` --> $DIR/recover-missing-semi-before-item.rs:41:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | pub use bar::Bar; | --- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `mod` --> $DIR/recover-missing-semi-before-item.rs:46:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | mod foo {} | --- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `type` --> $DIR/recover-missing-semi-before-item.rs:51:16 | LL | let foo = 3 - | ^ + | ^ help: add `;` here LL | type Foo = usize; | ---- unexpected token - | -help: add `;` here - | -LL | let foo = 3; - | + error: expected `;`, found keyword `fn` --> $DIR/recover-missing-semi-before-item.rs:59:19 | LL | const X: i32 = 123 - | ^ + | ^ help: add `;` here LL | LL | fn main() {} | -- unexpected token - | -help: add `;` here - | -LL | const X: i32 = 123; - | + error: aborting due to 10 previous errors diff --git a/tests/ui/parser/recover/recover-missing-semi.stderr b/tests/ui/parser/recover/recover-missing-semi.stderr index 3e8cb37160ec..ba4798285387 100644 --- a/tests/ui/parser/recover/recover-missing-semi.stderr +++ b/tests/ui/parser/recover/recover-missing-semi.stderr @@ -2,29 +2,19 @@ error: expected `;`, found keyword `let` --> $DIR/recover-missing-semi.rs:2:22 | LL | let _: usize = () - | ^ + | ^ help: add `;` here ... LL | let _ = 3; | --- unexpected token - | -help: add `;` here - | -LL | let _: usize = (); - | + error: expected `;`, found keyword `return` --> $DIR/recover-missing-semi.rs:9:22 | LL | let _: usize = () - | ^ + | ^ help: add `;` here ... LL | return 3; | ------ unexpected token - | -help: add `;` here - | -LL | let _: usize = (); - | + error[E0308]: mismatched types --> $DIR/recover-missing-semi.rs:2:20 diff --git a/tests/ui/suggestions/missing-semicolon.stderr b/tests/ui/suggestions/missing-semicolon.stderr index 86404e4511c2..54a64f664b50 100644 --- a/tests/ui/suggestions/missing-semicolon.stderr +++ b/tests/ui/suggestions/missing-semicolon.stderr @@ -2,27 +2,17 @@ error: expected `;`, found `}` --> $DIR/missing-semicolon.rs:6:7 | LL | () - | ^ + | ^ help: add `;` here LL | } | - unexpected token - | -help: add `;` here - | -LL | (); - | + error: expected `;`, found `}` --> $DIR/missing-semicolon.rs:32:7 | LL | () - | ^ + | ^ help: add `;` here LL | } | - unexpected token - | -help: add `;` here - | -LL | (); - | + error[E0618]: expected function, found `{integer}` --> $DIR/missing-semicolon.rs:5:13 diff --git a/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr b/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr index 3d6983ec8f98..12da91c20b3c 100644 --- a/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr +++ b/tests/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr @@ -2,14 +2,9 @@ error: expected `;`, found `}` --> $DIR/suggest-semicolon-for-fn-in-extern-block.rs:6:11 | LL | fn foo() - | ^ + | ^ help: add `;` here LL | } | - unexpected token - | -help: add `;` here - | -LL | fn foo(); - | + error: aborting due to 1 previous error From dad95578b0f000807f23fe2d37ca37ea8bd8522c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 12 Jul 2024 09:22:16 +1000 Subject: [PATCH 239/361] Add unit tests for `Parser::look_ahead`. It's currently buggy, so some of the test results are surprising, as described in the `FIXME` comments. The bugs will be fixed in subsequent commits. --- compiler/rustc_parse/src/parser/tests.rs | 116 +++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 42392ad2163d..538ec6b8cfd4 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1376,6 +1376,122 @@ fn ttdelim_span() { }); } +// Uses a macro rather than a function so that failure messages mention the +// correct line in the test function. +macro_rules! look { + ($p:ident, $dist:literal, $kind:expr) => { + $p.look_ahead($dist, |tok| assert_eq!($kind, tok.kind)); + }; +} + +#[test] +fn look_ahead() { + create_default_session_globals_then(|| { + let sym_f = Symbol::intern("f"); + let sym_x = Symbol::intern("x"); + #[allow(non_snake_case)] + let sym_S = Symbol::intern("S"); + let raw_no = IdentIsRaw::No; + + let psess = psess(); + let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); + + // Current position is the `fn`. + look!(p, 0, token::Ident(kw::Fn, raw_no)); + look!(p, 1, token::Ident(sym_f, raw_no)); + look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look!(p, 3, token::Ident(sym_x, raw_no)); + look!(p, 4, token::Colon); + look!(p, 5, token::Ident(sym::u32, raw_no)); + look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 7, token::OpenDelim(Delimiter::Brace)); + look!(p, 8, token::Ident(sym_x, raw_no)); + look!(p, 9, token::CloseDelim(Delimiter::Brace)); + look!(p, 10, token::Ident(kw::Struct, raw_no)); + look!(p, 11, token::Ident(sym_S, raw_no)); + look!(p, 12, token::Semi); + // Any lookahead past the end of the token stream returns `Eof`. + look!(p, 13, token::Eof); + look!(p, 14, token::Eof); + look!(p, 15, token::Eof); + look!(p, 100, token::Eof); + + // Move forward to the first `x`. + for _ in 0..3 { + p.bump(); + } + look!(p, 0, token::Ident(sym_x, raw_no)); + look!(p, 1, token::Colon); + look!(p, 2, token::Ident(sym::u32, raw_no)); + look!(p, 3, token::CloseDelim(Delimiter::Parenthesis)); + // FIXME(nnethercote) If we lookahead any distance past a close delim + // we currently return that close delim. + look!(p, 4, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 5, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 100, token::CloseDelim(Delimiter::Parenthesis)); + + // Move forward to the `;`. + for _ in 0..9 { + p.bump(); + } + look!(p, 0, token::Semi); + // Any lookahead past the end of the token stream returns `Eof`. + look!(p, 1, token::Eof); + look!(p, 100, token::Eof); + + // Move one past the `;`, i.e. past the end of the token stream. + p.bump(); + look!(p, 0, token::Eof); + look!(p, 1, token::Eof); + look!(p, 100, token::Eof); + + // Bumping after Eof is idempotent. + p.bump(); + look!(p, 0, token::Eof); + look!(p, 1, token::Eof); + look!(p, 100, token::Eof); + }); +} + +/// FIXME(nnethercote) Currently there is some buggy behaviour when using +/// `look_ahead` not within the outermost token stream, as this test shows. +#[test] +fn look_ahead_non_outermost_stream() { + create_default_session_globals_then(|| { + let sym_f = Symbol::intern("f"); + #[allow(non_snake_case)] + let sym_S = Symbol::intern("S"); + let raw_no = IdentIsRaw::No; + + let psess = psess(); + let mut p = string_to_parser(&psess, "mod m { fn f(x: u32) { x } struct S; }".to_string()); + + // Move forward to the `fn`, which is not within the outermost token + // stream (because it's inside the `mod { ... }`). + for _ in 0..3 { + p.bump(); + } + look!(p, 0, token::Ident(kw::Fn, raw_no)); + look!(p, 1, token::Ident(sym_f, raw_no)); + look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); + // FIXME(nnethercote) The current code incorrectly skips the `x: u32)` + // to the next token tree. + look!(p, 3, token::OpenDelim(Delimiter::Brace)); + // FIXME(nnethercote) The current code incorrectly skips the `x }` + // to the next token tree. + look!(p, 4, token::Ident(kw::Struct, raw_no)); + look!(p, 5, token::Ident(sym_S, raw_no)); + look!(p, 6, token::Semi); + // FIXME(nnethercote) If we lookahead any distance past a close delim + // we currently return that close delim. + look!(p, 7, token::CloseDelim(Delimiter::Brace)); + look!(p, 8, token::CloseDelim(Delimiter::Brace)); + look!(p, 9, token::CloseDelim(Delimiter::Brace)); + look!(p, 100, token::CloseDelim(Delimiter::Brace)); + }); +} + // This tests that when parsing a string (rather than a file) we don't try // and read in a file for a module declaration and just parse a stub. // See `recurse_into_file_modules` in the parser. From ebe1305b1e0bb32913b309ce65bd97106532ad6a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 12 Jul 2024 12:56:58 +1000 Subject: [PATCH 240/361] Remove the bogus special case from `Parser::look_ahead`. The general case at the bottom of `look_ahead` is slow, because it clones the token cursor. Above it there is a special case for performance that is hit most of the time and avoids the cloning. Unfortunately, its behaviour differs from the general case in two ways. - When within a pair of delimiters, if you look any distance past the closing delimiter you get the closing delimiter instead of what comes after the closing delimiter. - It uses `tree_cursor.look_ahead(dist - 1)` which totally confuses tokens with token trees. This means that only the first token in a token tree will be seen. E.g. in a sequence like `{ a }` the `a` and `}` will be skipped over. Bad! It's likely that these differences weren't noticed before now because the use of `look_ahead` in the parser is limited to small distances and relatively few contexts. Removing the special case causes slowdowns up of to 2% on a range of benchmarks. The next commit will add a new, correct special case to regain that lost performance. --- compiler/rustc_parse/src/parser/mod.rs | 37 +------------------ compiler/rustc_parse/src/parser/tests.rs | 47 +++++++++++++----------- 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 45ca267fe5d1..f906a2ecab7a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1118,41 +1118,8 @@ impl<'a> Parser<'a> { return looker(&self.token); } - if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last() - && delim != Delimiter::Invisible - { - // We are not in the outermost token stream, and the token stream - // we are in has non-skipped delimiters. Look for skipped - // delimiters in the lookahead range. - let tree_cursor = &self.token_cursor.tree_cursor; - let all_normal = (0..dist).all(|i| { - let token = tree_cursor.look_ahead(i); - !matches!(token, Some(TokenTree::Delimited(.., Delimiter::Invisible, _))) - }); - if all_normal { - // There were no skipped delimiters. Do lookahead by plain indexing. - return match tree_cursor.look_ahead(dist - 1) { - Some(tree) => { - // Indexing stayed within the current token stream. - match tree { - TokenTree::Token(token, _) => looker(token), - TokenTree::Delimited(dspan, _, delim, _) => { - looker(&Token::new(token::OpenDelim(*delim), dspan.open)) - } - } - } - None => { - // Indexing went past the end of the current token - // stream. Use the close delimiter, no matter how far - // ahead `dist` went. - looker(&Token::new(token::CloseDelim(delim), span.close)) - } - }; - } - } - - // We are in a more complex case. Just clone the token cursor and use - // `next`, skipping delimiters as necessary. Slow but simple. + // Just clone the token cursor and use `next`, skipping delimiters as + // necessary. Slow but simple. let mut cursor = self.token_cursor.clone(); let mut i = 0; let mut token = Token::dummy(); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 538ec6b8cfd4..5b2d119e42b4 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1424,12 +1424,15 @@ fn look_ahead() { look!(p, 1, token::Colon); look!(p, 2, token::Ident(sym::u32, raw_no)); look!(p, 3, token::CloseDelim(Delimiter::Parenthesis)); - // FIXME(nnethercote) If we lookahead any distance past a close delim - // we currently return that close delim. - look!(p, 4, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 5, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 100, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 4, token::OpenDelim(Delimiter::Brace)); + look!(p, 5, token::Ident(sym_x, raw_no)); + look!(p, 6, token::CloseDelim(Delimiter::Brace)); + look!(p, 7, token::Ident(kw::Struct, raw_no)); + look!(p, 8, token::Ident(sym_S, raw_no)); + look!(p, 9, token::Semi); + look!(p, 10, token::Eof); + look!(p, 11, token::Eof); + look!(p, 100, token::Eof); // Move forward to the `;`. for _ in 0..9 { @@ -1454,12 +1457,13 @@ fn look_ahead() { }); } -/// FIXME(nnethercote) Currently there is some buggy behaviour when using -/// `look_ahead` not within the outermost token stream, as this test shows. +/// There used to be some buggy behaviour when using `look_ahead` not within +/// the outermost token stream, which this test covers. #[test] fn look_ahead_non_outermost_stream() { create_default_session_globals_then(|| { let sym_f = Symbol::intern("f"); + let sym_x = Symbol::intern("x"); #[allow(non_snake_case)] let sym_S = Symbol::intern("S"); let raw_no = IdentIsRaw::No; @@ -1475,20 +1479,21 @@ fn look_ahead_non_outermost_stream() { look!(p, 0, token::Ident(kw::Fn, raw_no)); look!(p, 1, token::Ident(sym_f, raw_no)); look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); - // FIXME(nnethercote) The current code incorrectly skips the `x: u32)` - // to the next token tree. - look!(p, 3, token::OpenDelim(Delimiter::Brace)); - // FIXME(nnethercote) The current code incorrectly skips the `x }` - // to the next token tree. - look!(p, 4, token::Ident(kw::Struct, raw_no)); - look!(p, 5, token::Ident(sym_S, raw_no)); - look!(p, 6, token::Semi); - // FIXME(nnethercote) If we lookahead any distance past a close delim - // we currently return that close delim. - look!(p, 7, token::CloseDelim(Delimiter::Brace)); - look!(p, 8, token::CloseDelim(Delimiter::Brace)); + look!(p, 3, token::Ident(sym_x, raw_no)); + look!(p, 4, token::Colon); + look!(p, 5, token::Ident(sym::u32, raw_no)); + look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look!(p, 7, token::OpenDelim(Delimiter::Brace)); + look!(p, 8, token::Ident(sym_x, raw_no)); look!(p, 9, token::CloseDelim(Delimiter::Brace)); - look!(p, 100, token::CloseDelim(Delimiter::Brace)); + look!(p, 10, token::Ident(kw::Struct, raw_no)); + look!(p, 11, token::Ident(sym_S, raw_no)); + look!(p, 12, token::Semi); + look!(p, 13, token::CloseDelim(Delimiter::Brace)); + // Any lookahead past the end of the token stream returns `Eof`. + look!(p, 14, token::Eof); + look!(p, 15, token::Eof); + look!(p, 100, token::Eof); }); } From 100f3fd133d928e9c86cff202fa32e5e4d0ce6c7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 12 Jul 2024 13:20:24 +1000 Subject: [PATCH 241/361] Add a new special case to `Parser::look_ahead`. This new special case is simpler than the old special case because it only is used when `dist == 1`. But that's still enough to cover ~98% of cases. This results in equivalent performance to the old special case, and identical behaviour as the general case. --- compiler/rustc_parse/src/parser/mod.rs | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f906a2ecab7a..ef9b3aabc61c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1118,6 +1118,35 @@ impl<'a> Parser<'a> { return looker(&self.token); } + // Typically around 98% of the `dist > 0` cases have `dist == 1`, so we + // have a fast special case for that. + if dist == 1 { + // The index is zero because the tree cursor's index always points + // to the next token to be gotten. + match self.token_cursor.tree_cursor.look_ahead(0) { + Some(tree) => { + // Indexing stayed within the current token tree. + return match tree { + TokenTree::Token(token, _) => looker(token), + TokenTree::Delimited(dspan, _, delim, _) => { + looker(&Token::new(token::OpenDelim(*delim), dspan.open)) + } + }; + } + None => { + // The tree cursor lookahead went (one) past the end of the + // current token tree. Try to return a close delimiter. + if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last() + && delim != Delimiter::Invisible + { + // We are not in the outermost token stream, so we have + // delimiters. Also, those delimiters are not skipped. + return looker(&Token::new(token::CloseDelim(delim), span.close)); + } + } + } + } + // Just clone the token cursor and use `next`, skipping delimiters as // necessary. Slow but simple. let mut cursor = self.token_cursor.clone(); From 7f1518bddd76ad8e3a743278fd983c35d11b2411 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 11 Jul 2024 20:12:43 -0700 Subject: [PATCH 242/361] Add instability attribute on private const_strlen function A `rustc_const_stable` attribute by itself has nonintuitive purpose when placed in a public module. Separately, it would probably be okay to rename `const_strlen` to just `strlen` to make it more clear this is our general-purpose implementation of strlen now, not something specifically for const (avoiding confusion like in PR 127444). --- library/core/src/ffi/c_str.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index f845dfc1fc41..dc2a5803a1b2 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -740,6 +740,7 @@ impl AsRef for CStr { /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be /// located within `isize::MAX` from `ptr`. #[inline] +#[unstable(feature = "cstr_internals", issue = "none")] #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] #[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn const_strlen(ptr: *const c_char) -> usize { From abeb7203e4c979b2446bf0cca0155427f0c46c18 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:36:45 +0000 Subject: [PATCH 243/361] Add regression test for issue 127545 --- .../transforming-option-ref-issue-127545.rs | 8 ++++ ...ransforming-option-ref-issue-127545.stderr | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index 5ba58e742758..9125ffeeb066 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -4,3 +4,11 @@ pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { arg //~ ERROR 5:5: 5:8: mismatched types [E0308] } + +pub fn bar(arg: Option<&Vec>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308] +} + +pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index b7c7202113a1..2d4f26c388db 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -14,5 +14,45 @@ LL | arg.map(|v| &**v) | ++++++++++++++ error: aborting due to 1 previous error + --> $DIR/transforming-option-ref-issue-127545.rs:9:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:9:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:13:19 + | +LL | arg.unwrap_or(v) + | --------- ^ expected `&Vec`, found `&[i32]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&'a [i32]` +help: the return type of this call is `&'a [i32]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:13:5 + | +LL | arg.unwrap_or(v) + | ^^^^^^^^^^^^^^-^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From 5e1cabe98271fc79cd8ebf8e9722df781cad7aa8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 12 Jul 2024 08:43:28 +0000 Subject: [PATCH 244/361] Add suggestion to use Option::map_or over erroneous Option::unwrap_or --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 11 ++++ .../src/fn_ctxt/suggestions.rs | 65 +++++++++++++++++++ ...ransforming-option-ref-issue-127545.stderr | 10 ++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ab0f356ce91f..6fdf616f50e0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -948,6 +948,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, ); + self.suggest_deref_unwrap_or( + &mut err, + error_span, + callee_ty, + call_ident, + expected_ty, + provided_ty, + provided_args[*provided_idx], + is_method, + ); + // Call out where the function is defined self.label_fn_like( &mut err, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5975c52ca46e..15a1a18daa70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1429,6 +1429,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } + // Suggest to change `Option<&Vec>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`. + #[instrument(level = "trace", skip(self, err, provided_expr))] + pub(crate) fn suggest_deref_unwrap_or( + &self, + err: &mut Diag<'_>, + error_span: Span, + callee_ty: Option>, + call_ident: Option, + expected_ty: Ty<'tcx>, + provided_ty: Ty<'tcx>, + provided_expr: &Expr<'tcx>, + is_method: bool, + ) { + if !is_method { + return; + } + let Some(callee_ty) = callee_ty else { + return; + }; + let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else { + return; + }; + if !self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + return; + } + + if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { + return; + } + + let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else { + return; + }; + + // NOTE: Can we reuse `suggest_deref_or_ref`? + + // Create an dummy type `&[_]` so that both &[] and `&Vec` can coerce to it. + let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind() + && let ty::Infer(_) = elem_ty.kind() + && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0) + { + let slice = Ty::new_slice(self.tcx, *elem_ty); + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice) + } else { + provided_ty + }; + + if !self.can_coerce(expected_ty, dummy_ty) { + return; + } + let (provided_snip, applicability) = + match self.tcx.sess.source_map().span_to_snippet(provided_expr.span) { + Ok(snip) => (snip, Applicability::MachineApplicable), + Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), + }; + let sugg = &format!("map_or({provided_snip}, |v| v)"); + err.span_suggestion_verbose( + error_span, + "use `Option::map_or` to deref inner value of `Option`", + sugg, + applicability, + ); + return; + } + /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 2d4f26c388db..90a7cfdb4496 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -13,7 +13,7 @@ help: try using `.map(|v| &**v)` to convert `Option<&Vec>` to `Option<&[i32 LL | arg.map(|v| &**v) | ++++++++++++++ -error: aborting due to 1 previous error +error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:9:19 | LL | arg.unwrap_or(&[]) @@ -32,6 +32,10 @@ LL | arg.unwrap_or(&[]) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 @@ -52,6 +56,10 @@ LL | arg.unwrap_or(v) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(v, |v| v) + | ~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors From 843f5dd93b3edc65034eb8b9e16673c2bf8e28f2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 19:49:51 -0400 Subject: [PATCH 245/361] Add rustdoc support for use<> in (local) RPITs --- compiler/rustc_hir/src/hir.rs | 7 +++++++ src/librustdoc/clean/mod.rs | 5 +++-- src/librustdoc/clean/simplify.rs | 2 +- src/librustdoc/clean/types.rs | 2 ++ src/librustdoc/html/format.rs | 14 ++++++++++++++ tests/rustdoc/impl-trait-precise-capturing.rs | 14 ++++++++++++++ 6 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc/impl-trait-precise-capturing.rs diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d57fad6ba4c2..4561f9d9b49d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2708,6 +2708,13 @@ impl PreciseCapturingArg<'_> { PreciseCapturingArg::Param(param) => param.hir_id, } } + + pub fn name(self) -> Symbol { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.ident.name, + PreciseCapturingArg::Param(param) => param.ident.name, + } + } } /// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index aa596897fc42..98ce268a7746 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -228,8 +228,9 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) } - // FIXME(precise_capturing): Implement rustdoc support - hir::GenericBound::Use(..) => return None, + hir::GenericBound::Use(args, ..) => { + GenericBound::Use(args.iter().map(|arg| arg.name()).collect()) + } }) } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 58eef36677b2..1b7d84add1f8 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -79,7 +79,7 @@ pub(crate) fn merge_bounds( !bounds.iter_mut().any(|b| { let trait_ref = match *b { clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, + clean::GenericBound::Outlives(..) | clean::GenericBound::Use(_) => return false, }; // If this QPath's trait `trait_did` is the same as, or a supertrait // of, the bound's trait `did` then we can keep going, otherwise diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fe01d17b08a8..a31adc9949a3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1244,6 +1244,8 @@ impl Eq for Attributes {} pub(crate) enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), Outlives(Lifetime), + /// `use<'a, T>` precise-capturing bound syntax + Use(Vec), } impl GenericBound { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4268fadd6c59..9b0b2571ec11 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -412,6 +412,20 @@ impl clean::GenericBound { })?; ty.print(cx).fmt(f) } + clean::GenericBound::Use(args) => { + if f.alternate() { + f.write_str("use<")?; + } else { + f.write_str("use<")?; + } + for (i, arg) in args.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + arg.fmt(f)?; + } + if f.alternate() { f.write_str(">") } else { f.write_str(">") } + } }) } } diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs new file mode 100644 index 000000000000..d1987a555c15 --- /dev/null +++ b/tests/rustdoc/impl-trait-precise-capturing.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] +#![feature(precise_capturing)] + +//@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>" +pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {} + +//@ has foo/fn.params.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>" +pub fn params<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + +//@ has foo/fn.none.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>" +pub fn none() -> impl Sized + use<> {} + +//@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized" +pub fn first() -> impl use<> + Sized {} From bd135e487f904e757f6c3d2ebcc2d216ac4d9aaf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 19:50:03 -0400 Subject: [PATCH 246/361] Add rustdoc-json support for use<> --- rustfmt.toml | 2 ++ src/librustdoc/json/conversions.rs | 1 + src/rustdoc-json-types/lib.rs | 4 +++- src/tools/jsondoclint/src/validator.rs | 1 + tests/rustdoc-json/impl-trait-precise-capturing.rs | 6 ++++++ 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-json/impl-trait-precise-capturing.rs diff --git a/rustfmt.toml b/rustfmt.toml index b15ffdca38a0..e060fd8fe8bf 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -22,6 +22,8 @@ ignore = [ "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui-fulldeps/", # Some are whitespace-sensitive (e.g. `// ~ERROR` comments). + # #[cfg(bootstrap)] so that t-release sees this when they search for it + "/tests/rustdoc-json/impl-trait-precise-capturing.rs", # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5111e363c522..4ab0df367085 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -542,6 +542,7 @@ impl FromWithTcx for GenericBound { } } Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), + Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()), } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 89115d4d7d66..6fd23b60c8ad 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 31; +pub const FORMAT_VERSION: u32 = 32; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -538,6 +538,8 @@ pub enum GenericBound { modifier: TraitBoundModifier, }, Outlives(String), + /// `use<'a, T>` precise-capturing bound syntax + Use(Vec), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index cd011dce7844..ea1e573384b8 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -298,6 +298,7 @@ impl<'a> Validator<'a> { generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } GenericBound::Outlives(_) => {} + GenericBound::Use(_) => {} } } diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs new file mode 100644 index 000000000000..bf98868d1453 --- /dev/null +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -0,0 +1,6 @@ +#![feature(precise_capturing)] + +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\" +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\" +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\" +pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} From 3f4b9dd463ca37c68dd6b27592e37a9287099406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 12 Jul 2024 11:27:46 +0200 Subject: [PATCH 247/361] Lower timeout of CI jobs to 4 hours The previous value, 10 hours, is unnecessarily long, since most of our jobs finish within 2.5 hours currently. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cf0e5fba537..8032154a7365 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: defaults: run: shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} - timeout-minutes: 600 + timeout-minutes: 240 env: CI_JOB_NAME: ${{ matrix.image }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse From cae9d480bfe930a678fe2744082fc6ef1d957f63 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 3 Jul 2024 13:41:36 +0100 Subject: [PATCH 248/361] Adjust tests for x86 "Rust" ABI changes --- tests/codegen/float/f128.rs | 11 +++++++++-- tests/codegen/float/f16.rs | 11 +++++++++-- tests/codegen/issues/issue-32031.rs | 10 ++++++++-- tests/codegen/union-abi.rs | 10 ++++++++-- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 32c5be1ec651..80b572fbbc9f 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,3 +1,8 @@ +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 + // Verify that our intrinsics generate the correct LLVM calls for f128 #![crate_type = "lib"] @@ -138,14 +143,16 @@ pub fn f128_as_f16(a: f128) -> f16 { a as f16 } -// CHECK-LABEL: float @f128_as_f32( +// other-LABEL: float @f128_as_f32( +// x86-LABEL: i32 @f128_as_f32( #[no_mangle] pub fn f128_as_f32(a: f128) -> f32 { // CHECK: fptrunc fp128 %{{.+}} to float a as f32 } -// CHECK-LABEL: double @f128_as_f64( +// other-LABEL: double @f128_as_f64( +// x86-LABEL: void @f128_as_f64( #[no_mangle] pub fn f128_as_f64(a: f128) -> f64 { // CHECK: fptrunc fp128 %{{.+}} to double diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index 96daac869c28..2910d7d3e928 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,3 +1,8 @@ +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 + // Verify that our intrinsics generate the correct LLVM calls for f16 #![crate_type = "lib"] @@ -140,14 +145,16 @@ pub fn f16_as_self(a: f16) -> f16 { a as f16 } -// CHECK-LABEL: float @f16_as_f32( +// other-LABEL: float @f16_as_f32( +// x86-LABEL: i32 @f16_as_f32( #[no_mangle] pub fn f16_as_f32(a: f16) -> f32 { // CHECK: fpext half %{{.+}} to float a as f32 } -// CHECK-LABEL: double @f16_as_f64( +// other-LABEL: double @f16_as_f64( +// x86-LABEL: void @f16_as_f64( #[no_mangle] pub fn f16_as_f64(a: f16) -> f64 { // CHECK: fpext half %{{.+}} to double diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs index 9693c414a67d..4d6895166f1c 100644 --- a/tests/codegen/issues/issue-32031.rs +++ b/tests/codegen/issues/issue-32031.rs @@ -1,11 +1,16 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 #![crate_type = "lib"] #[no_mangle] pub struct F32(f32); -// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b) +// other: define{{.*}}float @add_newtype_f32(float %a, float %b) +// x86: define{{.*}}i32 @add_newtype_f32(float %a, float %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f32(a: F32, b: F32) -> F32 { @@ -15,7 +20,8 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 { #[no_mangle] pub struct F64(f64); -// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b) +// other: define{{.*}}double @add_newtype_f64(double %a, double %b) +// x86: define{{.*}}void @add_newtype_f64(ptr{{.*}}sret([8 x i8]){{.*}}%_0, double %a, double %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f64(a: F64, b: F64) -> F64 { diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index 9e02fa9ff359..08015014456c 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -1,5 +1,9 @@ //@ ignore-emscripten vectors passed directly //@ compile-flags: -O -C no-prepopulate-passes +// 32-bit x86 returns `f32` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 // This test that using union forward the abi of the inner type, as // discussed in #54668 @@ -67,7 +71,8 @@ pub union UnionF32 { a: f32, } -// CHECK: define {{(dso_local )?}}float @test_UnionF32(float %_1) +// other: define {{(dso_local )?}}float @test_UnionF32(float %_1) +// x86: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) #[no_mangle] pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} @@ -78,7 +83,8 @@ pub union UnionF32F32 { b: f32, } -// CHECK: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +// other: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +// x86: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) #[no_mangle] pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} From 15f770b1436c2be227c9338040e53d64f211fe63 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 11 Jul 2024 23:13:12 +0200 Subject: [PATCH 249/361] enable fuzzing of `SearchGraph` fully move it into `rustc_type_ir` and make it independent of `Interner`. --- compiler/rustc_middle/src/traits/solve.rs | 4 - .../rustc_middle/src/traits/solve/cache.rs | 121 ---- compiler/rustc_middle/src/ty/context.rs | 29 +- .../src/solve/eval_ctxt/mod.rs | 14 +- .../src/solve/inspect/build.rs | 69 +- .../src/solve/search_graph.rs | 631 ++---------------- compiler/rustc_query_system/src/cache.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 30 +- compiler/rustc_type_ir/src/interner.rs | 48 +- compiler/rustc_type_ir/src/lib.rs | 1 + .../src/search_graph/global_cache.rs | 118 ++++ .../rustc_type_ir/src/search_graph/mod.rs | 605 +++++++++++++++++ .../src/search_graph/validate.rs | 75 +++ 13 files changed, 986 insertions(+), 761 deletions(-) delete mode 100644 compiler/rustc_middle/src/traits/solve/cache.rs create mode 100644 compiler/rustc_type_ir/src/search_graph/global_cache.rs create mode 100644 compiler/rustc_type_ir/src/search_graph/mod.rs create mode 100644 compiler/rustc_type_ir/src/search_graph/validate.rs diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 7bc4c60f1027..f659bf8125a0 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -8,10 +8,6 @@ use crate::ty::{ self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; -mod cache; - -pub use cache::EvaluationCache; - pub type Goal<'tcx, P> = ir::solve::Goal, P>; pub type QueryInput<'tcx, P> = ir::solve::QueryInput, P>; pub type QueryResult<'tcx> = ir::solve::QueryResult>; diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs deleted file mode 100644 index 72a8d4eb4050..000000000000 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ /dev/null @@ -1,121 +0,0 @@ -use super::{inspect, CanonicalInput, QueryResult}; -use crate::ty::TyCtxt; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lock; -use rustc_query_system::cache::WithDepNode; -use rustc_query_system::dep_graph::DepNodeIndex; -use rustc_session::Limit; -use rustc_type_ir::solve::CacheData; - -/// The trait solver cache used by `-Znext-solver`. -/// -/// FIXME(@lcnr): link to some official documentation of how -/// this works. -#[derive(Default)] -pub struct EvaluationCache<'tcx> { - map: Lock, CacheEntry<'tcx>>>, -} - -impl<'tcx> rustc_type_ir::inherent::EvaluationCache> for &'tcx EvaluationCache<'tcx> { - /// Insert a final result into the global cache. - fn insert( - &self, - tcx: TyCtxt<'tcx>, - key: CanonicalInput<'tcx>, - proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, - additional_depth: usize, - encountered_overflow: bool, - cycle_participants: FxHashSet>, - dep_node: DepNodeIndex, - result: QueryResult<'tcx>, - ) { - let mut map = self.map.borrow_mut(); - let entry = map.entry(key).or_default(); - let data = WithDepNode::new(dep_node, QueryData { result, proof_tree }); - entry.cycle_participants.extend(cycle_participants); - if encountered_overflow { - entry.with_overflow.insert(additional_depth, data); - } else { - entry.success = Some(Success { data, additional_depth }); - } - - if cfg!(debug_assertions) { - drop(map); - let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow }; - let actual = self.get(tcx, key, [], additional_depth); - if !actual.as_ref().is_some_and(|actual| expected == *actual) { - bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}"); - } - } - } - - /// Try to fetch a cached result, checking the recursion limit - /// and handling root goals of coinductive cycles. - /// - /// If this returns `Some` the cache result can be used. - fn get( - &self, - tcx: TyCtxt<'tcx>, - key: CanonicalInput<'tcx>, - stack_entries: impl IntoIterator>, - available_depth: usize, - ) -> Option>> { - let map = self.map.borrow(); - let entry = map.get(&key)?; - - for stack_entry in stack_entries { - if entry.cycle_participants.contains(&stack_entry) { - return None; - } - } - - if let Some(ref success) = entry.success { - if Limit(available_depth).value_within_limit(success.additional_depth) { - let QueryData { result, proof_tree } = success.data.get(tcx); - return Some(CacheData { - result, - proof_tree, - additional_depth: success.additional_depth, - encountered_overflow: false, - }); - } - } - - entry.with_overflow.get(&available_depth).map(|e| { - let QueryData { result, proof_tree } = e.get(tcx); - CacheData { - result, - proof_tree, - additional_depth: available_depth, - encountered_overflow: true, - } - }) - } -} - -struct Success<'tcx> { - data: WithDepNode>, - additional_depth: usize, -} - -#[derive(Clone, Copy)] -pub struct QueryData<'tcx> { - pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, -} - -/// The cache entry for a goal `CanonicalInput`. -/// -/// This contains results whose computation never hit the -/// recursion limit in `success`, and all results which hit -/// the recursion limit in `with_overflow`. -#[derive(Default)] -struct CacheEntry<'tcx> { - success: Option>, - /// We have to be careful when caching roots of cycles. - /// - /// See the doc comment of `StackEntry::cycle_participants` for more - /// details. - cycle_participants: FxHashSet>, - with_overflow: FxHashMap>>, -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aee42bfe3aac..9e24ea485b26 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -59,6 +59,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -75,7 +76,7 @@ use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::SolverMode; use rustc_type_ir::TyKind::*; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -164,12 +165,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Clause = Clause<'tcx>; type Clauses = ty::Clauses<'tcx>; - type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>; + type Tracked = WithDepNode; + fn mk_tracked( + self, + data: T, + dep_node: DepNodeIndex, + ) -> Self::Tracked { + WithDepNode::new(dep_node, data) + } + fn get_tracked(self, tracked: &Self::Tracked) -> T { + tracked.get(self) + } - fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> { + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R { match mode { - SolverMode::Normal => &self.new_solver_evaluation_cache, - SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache, + SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()), + SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()), } } @@ -1283,8 +1298,8 @@ pub struct GlobalCtxt<'tcx> { pub evaluation_cache: traits::EvaluationCache<'tcx>, /// Caches the results of goal evaluation in the new solver. - pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>, - pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>, + pub new_solver_evaluation_cache: Lock>>, + pub new_solver_coherence_evaluation_cache: Lock>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, 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 c90f8e761633..c23bc8f09ad1 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 @@ -16,9 +16,9 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, - GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, - QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, + CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause, + NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode, + FIXPOINT_STEP_LIMIT, }; pub(super) mod canonical; @@ -72,7 +72,7 @@ where /// new placeholders to the caller. pub(super) max_input_universe: ty::UniverseIndex, - pub(super) search_graph: &'a mut SearchGraph, + pub(super) search_graph: &'a mut SearchGraph, nested_goals: NestedGoals, @@ -200,7 +200,7 @@ where generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode()); + let mut search_graph = SearchGraph::new(delegate.solver_mode()); let mut ecx = EvalCtxt { delegate, @@ -241,7 +241,7 @@ where /// and registering opaques from the canonicalized input. fn enter_canonical( cx: I, - search_graph: &'a mut search_graph::SearchGraph, + search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, canonical_goal_evaluation: &mut ProofTreeBuilder, f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, @@ -296,7 +296,7 @@ where #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( cx: I, - search_graph: &'a mut search_graph::SearchGraph, + search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, goal_evaluation: &mut ProofTreeBuilder, ) -> QueryResult { diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index b50676e8d532..3e266ddac71f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; use std::mem; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, search_graph, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; @@ -38,7 +38,7 @@ use crate::solve::{ /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder::Interner> +pub(crate) struct ProofTreeBuilder::Interner> where D: SolverDelegate, I: Interner, @@ -321,23 +321,6 @@ impl, I: Interner> ProofTreeBuilder { }) } - pub fn finalize_canonical_goal_evaluation( - &mut self, - cx: I, - ) -> Option { - self.as_mut().map(|this| match this { - DebugSolver::CanonicalGoalEvaluation(evaluation) => { - let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); - let final_revision = - cx.intern_canonical_goal_evaluation_step(final_revision.finalize()); - let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; - assert_eq!(evaluation.kind.replace(kind), None); - final_revision - } - _ => unreachable!(), - }) - } - pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { @@ -571,3 +554,51 @@ impl, I: Interner> ProofTreeBuilder { } } } + +impl search_graph::ProofTreeBuilder for ProofTreeBuilder +where + D: SolverDelegate, + I: Interner, +{ + fn try_apply_proof_tree( + &mut self, + proof_tree: Option, + ) -> bool { + if !self.is_noop() { + if let Some(final_revision) = proof_tree { + let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; + self.canonical_goal_evaluation_kind(kind); + true + } else { + false + } + } else { + true + } + } + + fn on_provisional_cache_hit(&mut self) { + self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::ProvisionalCacheHit); + } + + fn on_cycle_in_stack(&mut self) { + self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::CycleInStack); + } + + fn finalize_canonical_goal_evaluation( + &mut self, + tcx: I, + ) -> Option { + self.as_mut().map(|this| match this { + DebugSolver::CanonicalGoalEvaluation(evaluation) => { + let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); + let final_revision = + tcx.intern_canonical_goal_evaluation_step(final_revision.finalize()); + let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; + assert_eq!(evaluation.kind.replace(kind), None); + final_revision + } + _ => unreachable!(), + }) + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 69d52dcad7a5..fe053a506e71 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,599 +1,90 @@ -use std::mem; +use std::marker::PhantomData; -use rustc_index::{Idx, IndexVec}; -use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::inherent::*; +use rustc_type_ir::search_graph::{self, CycleKind, UsageKind}; +use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; use rustc_type_ir::Interner; -use tracing::debug; +use super::inspect::{self, ProofTreeBuilder}; +use super::FIXPOINT_STEP_LIMIT; use crate::delegate::SolverDelegate; -use crate::solve::inspect::{self, ProofTreeBuilder}; -use crate::solve::{ - CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, -}; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SolverLimit(usize); - -rustc_index::newtype_index! { - #[orderable] - #[gate_rustc_only] - pub struct StackDepth {} +/// This type is never constructed. We only use it to implement `search_graph::Delegate` +/// for all types which impl `SolverDelegate` and doing it directly fails in coherence. +pub(super) struct SearchGraphDelegate { + _marker: PhantomData, } +pub(super) type SearchGraph = search_graph::SearchGraph>; +impl search_graph::Delegate for SearchGraphDelegate +where + D: SolverDelegate, + I: Interner, +{ + type Cx = D::Interner; -bitflags::bitflags! { - /// Whether and how this goal has been used as the root of a - /// cycle. We track the kind of cycle as we're otherwise forced - /// to always rerun at least once. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - struct HasBeenUsed: u8 { - const INDUCTIVE_CYCLE = 1 << 0; - const COINDUCTIVE_CYCLE = 1 << 1; - } -} + const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT; -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] -struct StackEntry { - input: CanonicalInput, + type ProofTreeBuilder = ProofTreeBuilder; - available_depth: SolverLimit, - - /// The maximum depth reached by this stack entry, only up-to date - /// for the top of the stack and lazily updated for the rest. - reached_depth: StackDepth, - - /// Whether this entry is a non-root cycle participant. - /// - /// We must not move the result of non-root cycle participants to the - /// global cache. We store the highest stack depth of a head of a cycle - /// this goal is involved in. This necessary to soundly cache its - /// provisional result. - non_root_cycle_participant: Option, - - encountered_overflow: bool, - - has_been_used: HasBeenUsed, - - /// We put only the root goal of a coinductive cycle into the global cache. - /// - /// If we were to use that result when later trying to prove another cycle - /// participant, we can end up with unstable query results. - /// - /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for - /// an example of where this is needed. - /// - /// There can be multiple roots on the same stack, so we need to track - /// cycle participants per root: - /// ```plain - /// A :- B - /// B :- A, C - /// C :- D - /// D :- C - /// ``` - nested_goals: HashSet>, - /// Starts out as `None` and gets set when rerunning this - /// goal in case we encounter a cycle. - provisional_result: Option>, -} - -/// The provisional result for a goal which is not on the stack. -#[derive(Debug)] -struct DetachedEntry { - /// The head of the smallest non-trivial cycle involving this entry. - /// - /// Given the following rules, when proving `A` the head for - /// the provisional entry of `C` would be `B`. - /// ```plain - /// A :- B - /// B :- C - /// C :- A + B + C - /// ``` - head: StackDepth, - result: QueryResult, -} - -/// Stores the stack depth of a currently evaluated goal *and* already -/// computed results for goals which depend on other goals still on the stack. -/// -/// The provisional result may depend on whether the stack above it is inductive -/// or coinductive. Because of this, we store separate provisional results for -/// each case. If an provisional entry is not applicable, it may be the case -/// that we already have provisional result while computing a goal. In this case -/// we prefer the provisional result to potentially avoid fixpoint iterations. -/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example. -/// -/// The provisional cache can theoretically result in changes to the observable behavior, -/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs. -#[derive(derivative::Derivative)] -#[derivative(Default(bound = ""))] -struct ProvisionalCacheEntry { - stack_depth: Option, - with_inductive_stack: Option>, - with_coinductive_stack: Option>, -} - -impl ProvisionalCacheEntry { - fn is_empty(&self) -> bool { - self.stack_depth.is_none() - && self.with_inductive_stack.is_none() - && self.with_coinductive_stack.is_none() - } -} - -pub(super) struct SearchGraph { - mode: SolverMode, - /// The stack of goals currently being computed. - /// - /// An element is *deeper* in the stack if its index is *lower*. - stack: IndexVec>, - provisional_cache: HashMap, ProvisionalCacheEntry>, -} - -impl SearchGraph { - pub(super) fn new(mode: SolverMode) -> SearchGraph { - Self { mode, stack: Default::default(), provisional_cache: Default::default() } + fn recursion_limit(cx: I) -> usize { + cx.recursion_limit() } - pub(super) fn solver_mode(&self) -> SolverMode { - self.mode - } - - fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { - if let Some(parent) = self.stack.raw.last_mut() { - parent.reached_depth = parent.reached_depth.max(reached_depth); - parent.encountered_overflow |= encountered_overflow; + fn initial_provisional_result( + cx: I, + kind: CycleKind, + input: CanonicalInput, + ) -> QueryResult { + match kind { + CycleKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), + CycleKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)), } } - pub(super) fn is_empty(&self) -> bool { - self.stack.is_empty() - } - - /// Returns the remaining depth allowed for nested goals. - /// - /// This is generally simply one less than the current depth. - /// However, if we encountered overflow, we significantly reduce - /// the remaining depth of all nested goals to prevent hangs - /// in case there is exponential blowup. - fn allowed_depth_for_nested( + fn reached_fixpoint( cx: I, - stack: &IndexVec>, - ) -> Option { - if let Some(last) = stack.raw.last() { - if last.available_depth.0 == 0 { - return None; - } - - Some(if last.encountered_overflow { - SolverLimit(last.available_depth.0 / 4) - } else { - SolverLimit(last.available_depth.0 - 1) - }) - } else { - Some(SolverLimit(cx.recursion_limit())) - } - } - - fn stack_coinductive_from( - cx: I, - stack: &IndexVec>, - head: StackDepth, + kind: UsageKind, + input: CanonicalInput, + provisional_result: Option>, + result: QueryResult, ) -> bool { - stack.raw[head.index()..] - .iter() - .all(|entry| entry.input.value.goal.predicate.is_coinductive(cx)) - } - - // When encountering a solver cycle, the result of the current goal - // depends on goals lower on the stack. - // - // We have to therefore be careful when caching goals. Only the final result - // of the cycle root, i.e. the lowest goal on the stack involved in this cycle, - // is moved to the global cache while all others are stored in a provisional cache. - // - // We update both the head of this cycle to rerun its evaluation until - // we reach a fixpoint and all other cycle participants to make sure that - // their result does not get moved to the global cache. - fn tag_cycle_participants( - stack: &mut IndexVec>, - usage_kind: HasBeenUsed, - head: StackDepth, - ) { - stack[head].has_been_used |= usage_kind; - debug_assert!(!stack[head].has_been_used.is_empty()); - - // The current root of these cycles. Note that this may not be the final - // root in case a later goal depends on a goal higher up the stack. - let mut current_root = head; - while let Some(parent) = stack[current_root].non_root_cycle_participant { - current_root = parent; - debug_assert!(!stack[current_root].has_been_used.is_empty()); - } - - let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1); - let current_cycle_root = &mut stack[current_root.as_usize()]; - for entry in cycle_participants { - entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); - current_cycle_root.nested_goals.insert(entry.input); - current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); - } - } - - fn clear_dependent_provisional_results( - provisional_cache: &mut HashMap, ProvisionalCacheEntry>, - head: StackDepth, - ) { - #[allow(rustc::potential_query_instability)] - provisional_cache.retain(|_, entry| { - if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) { - entry.with_coinductive_stack.take(); - } - if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) { - entry.with_inductive_stack.take(); - } - !entry.is_empty() - }); - } - - /// The trait solver behavior is different for coherence - /// so we use a separate cache. Alternatively we could use - /// a single cache and share it between coherence and ordinary - /// trait solving. - pub(super) fn global_cache(&self, cx: I) -> I::EvaluationCache { - cx.evaluation_cache(self.mode) - } - - /// Probably the most involved method of the whole solver. - /// - /// Given some goal which is proven via the `prove_goal` closure, this - /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal>( - &mut self, - cx: I, - input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, - ) -> QueryResult { - self.check_invariants(); - // Check for overflow. - let Some(available_depth) = Self::allowed_depth_for_nested(cx, &self.stack) else { - if let Some(last) = self.stack.raw.last_mut() { - last.encountered_overflow = true; - } - - inspect - .canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); - return Self::response_no_constraints(cx, input, Certainty::overflow(true)); - }; - - if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) { - debug!("global cache hit"); - return result; - } - - // Check whether the goal is in the provisional cache. - // The provisional result may rely on the path to its cycle roots, - // so we have to check the path of the current goal matches that of - // the cache entry. - let cache_entry = self.provisional_cache.entry(input).or_default(); - if let Some(entry) = cache_entry - .with_coinductive_stack - .as_ref() - .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head)) - .or_else(|| { - cache_entry - .with_inductive_stack - .as_ref() - .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head)) - }) - { - debug!("provisional cache hit"); - // We have a nested goal which is already in the provisional cache, use - // its result. We do not provide any usage kind as that should have been - // already set correctly while computing the cache entry. - inspect.canonical_goal_evaluation_kind( - inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit, - ); - Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head); - return entry.result; - } else if let Some(stack_depth) = cache_entry.stack_depth { - debug!("encountered cycle with depth {stack_depth:?}"); - // We have a nested goal which directly relies on a goal deeper in the stack. - // - // We start by tagging all cycle participants, as that's necessary for caching. - // - // Finally we can return either the provisional response or the initial response - // in case we're in the first fixpoint iteration for this goal. - inspect.canonical_goal_evaluation_kind( - inspect::WipCanonicalGoalEvaluationKind::CycleInStack, - ); - let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth); - let usage_kind = if is_coinductive_cycle { - HasBeenUsed::COINDUCTIVE_CYCLE - } else { - HasBeenUsed::INDUCTIVE_CYCLE - }; - Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth); - - // Return the provisional result or, if we're in the first iteration, - // start with no constraints. - return if let Some(result) = self.stack[stack_depth].provisional_result { - result - } else if is_coinductive_cycle { - Self::response_no_constraints(cx, input, Certainty::Yes) - } else { - Self::response_no_constraints(cx, input, Certainty::overflow(false)) - }; - } else { - // No entry, we push this goal on the stack and try to prove it. - let depth = self.stack.next_index(); - let entry = StackEntry { - input, - available_depth, - reached_depth: depth, - non_root_cycle_participant: None, - encountered_overflow: false, - has_been_used: HasBeenUsed::empty(), - nested_goals: Default::default(), - provisional_result: None, - }; - assert_eq!(self.stack.push(entry), depth); - cache_entry.stack_depth = Some(depth); - } - - // This is for global caching, so we properly track query dependencies. - // Everything that affects the `result` should be performed within this - // `with_anon_task` closure. If computing this goal depends on something - // not tracked by the cache key and from outside of this anon task, it - // must not be added to the global cache. Notably, this is the case for - // trait solver cycles participants. - let ((final_entry, result), dep_node) = cx.with_cached_task(|| { - for _ in 0..FIXPOINT_STEP_LIMIT { - match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) { - StepResult::Done(final_entry, result) => return (final_entry, result), - StepResult::HasChanged => debug!("fixpoint changed provisional results"), - } - } - - debug!("canonical cycle overflow"); - let current_entry = self.stack.pop().unwrap(); - debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(cx, input, Certainty::overflow(false)); - (current_entry, result) - }); - - let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); - - self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); - - // We're now done with this goal. In case this goal is involved in a larger cycle - // do not remove it from the provisional cache and update its provisional result. - // We only add the root of cycles to the global cache. - if let Some(head) = final_entry.non_root_cycle_participant { - let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head); - - let entry = self.provisional_cache.get_mut(&input).unwrap(); - entry.stack_depth = None; - if coinductive_stack { - entry.with_coinductive_stack = Some(DetachedEntry { head, result }); - } else { - entry.with_inductive_stack = Some(DetachedEntry { head, result }); - } - } else { - self.provisional_cache.remove(&input); - let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len(); - // When encountering a cycle, both inductive and coinductive, we only - // move the root into the global cache. We also store all other cycle - // participants involved. - // - // We must not use the global cache entry of a root goal if a cycle - // participant is on the stack. This is necessary to prevent unstable - // results. See the comment of `StackEntry::nested_goals` for - // more details. - self.global_cache(cx).insert( - cx, - input, - proof_tree, - reached_depth, - final_entry.encountered_overflow, - final_entry.nested_goals, - dep_node, - result, - ) - } - - self.check_invariants(); - - result - } - - /// Try to fetch a previously computed result from the global cache, - /// making sure to only do so if it would match the result of reevaluating - /// this goal. - fn lookup_global_cache>( - &mut self, - cx: I, - input: CanonicalInput, - available_depth: SolverLimit, - inspect: &mut ProofTreeBuilder, - ) -> Option> { - let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self - .global_cache(cx) - // FIXME: Awkward `Limit -> usize -> Limit`. - .get(cx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; - - // If we're building a proof tree and the current cache entry does not - // contain a proof tree, we do not use the entry but instead recompute - // the goal. We simply overwrite the existing entry once we're done, - // caching the proof tree. - if !inspect.is_noop() { - if let Some(final_revision) = proof_tree { - let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { final_revision }; - inspect.canonical_goal_evaluation_kind(kind); - } else { - return None; - } - } - - // Adjust the parent goal as if we actually computed this goal. - let reached_depth = self.stack.next_index().plus(additional_depth); - self.update_parent_goal(reached_depth, encountered_overflow); - - Some(result) - } -} - -enum StepResult { - Done(StackEntry, QueryResult), - HasChanged, -} - -impl SearchGraph { - /// When we encounter a coinductive cycle, we have to fetch the - /// result of that cycle while we are still computing it. Because - /// of this we continuously recompute the cycle until the result - /// of the previous iteration is equal to the final result, at which - /// point we are done. - fn fixpoint_step_in_task( - &mut self, - cx: I, - input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - prove_goal: &mut F, - ) -> StepResult - where - D: SolverDelegate, - F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, - { - let result = prove_goal(self, inspect); - let stack_entry = self.stack.pop().unwrap(); - debug_assert_eq!(stack_entry.input, input); - - // If the current goal is not the root of a cycle, we are done. - if stack_entry.has_been_used.is_empty() { - return StepResult::Done(stack_entry, result); - } - - // If it is a cycle head, we have to keep trying to prove it until - // we reach a fixpoint. We need to do so for all cycle heads, - // not only for the root. - // - // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs - // for an example. - - // Start by clearing all provisional cache entries which depend on this - // the current goal. - Self::clear_dependent_provisional_results( - &mut self.provisional_cache, - self.stack.next_index(), - ); - - // Check whether we reached a fixpoint, either because the final result - // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the - // final result is equal to the initial response for that case. - let reached_fixpoint = if let Some(r) = stack_entry.provisional_result { + if let Some(r) = provisional_result { r == result - } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE { - Self::response_no_constraints(cx, input, Certainty::Yes) == result - } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE { - Self::response_no_constraints(cx, input, Certainty::overflow(false)) == result } else { - false - }; - - // If we did not reach a fixpoint, update the provisional result and reevaluate. - if reached_fixpoint { - StepResult::Done(stack_entry, result) - } else { - let depth = self.stack.push(StackEntry { - has_been_used: HasBeenUsed::empty(), - provisional_result: Some(result), - ..stack_entry - }); - debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth)); - StepResult::HasChanged + match kind { + UsageKind::Single(CycleKind::Coinductive) => { + response_no_constraints(cx, input, Certainty::Yes) == result + } + UsageKind::Single(CycleKind::Inductive) => { + response_no_constraints(cx, input, Certainty::overflow(false)) == result + } + UsageKind::Mixed => false, + } } } - fn response_no_constraints( + fn on_stack_overflow( cx: I, - goal: CanonicalInput, - certainty: Certainty, + inspect: &mut ProofTreeBuilder, + input: CanonicalInput, ) -> QueryResult { - Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) + inspect.canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); + response_no_constraints(cx, input, Certainty::overflow(true)) } - #[allow(rustc::potential_query_instability)] - fn check_invariants(&self) { - if !cfg!(debug_assertions) { - return; - } + fn on_fixpoint_overflow(cx: I, input: CanonicalInput) -> QueryResult { + response_no_constraints(cx, input, Certainty::overflow(false)) + } - let SearchGraph { mode: _, stack, provisional_cache } = self; - if stack.is_empty() { - assert!(provisional_cache.is_empty()); - } - - for (depth, entry) in stack.iter_enumerated() { - let StackEntry { - input, - available_depth: _, - reached_depth: _, - non_root_cycle_participant, - encountered_overflow: _, - has_been_used, - ref nested_goals, - provisional_result, - } = *entry; - let cache_entry = provisional_cache.get(&entry.input).unwrap(); - assert_eq!(cache_entry.stack_depth, Some(depth)); - if let Some(head) = non_root_cycle_participant { - assert!(head < depth); - assert!(nested_goals.is_empty()); - assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); - - let mut current_root = head; - while let Some(parent) = stack[current_root].non_root_cycle_participant { - current_root = parent; - } - assert!(stack[current_root].nested_goals.contains(&input)); - } - - if !nested_goals.is_empty() { - assert!(provisional_result.is_some() || !has_been_used.is_empty()); - for entry in stack.iter().take(depth.as_usize()) { - assert_eq!(nested_goals.get(&entry.input), None); - } - } - } - - for (&input, entry) in &self.provisional_cache { - let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } = - entry; - assert!( - stack_depth.is_some() - || with_coinductive_stack.is_some() - || with_inductive_stack.is_some() - ); - - if let &Some(stack_depth) = stack_depth { - assert_eq!(stack[stack_depth].input, input); - } - - let check_detached = |detached_entry: &DetachedEntry| { - let DetachedEntry { head, result: _ } = *detached_entry; - assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); - }; - - if let Some(with_coinductive_stack) = with_coinductive_stack { - check_detached(with_coinductive_stack); - } - - if let Some(with_inductive_stack) = with_inductive_stack { - check_detached(with_inductive_stack); - } - } + fn step_is_coinductive(cx: I, input: CanonicalInput) -> bool { + input.value.goal.predicate.is_coinductive(cx) } } + +fn response_no_constraints( + cx: I, + goal: CanonicalInput, + certainty: Certainty, +) -> QueryResult { + Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) +} diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs index 6e862db0b254..d8a5bdba7b8a 100644 --- a/compiler/rustc_query_system/src/cache.rs +++ b/compiler/rustc_query_system/src/cache.rs @@ -40,7 +40,7 @@ impl Cache { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct WithDepNode { dep_node: DepNodeIndex, cached_value: T, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index de86a8536f7a..f05d626b4703 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,11 +8,10 @@ use std::hash::Hash; use rustc_ast_ir::Mutability; -use crate::data_structures::HashSet; use crate::elaborate::Elaboratable; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; -use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; +use crate::solve::Reveal; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; @@ -539,33 +538,6 @@ pub trait Features: Copy { fn associated_const_equality(self) -> bool; } -pub trait EvaluationCache { - /// Insert a final result into the global cache. - fn insert( - &self, - tcx: I, - key: CanonicalInput, - proof_tree: Option, - additional_depth: usize, - encountered_overflow: bool, - cycle_participants: HashSet>, - dep_node: I::DepNodeIndex, - result: QueryResult, - ); - - /// Try to fetch a cached result, checking the recursion limit - /// and handling root goals of coinductive cycles. - /// - /// If this returns `Some` the cache result can be used. - fn get( - &self, - tcx: I, - key: CanonicalInput, - stack_entries: impl IntoIterator>, - available_depth: usize, - ) -> Option>; -} - pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { fn is_local(self) -> bool; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index fdd1553d389d..14ebbb12fe2f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -10,8 +10,11 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; +use crate::search_graph; use crate::solve::inspect::CanonicalGoalEvaluationStep; -use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode}; +use crate::solve::{ + CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, +}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty}; @@ -86,6 +89,13 @@ pub trait Interner: ) -> Self::ExternalConstraints; type DepNodeIndex; + type Tracked: Debug; + fn mk_tracked( + self, + data: T, + dep_node: Self::DepNodeIndex, + ) -> Self::Tracked; + fn get_tracked(self, tracked: &Self::Tracked) -> T; fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); // Kinds of tys @@ -125,8 +135,11 @@ pub trait Interner: type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - type EvaluationCache: EvaluationCache; - fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache; + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R; fn expand_abstract_consts>(self, t: T) -> T; @@ -373,3 +386,32 @@ impl CollectAndApply for Result { }) } } + +impl search_graph::Cx for I { + type ProofTree = Option; + type Input = CanonicalInput; + type Result = QueryResult; + + type DepNodeIndex = I::DepNodeIndex; + type Tracked = I::Tracked; + fn mk_tracked( + self, + data: T, + dep_node_index: I::DepNodeIndex, + ) -> I::Tracked { + I::mk_tracked(self, data, dep_node_index) + } + fn get_tracked(self, tracked: &I::Tracked) -> T { + I::get_tracked(self, tracked) + } + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) { + I::with_cached_task(self, task) + } + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R { + I::with_global_cache(self, mode, f) + } +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index b14a65fc7795..37ee66fa222a 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -30,6 +30,7 @@ pub mod lang_items; pub mod lift; pub mod outlives; pub mod relate; +pub mod search_graph; pub mod solve; // These modules are not `pub` since they are glob-imported. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs new file mode 100644 index 000000000000..5ccda931f9c5 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -0,0 +1,118 @@ +use rustc_index::IndexVec; + +use super::{AvailableDepth, Cx, StackDepth, StackEntry}; +use crate::data_structures::{HashMap, HashSet}; + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] +struct QueryData { + result: X::Result, + proof_tree: X::ProofTree, +} + +struct Success { + data: X::Tracked>, + additional_depth: usize, +} + +/// The cache entry for a given input. +/// +/// This contains results whose computation never hit the +/// recursion limit in `success`, and all results which hit +/// the recursion limit in `with_overflow`. +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +struct CacheEntry { + success: Option>, + /// We have to be careful when caching roots of cycles. + /// + /// See the doc comment of `StackEntry::cycle_participants` for more + /// details. + nested_goals: HashSet, + with_overflow: HashMap>>, +} + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +pub(super) struct CacheData<'a, X: Cx> { + pub(super) result: X::Result, + pub(super) proof_tree: X::ProofTree, + pub(super) additional_depth: usize, + pub(super) encountered_overflow: bool, + // FIXME: This is currently unused, but impacts the design + // by requiring a closure for `Cx::with_global_cache`. + pub(super) nested_goals: &'a HashSet, +} + +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +pub struct GlobalCache { + map: HashMap>, +} + +impl GlobalCache { + /// Insert a final result into the global cache. + pub(super) fn insert( + &mut self, + cx: X, + input: X::Input, + + result: X::Result, + proof_tree: X::ProofTree, + dep_node: X::DepNodeIndex, + + additional_depth: usize, + encountered_overflow: bool, + nested_goals: &HashSet, + ) { + let data = cx.mk_tracked(QueryData { result, proof_tree }, dep_node); + let entry = self.map.entry(input).or_default(); + entry.nested_goals.extend(nested_goals); + if encountered_overflow { + entry.with_overflow.insert(additional_depth, data); + } else { + entry.success = Some(Success { data, additional_depth }); + } + } + + /// Try to fetch a cached result, checking the recursion limit + /// and handling root goals of coinductive cycles. + /// + /// If this returns `Some` the cache result can be used. + pub(super) fn get<'a>( + &'a self, + cx: X, + input: X::Input, + stack: &IndexVec>, + available_depth: AvailableDepth, + ) -> Option> { + let entry = self.map.get(&input)?; + if stack.iter().any(|e| entry.nested_goals.contains(&e.input)) { + return None; + } + + if let Some(ref success) = entry.success { + if available_depth.cache_entry_is_applicable(success.additional_depth) { + let QueryData { result, proof_tree } = cx.get_tracked(&success.data); + return Some(CacheData { + result, + proof_tree, + additional_depth: success.additional_depth, + encountered_overflow: false, + nested_goals: &entry.nested_goals, + }); + } + } + + entry.with_overflow.get(&available_depth.0).map(|e| { + let QueryData { result, proof_tree } = cx.get_tracked(e); + CacheData { + result, + proof_tree, + additional_depth: available_depth.0, + encountered_overflow: true, + nested_goals: &entry.nested_goals, + } + }) + } +} diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs new file mode 100644 index 000000000000..c2204becdfd7 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -0,0 +1,605 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::marker::PhantomData; +use std::mem; + +use rustc_index::{Idx, IndexVec}; +use tracing::debug; + +use crate::data_structures::{HashMap, HashSet}; +use crate::solve::SolverMode; + +mod global_cache; +use global_cache::CacheData; +pub use global_cache::GlobalCache; +mod validate; + +/// The search graph does not simply use `Interner` directly +/// to enable its fuzzing without having to stub the rest of +/// the interner. We don't make this a super trait of `Interner` +/// as users of the shared type library shouldn't have to care +/// about `Input` and `Result` as they are implementation details +/// of the search graph. +pub trait Cx: Copy { + type ProofTree: Debug + Copy; + type Input: Debug + Eq + Hash + Copy; + type Result: Debug + Eq + Hash + Copy; + + type DepNodeIndex; + type Tracked: Debug; + fn mk_tracked( + self, + data: T, + dep_node_index: Self::DepNodeIndex, + ) -> Self::Tracked; + fn get_tracked(self, tracked: &Self::Tracked) -> T; + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); + + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut GlobalCache) -> R, + ) -> R; +} + +pub trait ProofTreeBuilder { + fn try_apply_proof_tree(&mut self, proof_tree: X::ProofTree) -> bool; + fn on_provisional_cache_hit(&mut self); + fn on_cycle_in_stack(&mut self); + fn finalize_canonical_goal_evaluation(&mut self, cx: X) -> X::ProofTree; +} + +pub trait Delegate { + type Cx: Cx; + const FIXPOINT_STEP_LIMIT: usize; + type ProofTreeBuilder: ProofTreeBuilder; + + fn recursion_limit(cx: Self::Cx) -> usize; + + fn initial_provisional_result( + cx: Self::Cx, + kind: CycleKind, + input: ::Input, + ) -> ::Result; + fn reached_fixpoint( + cx: Self::Cx, + kind: UsageKind, + input: ::Input, + provisional_result: Option<::Result>, + result: ::Result, + ) -> bool; + fn on_stack_overflow( + cx: Self::Cx, + inspect: &mut Self::ProofTreeBuilder, + input: ::Input, + ) -> ::Result; + fn on_fixpoint_overflow( + cx: Self::Cx, + input: ::Input, + ) -> ::Result; + + fn step_is_coinductive(cx: Self::Cx, input: ::Input) -> bool; +} + +/// In the initial iteration of a cycle, we do not yet have a provisional +/// result. In the case we return an initial provisional result depending +/// on the kind of cycle. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CycleKind { + Coinductive, + Inductive, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UsageKind { + Single(CycleKind), + Mixed, +} +impl UsageKind { + fn merge(self, other: Self) -> Self { + match (self, other) { + (UsageKind::Single(lhs), UsageKind::Single(rhs)) => { + if lhs == rhs { + UsageKind::Single(lhs) + } else { + UsageKind::Mixed + } + } + (UsageKind::Mixed, UsageKind::Mixed) + | (UsageKind::Mixed, UsageKind::Single(_)) + | (UsageKind::Single(_), UsageKind::Mixed) => UsageKind::Mixed, + } + } +} + +#[derive(Debug, Clone, Copy)] +struct AvailableDepth(usize); +impl AvailableDepth { + /// Returns the remaining depth allowed for nested goals. + /// + /// This is generally simply one less than the current depth. + /// However, if we encountered overflow, we significantly reduce + /// the remaining depth of all nested goals to prevent hangs + /// in case there is exponential blowup. + fn allowed_depth_for_nested( + cx: D::Cx, + stack: &IndexVec>, + ) -> Option { + if let Some(last) = stack.raw.last() { + if last.available_depth.0 == 0 { + return None; + } + + Some(if last.encountered_overflow { + AvailableDepth(last.available_depth.0 / 2) + } else { + AvailableDepth(last.available_depth.0 - 1) + }) + } else { + Some(AvailableDepth(D::recursion_limit(cx))) + } + } + + /// Whether we're allowed to use a global cache entry which required + /// the given depth. + fn cache_entry_is_applicable(self, additional_depth: usize) -> bool { + self.0 >= additional_depth + } +} + +rustc_index::newtype_index! { + #[orderable] + #[gate_rustc_only] + pub struct StackDepth {} +} + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +struct StackEntry { + input: X::Input, + + available_depth: AvailableDepth, + + /// The maximum depth reached by this stack entry, only up-to date + /// for the top of the stack and lazily updated for the rest. + reached_depth: StackDepth, + + /// Whether this entry is a non-root cycle participant. + /// + /// We must not move the result of non-root cycle participants to the + /// global cache. We store the highest stack depth of a head of a cycle + /// this goal is involved in. This necessary to soundly cache its + /// provisional result. + non_root_cycle_participant: Option, + + encountered_overflow: bool, + + has_been_used: Option, + + /// We put only the root goal of a coinductive cycle into the global cache. + /// + /// If we were to use that result when later trying to prove another cycle + /// participant, we can end up with unstable query results. + /// + /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for + /// an example of where this is needed. + /// + /// There can be multiple roots on the same stack, so we need to track + /// cycle participants per root: + /// ```plain + /// A :- B + /// B :- A, C + /// C :- D + /// D :- C + /// ``` + nested_goals: HashSet, + /// Starts out as `None` and gets set when rerunning this + /// goal in case we encounter a cycle. + provisional_result: Option, +} + +/// The provisional result for a goal which is not on the stack. +#[derive(Debug)] +struct DetachedEntry { + /// The head of the smallest non-trivial cycle involving this entry. + /// + /// Given the following rules, when proving `A` the head for + /// the provisional entry of `C` would be `B`. + /// ```plain + /// A :- B + /// B :- C + /// C :- A + B + C + /// ``` + head: StackDepth, + result: X::Result, +} + +/// Stores the stack depth of a currently evaluated goal *and* already +/// computed results for goals which depend on other goals still on the stack. +/// +/// The provisional result may depend on whether the stack above it is inductive +/// or coinductive. Because of this, we store separate provisional results for +/// each case. If an provisional entry is not applicable, it may be the case +/// that we already have provisional result while computing a goal. In this case +/// we prefer the provisional result to potentially avoid fixpoint iterations. +/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example. +/// +/// The provisional cache can theoretically result in changes to the observable behavior, +/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs. +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +struct ProvisionalCacheEntry { + stack_depth: Option, + with_inductive_stack: Option>, + with_coinductive_stack: Option>, +} + +impl ProvisionalCacheEntry { + fn is_empty(&self) -> bool { + self.stack_depth.is_none() + && self.with_inductive_stack.is_none() + && self.with_coinductive_stack.is_none() + } +} + +pub struct SearchGraph, X: Cx = ::Cx> { + mode: SolverMode, + /// The stack of goals currently being computed. + /// + /// An element is *deeper* in the stack if its index is *lower*. + stack: IndexVec>, + provisional_cache: HashMap>, + + _marker: PhantomData, +} + +impl, X: Cx> SearchGraph { + pub fn new(mode: SolverMode) -> SearchGraph { + Self { + mode, + stack: Default::default(), + provisional_cache: Default::default(), + _marker: PhantomData, + } + } + + pub fn solver_mode(&self) -> SolverMode { + self.mode + } + + fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { + if let Some(parent) = self.stack.raw.last_mut() { + parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.encountered_overflow |= encountered_overflow; + } + } + + pub fn is_empty(&self) -> bool { + self.stack.is_empty() + } + + fn stack_coinductive_from( + cx: X, + stack: &IndexVec>, + head: StackDepth, + ) -> bool { + stack.raw[head.index()..].iter().all(|entry| D::step_is_coinductive(cx, entry.input)) + } + + // When encountering a solver cycle, the result of the current goal + // depends on goals lower on the stack. + // + // We have to therefore be careful when caching goals. Only the final result + // of the cycle root, i.e. the lowest goal on the stack involved in this cycle, + // is moved to the global cache while all others are stored in a provisional cache. + // + // We update both the head of this cycle to rerun its evaluation until + // we reach a fixpoint and all other cycle participants to make sure that + // their result does not get moved to the global cache. + fn tag_cycle_participants( + stack: &mut IndexVec>, + usage_kind: Option, + head: StackDepth, + ) { + if let Some(usage_kind) = usage_kind { + stack[head].has_been_used = + Some(stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind))); + } + debug_assert!(stack[head].has_been_used.is_some()); + + // The current root of these cycles. Note that this may not be the final + // root in case a later goal depends on a goal higher up the stack. + let mut current_root = head; + while let Some(parent) = stack[current_root].non_root_cycle_participant { + current_root = parent; + debug_assert!(stack[current_root].has_been_used.is_some()); + } + + let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1); + let current_cycle_root = &mut stack[current_root.as_usize()]; + for entry in cycle_participants { + entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); + current_cycle_root.nested_goals.insert(entry.input); + current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); + } + } + + fn clear_dependent_provisional_results( + provisional_cache: &mut HashMap>, + head: StackDepth, + ) { + #[allow(rustc::potential_query_instability)] + provisional_cache.retain(|_, entry| { + if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_coinductive_stack.take(); + } + if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_inductive_stack.take(); + } + !entry.is_empty() + }); + } + + /// Probably the most involved method of the whole solver. + /// + /// Given some goal which is proven via the `prove_goal` closure, this + /// handles caching, overflow, and coinductive cycles. + pub fn with_new_goal( + &mut self, + cx: X, + input: X::Input, + inspect: &mut D::ProofTreeBuilder, + mut prove_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + ) -> X::Result { + self.check_invariants(); + // Check for overflow. + let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::(cx, &self.stack) + else { + if let Some(last) = self.stack.raw.last_mut() { + last.encountered_overflow = true; + } + + debug!("encountered stack overflow"); + return D::on_stack_overflow(cx, inspect, input); + }; + + if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) { + return result; + } + + // Check whether the goal is in the provisional cache. + // The provisional result may rely on the path to its cycle roots, + // so we have to check the path of the current goal matches that of + // the cache entry. + let cache_entry = self.provisional_cache.entry(input).or_default(); + if let Some(entry) = cache_entry + .with_coinductive_stack + .as_ref() + .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head)) + .or_else(|| { + cache_entry + .with_inductive_stack + .as_ref() + .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head)) + }) + { + debug!("provisional cache hit"); + // We have a nested goal which is already in the provisional cache, use + // its result. We do not provide any usage kind as that should have been + // already set correctly while computing the cache entry. + inspect.on_provisional_cache_hit(); + Self::tag_cycle_participants(&mut self.stack, None, entry.head); + return entry.result; + } else if let Some(stack_depth) = cache_entry.stack_depth { + debug!("encountered cycle with depth {stack_depth:?}"); + // We have a nested goal which directly relies on a goal deeper in the stack. + // + // We start by tagging all cycle participants, as that's necessary for caching. + // + // Finally we can return either the provisional response or the initial response + // in case we're in the first fixpoint iteration for this goal. + inspect.on_cycle_in_stack(); + + let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth); + let cycle_kind = + if is_coinductive_cycle { CycleKind::Coinductive } else { CycleKind::Inductive }; + Self::tag_cycle_participants( + &mut self.stack, + Some(UsageKind::Single(cycle_kind)), + stack_depth, + ); + + // Return the provisional result or, if we're in the first iteration, + // start with no constraints. + return if let Some(result) = self.stack[stack_depth].provisional_result { + result + } else { + D::initial_provisional_result(cx, cycle_kind, input) + }; + } else { + // No entry, we push this goal on the stack and try to prove it. + let depth = self.stack.next_index(); + let entry = StackEntry { + input, + available_depth, + reached_depth: depth, + non_root_cycle_participant: None, + encountered_overflow: false, + has_been_used: None, + nested_goals: Default::default(), + provisional_result: None, + }; + assert_eq!(self.stack.push(entry), depth); + cache_entry.stack_depth = Some(depth); + }; + + // This is for global caching, so we properly track query dependencies. + // Everything that affects the `result` should be performed within this + // `with_anon_task` closure. If computing this goal depends on something + // not tracked by the cache key and from outside of this anon task, it + // must not be added to the global cache. Notably, this is the case for + // trait solver cycles participants. + let ((final_entry, result), dep_node) = cx.with_cached_task(|| { + for _ in 0..D::FIXPOINT_STEP_LIMIT { + match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) { + StepResult::Done(final_entry, result) => return (final_entry, result), + StepResult::HasChanged => debug!("fixpoint changed provisional results"), + } + } + + debug!("canonical cycle overflow"); + let current_entry = self.stack.pop().unwrap(); + debug_assert!(current_entry.has_been_used.is_none()); + let result = D::on_fixpoint_overflow(cx, input); + (current_entry, result) + }); + + let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); + + self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); + + // We're now done with this goal. In case this goal is involved in a larger cycle + // do not remove it from the provisional cache and update its provisional result. + // We only add the root of cycles to the global cache. + if let Some(head) = final_entry.non_root_cycle_participant { + let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head); + + let entry = self.provisional_cache.get_mut(&input).unwrap(); + entry.stack_depth = None; + if coinductive_stack { + entry.with_coinductive_stack = Some(DetachedEntry { head, result }); + } else { + entry.with_inductive_stack = Some(DetachedEntry { head, result }); + } + } else { + // When encountering a cycle, both inductive and coinductive, we only + // move the root into the global cache. We also store all other cycle + // participants involved. + // + // We must not use the global cache entry of a root goal if a cycle + // participant is on the stack. This is necessary to prevent unstable + // results. See the comment of `StackEntry::nested_goals` for + // more details. + self.provisional_cache.remove(&input); + let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); + cx.with_global_cache(self.mode, |cache| { + cache.insert( + cx, + input, + result, + proof_tree, + dep_node, + additional_depth, + final_entry.encountered_overflow, + &final_entry.nested_goals, + ) + }) + } + + self.check_invariants(); + + result + } + + /// Try to fetch a previously computed result from the global cache, + /// making sure to only do so if it would match the result of reevaluating + /// this goal. + fn lookup_global_cache( + &mut self, + cx: X, + input: X::Input, + available_depth: AvailableDepth, + inspect: &mut D::ProofTreeBuilder, + ) -> Option { + cx.with_global_cache(self.mode, |cache| { + let CacheData { + result, + proof_tree, + additional_depth, + encountered_overflow, + nested_goals: _, // FIXME: consider nested goals here. + } = cache.get(cx, input, &self.stack, available_depth)?; + + // If we're building a proof tree and the current cache entry does not + // contain a proof tree, we do not use the entry but instead recompute + // the goal. We simply overwrite the existing entry once we're done, + // caching the proof tree. + if !inspect.try_apply_proof_tree(proof_tree) { + return None; + } + + // Update the reached depth of the current goal to make sure + // its state is the same regardless of whether we've used the + // global cache or not. + let reached_depth = self.stack.next_index().plus(additional_depth); + self.update_parent_goal(reached_depth, encountered_overflow); + + debug!("global cache hit"); + Some(result) + }) + } +} + +enum StepResult { + Done(StackEntry, X::Result), + HasChanged, +} + +impl, X: Cx> SearchGraph { + /// When we encounter a coinductive cycle, we have to fetch the + /// result of that cycle while we are still computing it. Because + /// of this we continuously recompute the cycle until the result + /// of the previous iteration is equal to the final result, at which + /// point we are done. + fn fixpoint_step_in_task( + &mut self, + cx: X, + input: X::Input, + inspect: &mut D::ProofTreeBuilder, + prove_goal: &mut F, + ) -> StepResult + where + F: FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + { + let result = prove_goal(self, inspect); + let stack_entry = self.stack.pop().unwrap(); + debug_assert_eq!(stack_entry.input, input); + + // If the current goal is not the root of a cycle, we are done. + let Some(usage_kind) = stack_entry.has_been_used else { + return StepResult::Done(stack_entry, result); + }; + + // If it is a cycle head, we have to keep trying to prove it until + // we reach a fixpoint. We need to do so for all cycle heads, + // not only for the root. + // + // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs + // for an example. + + // Start by clearing all provisional cache entries which depend on this + // the current goal. + Self::clear_dependent_provisional_results( + &mut self.provisional_cache, + self.stack.next_index(), + ); + + // Check whether we reached a fixpoint, either because the final result + // is equal to the provisional result of the previous iteration, or because + // this was only the root of either coinductive or inductive cycles, and the + // final result is equal to the initial response for that case. + // + // If we did not reach a fixpoint, update the provisional result and reevaluate. + if D::reached_fixpoint(cx, usage_kind, input, stack_entry.provisional_result, result) { + StepResult::Done(stack_entry, result) + } else { + let depth = self.stack.push(StackEntry { + has_been_used: None, + provisional_result: Some(result), + ..stack_entry + }); + debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth)); + StepResult::HasChanged + } + } +} diff --git a/compiler/rustc_type_ir/src/search_graph/validate.rs b/compiler/rustc_type_ir/src/search_graph/validate.rs new file mode 100644 index 000000000000..1ae806834ba7 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/validate.rs @@ -0,0 +1,75 @@ +use super::*; + +impl, X: Cx> SearchGraph { + #[allow(rustc::potential_query_instability)] + pub(super) fn check_invariants(&self) { + if !cfg!(debug_assertions) { + return; + } + + let SearchGraph { mode: _, stack, provisional_cache, _marker } = self; + if stack.is_empty() { + assert!(provisional_cache.is_empty()); + } + + for (depth, entry) in stack.iter_enumerated() { + let StackEntry { + input, + available_depth: _, + reached_depth: _, + non_root_cycle_participant, + encountered_overflow: _, + has_been_used, + ref nested_goals, + provisional_result, + } = *entry; + let cache_entry = provisional_cache.get(&entry.input).unwrap(); + assert_eq!(cache_entry.stack_depth, Some(depth)); + if let Some(head) = non_root_cycle_participant { + assert!(head < depth); + assert!(nested_goals.is_empty()); + assert_ne!(stack[head].has_been_used, None); + + let mut current_root = head; + while let Some(parent) = stack[current_root].non_root_cycle_participant { + current_root = parent; + } + assert!(stack[current_root].nested_goals.contains(&input)); + } + + if !nested_goals.is_empty() { + assert!(provisional_result.is_some() || has_been_used.is_some()); + for entry in stack.iter().take(depth.as_usize()) { + assert_eq!(nested_goals.get(&entry.input), None); + } + } + } + + for (&input, entry) in &self.provisional_cache { + let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } = + entry; + assert!( + stack_depth.is_some() + || with_coinductive_stack.is_some() + || with_inductive_stack.is_some() + ); + + if let &Some(stack_depth) = stack_depth { + assert_eq!(stack[stack_depth].input, input); + } + + let check_detached = |detached_entry: &DetachedEntry| { + let DetachedEntry { head, result: _ } = *detached_entry; + assert_ne!(stack[head].has_been_used, None); + }; + + if let Some(with_coinductive_stack) = with_coinductive_stack { + check_detached(with_coinductive_stack); + } + + if let Some(with_inductive_stack) = with_inductive_stack { + check_detached(with_inductive_stack); + } + } + } +} From cef8a044ea73f8056d70d4d9f1f90fad47807786 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 4 Jul 2024 16:45:48 -0400 Subject: [PATCH 250/361] rewrite extra-filename-with-temp-outputs to rmake --- src/tools/run-make-support/src/lib.rs | 5 ++++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../extra-filename-with-temp-outputs/Makefile | 7 ------ .../extra-filename-with-temp-outputs/rmake.rs | 23 +++++++++++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/extra-filename-with-temp-outputs/Makefile create mode 100644 tests/run-make/extra-filename-with-temp-outputs/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5655318267a2..04b6fd2d6c18 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -303,6 +303,11 @@ pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, exp .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) } +/// Returns true if the filename at `path` ends with `suffix`. +pub fn has_suffix>(path: P, suffix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) +} + /// Gathers all files in the current working directory that have the extension `ext`, and counts /// the number of lines within that contain a match with the regex pattern `re`. pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 33120cf93f90..1879d60e287a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -37,7 +37,6 @@ run-make/extern-fn-with-packed-struct/Makefile run-make/extern-fn-with-union/Makefile run-make/extern-multiple-copies/Makefile run-make/extern-multiple-copies2/Makefile -run-make/extra-filename-with-temp-outputs/Makefile run-make/fmt-write-bloat/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile diff --git a/tests/run-make/extra-filename-with-temp-outputs/Makefile b/tests/run-make/extra-filename-with-temp-outputs/Makefile deleted file mode 100644 index 64745bef5b86..000000000000 --- a/tests/run-make/extra-filename-with-temp-outputs/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) -C extra-filename=bar foo.rs -C save-temps - rm $(TMPDIR)/foobar.foo*0.rcgu.o - rm $(TMPDIR)/$(call BIN,foobar) diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs new file mode 100644 index 000000000000..546e462499f9 --- /dev/null +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -0,0 +1,23 @@ +// In order to prevent temporary files from overwriting each other in parallel +// compilation, rustc was changed to mix an extra filename with temporary +// outputs. However, as this is a similar behavior with the codegen flag +// -C extra-filename, this test checks that the manually passed flag +// is not overwritten by this feature, and that the output files +// are named as expected. +// See https://github.com/rust-lang/rust/pull/15686 + +//FIXME(Oneirical): ignore-cross-compile + +use run_make_support::{ + bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files, +}; + +fn main() { + rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run(); + let object_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o") + }); + let object_file = object_files.get(0).unwrap(); + fs_wrapper::remove_file(object_file); + fs_wrapper::remove_file(bin_name("foobar")); +} From c6cdbe635b08f278ae2d7f1945dca79b9e69ee9c Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 4 Jul 2024 17:04:20 -0400 Subject: [PATCH 251/361] rewrite and rename issue-85019-moved-src-dir to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../extra-filename-with-temp-outputs/rmake.rs | 2 - .../issue-85019-moved-src-dir/Makefile | 28 -------------- .../main.rs | 0 .../my_lib.rs | 0 .../moved-src-dir-fingerprint-ice/rmake.rs | 38 +++++++++++++++++++ 6 files changed, 38 insertions(+), 31 deletions(-) delete mode 100644 tests/run-make/issue-85019-moved-src-dir/Makefile rename tests/run-make/{issue-85019-moved-src-dir => moved-src-dir-fingerprint-ice}/main.rs (100%) rename tests/run-make/{issue-85019-moved-src-dir => moved-src-dir-fingerprint-ice}/my_lib.rs (100%) create mode 100644 tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 1879d60e287a..07d047a48151 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -59,7 +59,6 @@ run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile -run-make/issue-85019-moved-src-dir/Makefile run-make/issue-85401-static-mir/Makefile run-make/issue-88756-default-output/Makefile run-make/issue-97463-abi-param-passing/Makefile diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index 546e462499f9..c39e397a7cb3 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -6,8 +6,6 @@ // are named as expected. // See https://github.com/rust-lang/rust/pull/15686 -//FIXME(Oneirical): ignore-cross-compile - use run_make_support::{ bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files, }; diff --git a/tests/run-make/issue-85019-moved-src-dir/Makefile b/tests/run-make/issue-85019-moved-src-dir/Makefile deleted file mode 100644 index dec289058f93..000000000000 --- a/tests/run-make/issue-85019-moved-src-dir/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../tools.mk - -INCR=$(TMPDIR)/incr -FIRST_SRC=$(TMPDIR)/first_src -SECOND_SRC=$(TMPDIR)/second_src - -# ignore-none no-std is not supported -# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for 'std' - -# Tests that we don't get an ICE when the working directory -# (but not the build directory!) changes between compilation -# sessions - -all: - mkdir $(INCR) - # Build from 'FIRST_SRC' - mkdir $(FIRST_SRC) - cp my_lib.rs $(FIRST_SRC)/my_lib.rs - cp main.rs $(FIRST_SRC)/main.rs - cd $(FIRST_SRC) && \ - $(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \ - $(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET) - # Build from 'SECOND_SRC', keeping the output directory and incremental directory - # the same - mv $(FIRST_SRC) $(SECOND_SRC) - cd $(SECOND_SRC) && \ - $(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \ - $(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET) diff --git a/tests/run-make/issue-85019-moved-src-dir/main.rs b/tests/run-make/moved-src-dir-fingerprint-ice/main.rs similarity index 100% rename from tests/run-make/issue-85019-moved-src-dir/main.rs rename to tests/run-make/moved-src-dir-fingerprint-ice/main.rs diff --git a/tests/run-make/issue-85019-moved-src-dir/my_lib.rs b/tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs similarity index 100% rename from tests/run-make/issue-85019-moved-src-dir/my_lib.rs rename to tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs new file mode 100644 index 000000000000..c64260299892 --- /dev/null +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -0,0 +1,38 @@ +// A SourceFile created during compilation may have a relative +// path (e.g. if rustc itself is invoked with a relative path). +// When we write out crate metadata, we convert all relative paths +// to absolute paths using the current working directory. +// However, the working directory was previously not included in the crate hash. +// This meant that the crate metadata could change while the crate +// hash remained the same. Among other problems, this could cause a +// fingerprint mismatch ICE, since incremental compilation uses +// the crate metadata hash to determine if a foreign query is green. +// This test checks that we don't get an ICE when the working directory +// (but not the build directory!) changes between compilation +// sessions. +// See https://github.com/rust-lang/rust/issues/85019 + +//@ ignore-none +// Reason: no-std is not supported +//@ ignore-nvptx64-nvidia-cuda +// FIXME: can't find crate for 'std' + +use run_make_support::{fs_wrapper, rust_lib_name, rustc}; + +fn main() { + fs_wrapper::create_dir("incr"); + fs_wrapper::create_dir("first_src"); + fs_wrapper::create_dir("output"); + fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs"); + fs_wrapper::rename("main.rs", "first_src/main.rs"); + // Build from "first_src" + std::env::set_current_dir("first_src").unwrap(); + rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); + rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); + std::env::set_current_dir("..").unwrap(); + fs_wrapper::rename("first_src", "second_src"); + std::env::set_current_dir("second_src").unwrap(); + // Build from "second_src" - the output and incremental directory remain identical + rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); + rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); +} From f768db6ba6d8415fab3bd51ec85ebf41f2209f7e Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 5 Jul 2024 15:07:15 -0400 Subject: [PATCH 252/361] rewrite and rename issue-83045 to rmake --- .../a.rs | 0 .../b.rs | 0 .../c.rs | 0 .../run-make/ice-dep-cannot-find-dep/rmake.rs | 39 +++++++++++++++++++ tests/run-make/issue-83045/Makefile | 33 ---------------- 5 files changed, 39 insertions(+), 33 deletions(-) rename tests/run-make/{issue-83045 => ice-dep-cannot-find-dep}/a.rs (100%) rename tests/run-make/{issue-83045 => ice-dep-cannot-find-dep}/b.rs (100%) rename tests/run-make/{issue-83045 => ice-dep-cannot-find-dep}/c.rs (100%) create mode 100644 tests/run-make/ice-dep-cannot-find-dep/rmake.rs delete mode 100644 tests/run-make/issue-83045/Makefile diff --git a/tests/run-make/issue-83045/a.rs b/tests/run-make/ice-dep-cannot-find-dep/a.rs similarity index 100% rename from tests/run-make/issue-83045/a.rs rename to tests/run-make/ice-dep-cannot-find-dep/a.rs diff --git a/tests/run-make/issue-83045/b.rs b/tests/run-make/ice-dep-cannot-find-dep/b.rs similarity index 100% rename from tests/run-make/issue-83045/b.rs rename to tests/run-make/ice-dep-cannot-find-dep/b.rs diff --git a/tests/run-make/issue-83045/c.rs b/tests/run-make/ice-dep-cannot-find-dep/c.rs similarity index 100% rename from tests/run-make/issue-83045/c.rs rename to tests/run-make/ice-dep-cannot-find-dep/c.rs diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs new file mode 100644 index 000000000000..4256831a1eea --- /dev/null +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -0,0 +1,39 @@ +// This test case creates a situation where the crate loader would run +// into an ICE (internal compiler error) when confronted with an invalid setup where it cannot +// find the dependency of a direct dependency. +// +// The test case makes sure that the compiler produces the expected +// error message but does not ICE immediately after. +// +// See https://github.com/rust-lang/rust/issues/83045 + +//@ only-x86_64 +//@ only-linux +// Reason: This is a platform-independent issue, no need to waste time testing +// everywhere. + +// NOTE: We use `bare_rustc` below so that the compiler can't find liba.rlib +// If we used `rustc` the additional '-L rmake_out' option would allow rustc to +// actually find the crate. + +use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc}; + +fn main() { + rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run(); + rustc() + .crate_name("b") + .crate_type("rlib") + .extern_("a", rust_lib_name("a")) + .input("b.rs") + .arg("--verbose") + .run(); + fs_wrapper::create_dir("wrong_directory"); + bare_rustc() + .extern_("b", rust_lib_name("b")) + .crate_type("rlib") + .edition("2018") + .input("c.rs") + .run_fail() + .assert_stderr_contains("E0463") + .assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/issue-83045/Makefile b/tests/run-make/issue-83045/Makefile deleted file mode 100644 index b76e184b610c..000000000000 --- a/tests/run-make/issue-83045/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -include ../tools.mk - -# This test case creates a situation where the crate loader would run -# into an ICE when confronted with an invalid setup where it cannot -# find the dependency of a direct dependency. -# -# The test case makes sure that the compiler produces the expected -# error message but does not ICE immediately after. -# -# See https://github.com/rust-lang/rust/issues/83045 - -# This is a platform-independent issue, no need to waste time testing -# everywhere. -# only-x86_64 -# only-linux - -# NOTE: We use BARE_RUSTC below so that the compiler can't find liba.rlib -# If we used RUSTC the additional '-L TMPDIR' option would allow rustc to -# actually find the crate. -# -# We check that we get the expected error message -# But that we do not get an ICE - -all: - $(RUSTC) --crate-name=a --crate-type=rlib a.rs --verbose - $(RUSTC) --crate-name=b --crate-type=rlib --extern a=$(TMPDIR)/liba.rlib b.rs --verbose - $(BARE_RUSTC) --out-dir $(TMPDIR) \ - --extern b=$(TMPDIR)/libb.rlib \ - --crate-type=rlib \ - --edition=2018 \ - c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt - $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt From 87c7a42ba92d341c6d4a330a5d4c02b839158c1e Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 5 Jul 2024 15:14:55 -0400 Subject: [PATCH 253/361] rewrite rustc-macro-dep-files to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/rustc-macro-dep-files/Makefile | 11 ----------- tests/run-make/rustc-macro-dep-files/rmake.rs | 13 +++++++++++++ 3 files changed, 13 insertions(+), 12 deletions(-) delete mode 100644 tests/run-make/rustc-macro-dep-files/Makefile create mode 100644 tests/run-make/rustc-macro-dep-files/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 33120cf93f90..22edea79adf2 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -116,7 +116,6 @@ run-make/return-non-c-like-enum-from-c/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile -run-make/rustc-macro-dep-files/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile diff --git a/tests/run-make/rustc-macro-dep-files/Makefile b/tests/run-make/rustc-macro-dep-files/Makefile deleted file mode 100644 index 76d713c4bb3c..000000000000 --- a/tests/run-make/rustc-macro-dep-files/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` -# instead of hardcoding them everywhere they're needed. -ifeq ($(IS_MUSL_HOST),1) -ADDITIONAL_ARGS := $(RUSTFLAGS) -endif -all: - $(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR) - $(RUSTC) bar.rs --target $(TARGET) --emit dep-info - $(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs new file mode 100644 index 000000000000..b90e719b7d68 --- /dev/null +++ b/tests/run-make/rustc-macro-dep-files/rmake.rs @@ -0,0 +1,13 @@ +// --emit dep-info used to print all macro-generated code it could +// find as if it was part of a nonexistent file named "proc-macro source", +// which is not a valid path. After this was fixed in #36776, this test checks +// that macro code is not falsely seen as coming from a different file in dep-info. +// See https://github.com/rust-lang/rust/issues/36625 + +use run_make_support::{fs_wrapper, rustc, target}; + +fn main() { + rustc().input("foo.rs").run(); + rustc().input("bar.rs").target(target()).emit("dep-info").run(); + assert!(!fs_wrapper::read_to_string("bar.d").contains("proc-macro source")); +} From fe76650144a6da47583d50e6df8021bcf94e37d1 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 5 Jul 2024 15:26:29 -0400 Subject: [PATCH 254/361] rewrite env-dep-info to rmake --- src/tools/run-make-support/src/rustc.rs | 9 +++++--- .../tidy/src/allowed_run_make_makefiles.txt | 2 -- tests/run-make/env-dep-info/Makefile | 19 ----------------- tests/run-make/env-dep-info/correct_macro.d | 6 ++++++ tests/run-make/env-dep-info/correct_main.d | 8 +++++++ tests/run-make/env-dep-info/rmake.rs | 21 +++++++++++++++++++ .../run-make/ice-dep-cannot-find-dep/rmake.rs | 1 - .../run-make/rustc-macro-dep-files/correct.d | 3 +++ tests/run-make/rustc-macro-dep-files/rmake.rs | 5 +++-- 9 files changed, 47 insertions(+), 27 deletions(-) delete mode 100644 tests/run-make/env-dep-info/Makefile create mode 100644 tests/run-make/env-dep-info/correct_macro.d create mode 100644 tests/run-make/env-dep-info/correct_main.d create mode 100644 tests/run-make/env-dep-info/rmake.rs create mode 100644 tests/run-make/rustc-macro-dep-files/correct.d diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index a2a7c8064dca..ae200d514310 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -4,13 +4,15 @@ use std::path::Path; use crate::{command, cwd, env_var, set_host_rpath}; -/// Construct a new `rustc` invocation. +/// Construct a new `rustc` invocation. This will automatically set the library +/// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. #[track_caller] pub fn rustc() -> Rustc { Rustc::new() } -/// Construct a plain `rustc` invocation with no flags set. +/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_rpath`] +/// still presets the environment variable `HOST_RPATH_DIR` by default. #[track_caller] pub fn bare_rustc() -> Rustc { Rustc::bare() @@ -42,7 +44,8 @@ fn setup_common() -> Command { impl Rustc { // `rustc` invocation constructor methods - /// Construct a new `rustc` invocation. + /// Construct a new `rustc` invocation. This will automatically set the library + /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 22edea79adf2..b8e203fe0ea4 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile run-make/emit-to-stdout/Makefile -run-make/env-dep-info/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile @@ -58,7 +57,6 @@ run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile -run-make/issue-83045/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/issue-85019-moved-src-dir/Makefile run-make/issue-85401-static-mir/Makefile diff --git a/tests/run-make/env-dep-info/Makefile b/tests/run-make/env-dep-info/Makefile deleted file mode 100644 index bc0ffc2df1e0..000000000000 --- a/tests/run-make/env-dep-info/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -include ../tools.mk - -# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` -# instead of hardcoding them everywhere they're needed. -ifeq ($(IS_MUSL_HOST),1) -ADDITIONAL_ARGS := $(RUSTFLAGS) -endif - -all: - EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs - $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d - # Proc macro - $(BARE_RUSTC) $(ADDITIONAL_ARGS) --out-dir $(TMPDIR) macro_def.rs - EXISTING_PROC_MACRO_ENV=1 $(RUSTC) --emit dep-info macro_use.rs - $(CGREP) "# env-dep:EXISTING_PROC_MACRO_ENV=1" < $(TMPDIR)/macro_use.d - $(CGREP) "# env-dep:NONEXISTENT_PROC_MACEO_ENV" < $(TMPDIR)/macro_use.d diff --git a/tests/run-make/env-dep-info/correct_macro.d b/tests/run-make/env-dep-info/correct_macro.d new file mode 100644 index 000000000000..edfe0e632024 --- /dev/null +++ b/tests/run-make/env-dep-info/correct_macro.d @@ -0,0 +1,6 @@ +macro_use.d: macro_use.rs + +macro_use.rs: + +# env-dep:EXISTING_PROC_MACRO_ENV=1 +# env-dep:NONEXISTENT_PROC_MACEO_ENV diff --git a/tests/run-make/env-dep-info/correct_main.d b/tests/run-make/env-dep-info/correct_main.d new file mode 100644 index 000000000000..ef89729841d8 --- /dev/null +++ b/tests/run-make/env-dep-info/correct_main.d @@ -0,0 +1,8 @@ +main.d: main.rs + +main.rs: + +# env-dep:ESCAPE\nESCAPE\\ +# env-dep:EXISTING_ENV=1 +# env-dep:EXISTING_OPT_ENV=1 +# env-dep:NONEXISTENT_OPT_ENV diff --git a/tests/run-make/env-dep-info/rmake.rs b/tests/run-make/env-dep-info/rmake.rs new file mode 100644 index 000000000000..5b51a5476f49 --- /dev/null +++ b/tests/run-make/env-dep-info/rmake.rs @@ -0,0 +1,21 @@ +// Inside dep-info emit files, #71858 made it so all accessed environment +// variables are usefully printed. This test checks that this feature works +// as intended by checking if the environment variables used in compilation +// appear in the output dep-info files. +// See https://github.com/rust-lang/rust/issues/40364 + +use run_make_support::{diff, rustc}; + +fn main() { + rustc() + .env("EXISTING_ENV", "1") + .env("EXISTING_OPT_ENV", "1") + .emit("dep-info") + .input("main.rs") + .run(); + diff().expected_file("correct_main.d").actual_file("main.d").run(); + // Procedural macro + rustc().input("macro_def.rs").run(); + rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run(); + diff().expected_file("correct_macro.d").actual_file("macro_use.d").run(); +} diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs index 4256831a1eea..33c755bddd7b 100644 --- a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -27,7 +27,6 @@ fn main() { .input("b.rs") .arg("--verbose") .run(); - fs_wrapper::create_dir("wrong_directory"); bare_rustc() .extern_("b", rust_lib_name("b")) .crate_type("rlib") diff --git a/tests/run-make/rustc-macro-dep-files/correct.d b/tests/run-make/rustc-macro-dep-files/correct.d new file mode 100644 index 000000000000..8cb708fff61b --- /dev/null +++ b/tests/run-make/rustc-macro-dep-files/correct.d @@ -0,0 +1,3 @@ +bar.d: bar.rs + +bar.rs: diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs index b90e719b7d68..bc02a04c9b8f 100644 --- a/tests/run-make/rustc-macro-dep-files/rmake.rs +++ b/tests/run-make/rustc-macro-dep-files/rmake.rs @@ -4,10 +4,11 @@ // that macro code is not falsely seen as coming from a different file in dep-info. // See https://github.com/rust-lang/rust/issues/36625 -use run_make_support::{fs_wrapper, rustc, target}; +use run_make_support::{diff, rustc, target}; fn main() { rustc().input("foo.rs").run(); rustc().input("bar.rs").target(target()).emit("dep-info").run(); - assert!(!fs_wrapper::read_to_string("bar.d").contains("proc-macro source")); + // The emitted file should not contain "proc-macro source". + diff().expected_file("correct.d").actual_file("bar.d").run(); } From 1c8f9bb84d5956abe6671bf77ccaba64505266a5 Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 5 Jul 2024 17:24:10 -0400 Subject: [PATCH 255/361] fix interleaved panic output previously, we only held a lock for printing the backtrace itself. since all threads were printing to the same file descriptor, that meant random output in the default panic hook would be interleaved with the backtrace. now, we hold the lock for the full duration of the hook, and the output is ordered. --- library/std/src/panicking.rs | 8 ++- library/std/src/sys/backtrace.rs | 55 +++++++++---------- .../backtrace/synchronized-panic-handler.rs | 2 + .../synchronized-panic-handler.run.stderr | 8 +-- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ebd054156951..418a855fb728 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -253,16 +253,20 @@ fn default_hook(info: &PanicHookInfo<'_>) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut dyn crate::io::Write| { + // Use a lock to prevent mixed output in multithreading context. + // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. + let mut lock = backtrace::lock(); let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); match backtrace { + // SAFETY: we took out a lock just a second ago. Some(BacktraceStyle::Short) => { - drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Short)) + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short)) } Some(BacktraceStyle::Full) => { - drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full)) + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full)) } Some(BacktraceStyle::Off) => { if FIRST_PANIC.swap(false, Ordering::Relaxed) { diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index 0b2338fd7de9..7401d8ce3208 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -7,44 +7,41 @@ use crate::fmt; use crate::io; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; -use crate::sync::{Mutex, PoisonError}; +use crate::sync::{Mutex, MutexGuard, PoisonError}; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -pub fn lock() -> impl Drop { +pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>); + +pub(crate) fn lock<'a>() -> BacktraceLock<'a> { static LOCK: Mutex<()> = Mutex::new(()); - LOCK.lock().unwrap_or_else(PoisonError::into_inner) + BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner)) } -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - // There are issues currently linking libbacktrace into tests, and in - // general during std's own unit tests we're not testing this path. In - // test mode immediately return here to optimize away any references to the - // libbacktrace symbols - if cfg!(test) { - return Ok(()); - } - - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also requires it, like `SymFromAddr` on Windows. - unsafe { - let _lock = lock(); - _print(w, format) - } -} - -unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - struct DisplayBacktrace { - format: PrintFmt, - } - impl fmt::Display for DisplayBacktrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - unsafe { _print_fmt(fmt, self.format) } +impl BacktraceLock<'_> { + /// Prints the current backtrace. + /// + /// NOTE: this function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. + pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + // There are issues currently linking libbacktrace into tests, and in + // general during std's own unit tests we're not testing this path. In + // test mode immediately return here to optimize away any references to the + // libbacktrace symbols + if cfg!(test) { + return Ok(()); } + + struct DisplayBacktrace { + format: PrintFmt, + } + impl fmt::Display for DisplayBacktrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { _print_fmt(fmt, self.format) } + } + } + write!(w, "{}", DisplayBacktrace { format }) } - write!(w, "{}", DisplayBacktrace { format }) } unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs index 0ea285968d59..00eb249da1dd 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.rs +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ edition:2021 +//@ exec-env:RUST_BACKTRACE=0 +//@ needs-threads use std::thread; const PANIC_MESSAGE: &str = "oops oh no woe is me"; diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr index 06ef53836c26..b7c815a94c86 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.run.stderr +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -1,5 +1,5 @@ -thread '' panicked at $DIR/synchronized-panic-handler.rs:thread '8:5' panicked at : -oops oh no woe is me$DIR/synchronized-panic-handler.rs -:note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -8:5: +thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +oops oh no woe is me +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: oops oh no woe is me From 2772f897976f01133d22cd730d0eda5346efa73a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 12 Jul 2024 13:53:58 -0400 Subject: [PATCH 256/361] Rename the internal `const_strlen` to just `strlen` Since the libs and lang teams completed an FCP to allow for const `strlen` ([1]), currently implemented with `const_eval_select`, there is no longer any reason to avoid this specific function or use it only in const. Rename it to reflect this status change. [1]: https://github.com/rust-lang/rust/issues/113219#issuecomment-2016939401 --- library/core/src/ffi/c_str.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index dc2a5803a1b2..76752f22ed89 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -282,7 +282,7 @@ impl CStr { pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C // string with a NUL terminator less than `isize::MAX` from `ptr`. - let len = unsafe { const_strlen(ptr) }; + let len = unsafe { strlen(ptr) }; // SAFETY: The caller has provided a valid pointer with length less than // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid @@ -743,7 +743,7 @@ impl AsRef for CStr { #[unstable(feature = "cstr_internals", issue = "none")] #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] #[rustc_allow_const_fn_unstable(const_eval_select)] -const unsafe fn const_strlen(ptr: *const c_char) -> usize { +const unsafe fn strlen(ptr: *const c_char) -> usize { const fn strlen_ct(s: *const c_char) -> usize { let mut len = 0; From 1fd0311eabd9d1307b21eafd2a5e9227b91dfb9a Mon Sep 17 00:00:00 2001 From: sayantn Date: Fri, 12 Jul 2024 23:30:22 +0530 Subject: [PATCH 257/361] Added the `xop` target feature and `xop_target_feature` gate --- compiler/rustc_codegen_ssa/src/target_features.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 1 + tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- .../feature-gate-xop_target_feature.rs | 6 ++++++ .../feature-gate-xop_target_feature.stderr | 13 +++++++++++++ 8 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-xop_target_feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-xop_target_feature.stderr diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 22006c0b4712..cea164df6173 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -81,6 +81,7 @@ pub fn from_target_feature( Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, + Some(sym::xop_target_feature) => rust_features.xop_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index dfbe270822c0..5673101dc244 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -642,6 +642,8 @@ declare_features! ( (unstable, used_with_arg, "1.60.0", Some(93798)), /// Allows use of x86 `AMX` target-feature attributes and intrinsics (unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)), + /// Allows use of the `xop` target-feature + (unstable, xop_target_feature, "CURRENT_RUSTC_VERSION", Some(127208)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 827b9062d83a..2fe7c951793f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2076,6 +2076,7 @@ symbols! { x87_reg, xer, xmm_reg, + xop_target_feature, yeet_desugar_details, yeet_expr, yes, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index aec2828181b9..6667efb14e2d 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -246,6 +246,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("tbm", Unstable(sym::tbm_target_feature)), ("vaes", Unstable(sym::avx512_target_feature)), ("vpclmulqdq", Unstable(sym::avx512_target_feature)), + ("xop", Unstable(sym::xop_target_feature)), ("xsave", Stable), ("xsavec", Stable), ("xsaveopt", Stable), diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 15b0100d7d23..00a97ca1488a 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 196 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 197 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index c35fb68c839d..78b7f0f5d997 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/feature-gates/feature-gate-xop_target_feature.rs b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs new file mode 100644 index 000000000000..3032a6fbb475 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "xop")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr new file mode 100644 index 000000000000..58f7b0b3b002 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `xop` is currently unstable + --> $DIR/feature-gate-xop_target_feature.rs:2:18 + | +LL | #[target_feature(enable = "xop")] + | ^^^^^^^^^^^^^^ + | + = note: see issue #127208 for more information + = help: add `#![feature(xop_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 a45c12cf0f994409309b8099bf5de52b392fb061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Fri, 12 Jul 2024 20:09:29 +0200 Subject: [PATCH 258/361] Stabilize io_slice_advance --- library/std/src/io/mod.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 97b72f9664bb..b464461277a0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1256,8 +1256,6 @@ impl<'a> IoSliceMut<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSliceMut; /// use std::ops::Deref; /// @@ -1268,7 +1266,7 @@ impl<'a> IoSliceMut<'a> { /// buf.advance(3); /// assert_eq!(buf.deref(), [1; 5].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance(&mut self, n: usize) { self.0.advance(n) @@ -1290,8 +1288,6 @@ impl<'a> IoSliceMut<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSliceMut; /// use std::ops::Deref; /// @@ -1309,7 +1305,7 @@ impl<'a> IoSliceMut<'a> { /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) { // Number of buffers to remove. @@ -1400,8 +1396,6 @@ impl<'a> IoSlice<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSlice; /// use std::ops::Deref; /// @@ -1412,7 +1406,7 @@ impl<'a> IoSlice<'a> { /// buf.advance(3); /// assert_eq!(buf.deref(), [1; 5].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance(&mut self, n: usize) { self.0.advance(n) @@ -1434,8 +1428,6 @@ impl<'a> IoSlice<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSlice; /// use std::ops::Deref; /// @@ -1452,7 +1444,7 @@ impl<'a> IoSlice<'a> { /// IoSlice::advance_slices(&mut bufs, 10); /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) { // Number of buffers to remove. From 97990a475928cb7428ed945342cec70a4e19c3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 15:47:30 +0200 Subject: [PATCH 259/361] Move `DropBomb` from `run-make-support` to `build_helper` So that it can be also used in bootstrap. --- Cargo.lock | 1 + .../src/drop_bomb/mod.rs | 8 ++++---- .../src/drop_bomb/tests.rs | 0 src/tools/build_helper/src/lib.rs | 1 + src/tools/run-make-support/Cargo.toml | 2 ++ src/tools/run-make-support/src/command.rs | 2 +- src/tools/run-make-support/src/diff/mod.rs | 2 +- src/tools/run-make-support/src/lib.rs | 1 - 8 files changed, 10 insertions(+), 7 deletions(-) rename src/tools/{run-make-support => build_helper}/src/drop_bomb/mod.rs (88%) rename src/tools/{run-make-support => build_helper}/src/drop_bomb/tests.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index eba4eed3686b..cafc623c185a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3420,6 +3420,7 @@ version = "0.2.0" dependencies = [ "ar", "bstr", + "build_helper", "gimli 0.28.1", "object 0.34.0", "regex", diff --git a/src/tools/run-make-support/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs similarity index 88% rename from src/tools/run-make-support/src/drop_bomb/mod.rs rename to src/tools/build_helper/src/drop_bomb/mod.rs index 2fc84892c1bd..ffb86d1c9eef 100644 --- a/src/tools/run-make-support/src/drop_bomb/mod.rs +++ b/src/tools/build_helper/src/drop_bomb/mod.rs @@ -12,7 +12,7 @@ use std::panic; mod tests; #[derive(Debug)] -pub(crate) struct DropBomb { +pub struct DropBomb { command: OsString, defused: bool, armed_line: u32, @@ -21,9 +21,9 @@ pub(crate) struct DropBomb { impl DropBomb { /// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then /// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help - /// propagate the caller info from rmake.rs. + /// propagate the caller location. #[track_caller] - pub(crate) fn arm>(command: S) -> DropBomb { + pub fn arm>(command: S) -> DropBomb { DropBomb { command: command.as_ref().into(), defused: false, @@ -32,7 +32,7 @@ impl DropBomb { } /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped. - pub(crate) fn defuse(&mut self) { + pub fn defuse(&mut self) { self.defused = true; } } diff --git a/src/tools/run-make-support/src/drop_bomb/tests.rs b/src/tools/build_helper/src/drop_bomb/tests.rs similarity index 100% rename from src/tools/run-make-support/src/drop_bomb/tests.rs rename to src/tools/build_helper/src/drop_bomb/tests.rs diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 15807d1c0d8f..4a4f0ca2a9d4 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,6 +1,7 @@ //! Types and functions shared across tools in this workspace. pub mod ci; +pub mod drop_bomb; pub mod git; pub mod metrics; pub mod stage0_parser; diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index ec3b8a96ef3b..969552dec84a 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -11,3 +11,5 @@ wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.28.1" ar = "0.9.0" + +build_helper = { path = "../build_helper" } diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index c506c3d6b61a..5017a4b88dad 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -5,8 +5,8 @@ use std::panic; use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; -use crate::drop_bomb::DropBomb; use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output}; +use build_helper::drop_bomb::DropBomb; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 24fa88af82ec..ad989b74e4d9 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -2,8 +2,8 @@ use regex::Regex; use similar::TextDiff; use std::path::{Path, PathBuf}; -use crate::drop_bomb::DropBomb; use crate::fs_wrapper; +use build_helper::drop_bomb::DropBomb; #[cfg(test)] mod tests; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5655318267a2..cb61aa7516de 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -7,7 +7,6 @@ pub mod cc; pub mod clang; mod command; pub mod diff; -mod drop_bomb; pub mod fs_wrapper; pub mod llvm; pub mod run; From 49f54b8ee8c8ac04e53d30832d52b0b06e43540b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 15:51:21 +0200 Subject: [PATCH 260/361] Configure test execution for the `build_helper` crate in bootstrap To enable the previously moved `DropBomb` tests. --- src/bootstrap/src/core/build_steps/test.rs | 47 ++++++++++++++++++++++ src/bootstrap/src/core/builder.rs | 1 + 2 files changed, 48 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0b60587bb792..a27d1a59beb6 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1352,6 +1352,53 @@ impl Step for CrateRunMakeSupport { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateBuildHelper { + host: TargetSelection, +} + +impl Step for CrateBuildHelper { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build_helper") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CrateBuildHelper { host: run.target }); + } + + /// Runs `cargo test` for build_helper. + fn run(self, builder: &Builder<'_>) { + let host = self.host; + let compiler = builder.compiler(builder.top_stage, host); + + builder.ensure(compile::Std::new(compiler, host)); + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + host, + "test", + "src/tools/build_helper", + SourceType::InTree, + &[], + ); + cargo.allow_features("test"); + run_cargo_test( + cargo, + &[], + &[], + "build_helper", + "build_helper self test", + compiler, + host, + builder, + ); + } +} + default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 65cc1fa74782..fd5ddc6d2e60 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -860,6 +860,7 @@ impl<'a> Builder<'a> { test::Clippy, test::CompiletestTest, test::CrateRunMakeSupport, + test::CrateBuildHelper, test::RustdocJSStd, test::RustdocJSNotStd, test::RustdocGUI, From 042473fd13eaa51eb795dfb643b7660fb8d653a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 15:56:16 +0200 Subject: [PATCH 261/361] Store full arm location in `DropBomb` Before, only the line was stored. This was enough for run-make tests, since these mostly only contain a single `rmake.rs` file, but not for bootstrap. --- src/tools/build_helper/src/drop_bomb/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs index ffb86d1c9eef..854113a5181a 100644 --- a/src/tools/build_helper/src/drop_bomb/mod.rs +++ b/src/tools/build_helper/src/drop_bomb/mod.rs @@ -15,7 +15,7 @@ mod tests; pub struct DropBomb { command: OsString, defused: bool, - armed_line: u32, + armed_location: panic::Location<'static>, } impl DropBomb { @@ -27,7 +27,7 @@ impl DropBomb { DropBomb { command: command.as_ref().into(), defused: false, - armed_line: panic::Location::caller().line(), + armed_location: *panic::Location::caller(), } } @@ -41,8 +41,8 @@ impl Drop for DropBomb { fn drop(&mut self) { if !self.defused && !std::thread::panicking() { panic!( - "command constructed but not executed at line {}: `{}`", - self.armed_line, + "command constructed but not executed at {}: `{}`", + self.armed_location, self.command.to_string_lossy() ) } From a1626d709cba2ff9508fe4fccba04110e5a87c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 16:13:33 +0200 Subject: [PATCH 262/361] Make `command` field of `BootstrapCommand` private to force access to it through the `as_command_mut` method This will be useful for disarming drop bombs when the inner command is accessed. --- src/bootstrap/src/core/build_steps/compile.rs | 3 ++- src/bootstrap/src/core/build_steps/llvm.rs | 4 ++-- src/bootstrap/src/core/build_steps/setup.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- .../src/core/build_steps/toolstate.rs | 23 +++++++++++-------- src/bootstrap/src/core/builder.rs | 2 +- src/bootstrap/src/core/config/config.rs | 16 ++++++------- src/bootstrap/src/core/sanity.rs | 2 +- src/bootstrap/src/lib.rs | 23 +++++++++++-------- src/bootstrap/src/utils/channel.rs | 9 ++++---- src/bootstrap/src/utils/exec.rs | 8 ++++++- src/bootstrap/src/utils/helpers.rs | 2 +- src/bootstrap/src/utils/render_tests.rs | 2 +- src/bootstrap/src/utils/tarball.rs | 4 ++-- 14 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11a7a4045351..188426a4ecfe 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2080,7 +2080,8 @@ pub fn stream_cargo( tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { - let mut cargo = cargo.into_cmd().command; + let mut cmd = cargo.into_cmd(); + let cargo = cmd.as_command_mut(); // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 872823506f88..41dff2123f13 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -172,7 +172,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` config.src.join("src/version"), ]); - output(&mut rev_list.command).trim().to_owned() + output(rev_list.as_command_mut()).trim().to_owned() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { @@ -254,7 +254,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { // `true` here. let llvm_sha = detect_llvm_sha(config, true); let head_sha = - output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command); + output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut()); let head_sha = head_sha.trim(); llvm_sha == head_sha } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index e6a09e8cb8e8..29cc5e00637e 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -484,7 +484,7 @@ impl Step for Hook { fn install_git_hook_maybe(config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) .args(["rev-parse", "--git-common-dir"]) - .command + .as_command_mut() .output() .map(|output| { assert!(output.status.success(), "failed to run `git`"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a27d1a59beb6..735706758703 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2105,7 +2105,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--nightly-branch").arg(git_config.nightly_branch); // FIXME: Move CiEnv back to bootstrap, it is only used here anyway - builder.ci_env.force_coloring_in_ci(&mut cmd.command); + builder.ci_env.force_coloring_in_ci(cmd.as_command_mut()); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index e3e7931a5a2a..9ddd68da59d1 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -106,7 +106,7 @@ fn check_changed_files(toolstates: &HashMap, ToolState>) { .arg("--name-status") .arg("HEAD") .arg("HEAD^") - .command + .as_command_mut() .output(); let output = match output { Ok(o) => o, @@ -329,7 +329,7 @@ fn checkout_toolstate_repo() { .arg("--depth=1") .arg(toolstate_repo()) .arg(TOOLSTATE_DIR) - .command + .as_command_mut() .status(); let success = match status { Ok(s) => s.success(), @@ -343,8 +343,13 @@ fn checkout_toolstate_repo() { /// Sets up config and authentication for modifying the toolstate repo. fn prepare_toolstate_config(token: &str) { fn git_config(key: &str, value: &str) { - let status = - helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status(); + let status = helpers::git(None) + .arg("config") + .arg("--global") + .arg(key) + .arg(value) + .as_command_mut() + .status(); let success = match status { Ok(s) => s.success(), Err(_) => false, @@ -413,7 +418,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("-a") .arg("-m") .arg(&message) - .command + .as_command_mut() .status()); if !status.success() { success = true; @@ -424,7 +429,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("push") .arg("origin") .arg("master") - .command + .as_command_mut() .status()); // If we successfully push, exit. if status.success() { @@ -437,14 +442,14 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("fetch") .arg("origin") .arg("master") - .command + .as_command_mut() .status()); assert!(status.success()); let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") - .command + .as_command_mut() .status()); assert!(status.success()); } @@ -460,7 +465,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output()); + let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").as_command_mut().output()); let commit = t!(String::from_utf8(commit.stdout)); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index fd5ddc6d2e60..b14a0c5f072c 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2105,7 +2105,7 @@ impl<'a> Builder<'a> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - self.ci_env.force_coloring_in_ci(&mut cargo.command); + self.ci_env.force_coloring_in_ci(cargo.as_command_mut()); // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 3327df972bf8..11207cf89354 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1259,7 +1259,7 @@ impl Config { cmd.arg("rev-parse").arg("--show-cdup"); // Discard stderr because we expect this to fail when building from a tarball. let output = cmd - .command + .as_command_mut() .stderr(std::process::Stdio::null()) .output() .ok() @@ -2163,7 +2163,7 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); - output(&mut git.command) + output(git.as_command_mut()) } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -2469,11 +2469,11 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - &mut helpers::git(Some(&self.src)) + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]) - .command, + .as_command_mut(), ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2489,7 +2489,7 @@ impl Config { .args(["diff-index", "--quiet", commit]) .arg("--") .args([self.src.join("compiler"), self.src.join("library")]) - .command + .as_command_mut() .status()) .success(); if has_changes { @@ -2563,11 +2563,11 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - &mut helpers::git(Some(&self.src)) + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]) - .command, + .as_command_mut(), ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2589,7 +2589,7 @@ impl Config { git.arg(top_level.join(path)); } - let has_changes = !t!(git.command.status()).success(); + let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { if if_unchanged { if self.verbose > 0 { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 9995da3a1e5b..4bdc8ac07958 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -209,7 +209,7 @@ than building it. #[cfg(not(feature = "bootstrap-self-test"))] let stage0_supported_target_list: HashSet = crate::utils::helpers::output( - &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command, + command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(), ) .lines() .map(|s| s.to_string()) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index f16afb297965..b79e1badb2a9 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -493,11 +493,14 @@ impl Build { let submodule_git = || helpers::git(Some(&absolute_path)); // Determine commit checked out in submodule. - let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command); + let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut()); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. let recorded = output( - &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command, + helpers::git(Some(&self.src)) + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .as_command_mut(), ); let actual_hash = recorded .split_whitespace() @@ -522,7 +525,7 @@ impl Build { let current_branch = { let output = helpers::git(Some(&self.src)) .args(["symbolic-ref", "--short", "HEAD"]) - .command + .as_command_mut() .stderr(Stdio::inherit()) .output(); let output = t!(output); @@ -548,7 +551,7 @@ impl Build { git }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. - if !update(true).command.status().map_or(false, |status| status.success()) { + if !update(true).as_command_mut().status().map_or(false, |status| status.success()) { update(false).run(self); } @@ -941,10 +944,12 @@ impl Build { self.verbose(|| println!("running: {command:?}")); - command.command.stdout(command.stdout.stdio()); - command.command.stderr(command.stderr.stdio()); + let stdout = command.stdout.stdio(); + command.as_command_mut().stdout(stdout); + let stderr = command.stderr.stdio(); + command.as_command_mut().stderr(stderr); - let output = command.command.output(); + let output = command.as_command_mut().output(); use std::fmt::Write; @@ -1931,7 +1936,7 @@ fn envify(s: &str) -> String { pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { let diff = helpers::git(Some(dir)) .arg("diff") - .command + .as_command_mut() .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); @@ -1941,7 +1946,7 @@ pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .command + .as_command_mut() .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 2ca86bdb0ed2..8d5328c95eb2 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -45,7 +45,7 @@ impl GitInfo { } // Make sure git commands work - match helpers::git(Some(dir)).arg("rev-parse").command.output() { + match helpers::git(Some(dir)).arg("rev-parse").as_command_mut().output() { Ok(ref out) if out.status.success() => {} _ => return GitInfo::Absent, } @@ -63,11 +63,12 @@ impl GitInfo { .arg("-1") .arg("--date=short") .arg("--pretty=format:%cd") - .command, + .as_command_mut(), ); - let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command); + let ver_hash = + output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); let short_ver_hash = output( - &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command, + helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(), ); GitInfo::Present(Some(Info { commit_date: ver_date.trim().to_string(), diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index ba963f52dc2b..09801a05fa36 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -55,7 +55,7 @@ impl OutputMode { /// [delay_failure]: BootstrapCommand::delay_failure #[derive(Debug)] pub struct BootstrapCommand { - pub command: Command, + command: Command, pub failure_behavior: BehaviorOnFailure, pub stdout: OutputMode, pub stderr: OutputMode, @@ -145,6 +145,12 @@ impl BootstrapCommand { pub fn run(&mut self, builder: &Build) -> CommandOutput { builder.run(self) } + + /// Provides access to the stdlib Command inside. + /// All usages of this function should be eventually removed from bootstrap. + pub fn as_command_mut(&mut self) -> &mut Command { + &mut self.command + } } impl From for BootstrapCommand { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 5dd3ba96786c..fd8aee37d900 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -244,7 +244,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( // FIXME: get rid of this function pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { - let status = match cmd.command.status() { + let status = match cmd.as_command_mut().status() { Ok(status) => status, Err(e) => { println!("failed to execute command: {cmd:?}\nERROR: {e}"); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 2e99bc68a8b7..3a5776bdfe0d 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -50,7 +50,7 @@ pub(crate) fn try_run_tests( } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - let cmd = &mut cmd.command; + let cmd = cmd.as_command_mut(); cmd.stdout(Stdio::piped()); builder.verbose(|| println!("running: {cmd:?}")); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 4f0104e4bbab..f5fc94273c9a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -370,11 +370,11 @@ impl<'a> Tarball<'a> { if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date let timestamp = helpers::output( - &mut helpers::git(Some(&self.builder.src)) + helpers::git(Some(&self.builder.src)) .arg("log") .arg("-1") .arg("--format=%ct") - .command, + .as_command_mut(), ); cmd.args(["--override-file-mtime", timestamp.trim()]); } From cefd5b38348d129f657597f741dcb45cf2ca44b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 16:15:59 +0200 Subject: [PATCH 263/361] Add `DropBomb` to `BootstrapCommand` This makes it harder to accidentally forget to execute a created command in bootstrap. --- src/bootstrap/src/lib.rs | 1 + src/bootstrap/src/utils/exec.rs | 18 ++++++++++++++++++ src/bootstrap/src/utils/helpers.rs | 1 + 3 files changed, 20 insertions(+) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index b79e1badb2a9..4a69068b51e7 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -938,6 +938,7 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. fn run(&self, command: &mut BootstrapCommand) -> CommandOutput { + command.mark_as_executed(); if self.config.dry_run() && !command.run_always { return CommandOutput::default(); } diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 09801a05fa36..a9291d45f216 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,5 @@ use crate::Build; +use build_helper::drop_bomb::DropBomb; use std::ffi::OsStr; use std::path::Path; use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; @@ -61,9 +62,13 @@ pub struct BootstrapCommand { pub stderr: OutputMode, // Run the command even during dry run pub run_always: bool, + // This field makes sure that each command is executed (or disarmed) before it is dropped, + // to avoid forgetting to execute a command. + drop_bomb: DropBomb, } impl BootstrapCommand { + #[track_caller] pub fn new>(program: S) -> Self { Command::new(program).into() } @@ -149,18 +154,30 @@ impl BootstrapCommand { /// Provides access to the stdlib Command inside. /// All usages of this function should be eventually removed from bootstrap. pub fn as_command_mut(&mut self) -> &mut Command { + // We don't know what will happen with the returned command, so we need to mark this + // command as executed proactively. + self.mark_as_executed(); &mut self.command } + + /// Mark the command as being executd, disarming the drop bomb. + /// If this method is not called before the command is dropped, its drop will panic. + pub fn mark_as_executed(&mut self) { + self.drop_bomb.defuse(); + } } impl From for BootstrapCommand { + #[track_caller] fn from(command: Command) -> Self { + let program = command.get_program().to_owned(); Self { command, failure_behavior: BehaviorOnFailure::Exit, stdout: OutputMode::Print, stderr: OutputMode::Print, run_always: false, + drop_bomb: DropBomb::arm(program), } } } @@ -175,6 +192,7 @@ enum CommandStatus { /// Create a new BootstrapCommand. This is a helper function to make command creation /// shorter than `BootstrapCommand::new`. +#[track_caller] #[must_use] pub fn command>(program: S) -> BootstrapCommand { BootstrapCommand::new(program) diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index fd8aee37d900..f695b3229fe6 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -501,6 +501,7 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { /// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every /// git command creation, which is painful to ensure that the required change is applied /// on each one of them correctly. +#[track_caller] pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { let mut git = command("git"); From 542344f5bb32a8593b4d775d351d3f4fc8e55fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 20:24:37 +0200 Subject: [PATCH 264/361] Print command creation and execution location when it fails This should make it quicker to debug command failures. --- src/bootstrap/src/lib.rs | 15 ++++++++++++--- src/bootstrap/src/utils/exec.rs | 8 +++++++- src/tools/build_helper/src/drop_bomb/mod.rs | 4 ++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 4a69068b51e7..10ec7d135f0c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -937,13 +937,19 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. + #[track_caller] fn run(&self, command: &mut BootstrapCommand) -> CommandOutput { command.mark_as_executed(); if self.config.dry_run() && !command.run_always { return CommandOutput::default(); } - self.verbose(|| println!("running: {command:?}")); + let created_at = command.get_created_location(); + let executed_at = std::panic::Location::caller(); + + self.verbose(|| { + println!("running: {command:?} (created at {created_at}, executed at {executed_at})") + }); let stdout = command.stdout.stdio(); command.as_command_mut().stdout(stdout); @@ -962,8 +968,11 @@ impl Build { Ok(output) => { writeln!( message, - "\n\nCommand {command:?} did not execute successfully.\ - \nExpected success, got: {}", + r#" +Command {command:?} did not execute successfully. +Expected success, got {} +Created at: {created_at} +Executed at: {executed_at}"#, output.status, ) .unwrap(); diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index a9291d45f216..38fc0cf70b5c 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -160,17 +160,23 @@ impl BootstrapCommand { &mut self.command } - /// Mark the command as being executd, disarming the drop bomb. + /// Mark the command as being executed, disarming the drop bomb. /// If this method is not called before the command is dropped, its drop will panic. pub fn mark_as_executed(&mut self) { self.drop_bomb.defuse(); } + + /// Returns the source code location where this command was created. + pub fn get_created_location(&self) -> std::panic::Location<'static> { + self.drop_bomb.get_created_location() + } } impl From for BootstrapCommand { #[track_caller] fn from(command: Command) -> Self { let program = command.get_program().to_owned(); + Self { command, failure_behavior: BehaviorOnFailure::Exit, diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs index 854113a5181a..2dd4a6bee26b 100644 --- a/src/tools/build_helper/src/drop_bomb/mod.rs +++ b/src/tools/build_helper/src/drop_bomb/mod.rs @@ -31,6 +31,10 @@ impl DropBomb { } } + pub fn get_created_location(&self) -> panic::Location<'static> { + self.armed_location + } + /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped. pub fn defuse(&mut self) { self.defused = true; From fdf1477221ae7a504d6616b001f3edb6c4c50c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 20:32:03 +0200 Subject: [PATCH 265/361] Improve the `Debug` representation of `BootstrapCommand` Avoid printing useless information in the `Debug` output. --- src/bootstrap/src/utils/exec.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 38fc0cf70b5c..c8457f2d0c90 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,6 +1,7 @@ use crate::Build; use build_helper::drop_bomb::DropBomb; use std::ffi::OsStr; +use std::fmt::{Debug, Formatter}; use std::path::Path; use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; @@ -54,7 +55,6 @@ impl OutputMode { /// /// [allow_failure]: BootstrapCommand::allow_failure /// [delay_failure]: BootstrapCommand::delay_failure -#[derive(Debug)] pub struct BootstrapCommand { command: Command, pub failure_behavior: BehaviorOnFailure, @@ -147,6 +147,7 @@ impl BootstrapCommand { } /// Run the command, returning its output. + #[track_caller] pub fn run(&mut self, builder: &Build) -> CommandOutput { builder.run(self) } @@ -172,6 +173,17 @@ impl BootstrapCommand { } } +impl Debug for BootstrapCommand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.command)?; + write!( + f, + " (failure_mode={:?}, stdout_mode={:?}, stderr_mode={:?})", + self.failure_behavior, self.stdout, self.stderr + ) + } +} + impl From for BootstrapCommand { #[track_caller] fn from(command: Command) -> Self { From 9634633889a48d1d565ce22cc0b577addd2ab32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 11:57:45 +0200 Subject: [PATCH 266/361] Improve error message of drop bombs --- src/tools/build_helper/src/drop_bomb/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs index 2dd4a6bee26b..0a5bb04b55b3 100644 --- a/src/tools/build_helper/src/drop_bomb/mod.rs +++ b/src/tools/build_helper/src/drop_bomb/mod.rs @@ -45,7 +45,7 @@ impl Drop for DropBomb { fn drop(&mut self) { if !self.defused && !std::thread::panicking() { panic!( - "command constructed but not executed at {}: `{}`", + "command constructed at `{}` was dropped without being executed: `{}`", self.armed_location, self.command.to_string_lossy() ) From 8ee18d600f962df67e831da4d07cc556cff39526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 13:28:14 +0200 Subject: [PATCH 267/361] Fix a case where a RustBook command is potentially not executed We can move the command creation to a block where it is clear that the command will be executed. --- src/bootstrap/src/core/build_steps/doc.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 4b35d6c5d4c9..d1080775efe5 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -146,7 +146,6 @@ impl Step for RustbookSrc

{ let out = out.join(&name); let index = out.join("index.html"); let rustbook = builder.tool_exe(Tool::Rustbook); - let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); if !builder.config.dry_run() && (!up_to_date(&src, &index) || !up_to_date(&rustbook, &index)) @@ -154,7 +153,13 @@ impl Step for RustbookSrc

{ builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); + builder + .tool_cmd(Tool::Rustbook) + .arg("build") + .arg(&src) + .arg("-d") + .arg(&out) + .run(builder); for lang in &self.languages { let out = out.join(lang); From ebb30890388d3a569de823d1278a0aa467847d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 13:42:33 +0200 Subject: [PATCH 268/361] Remove unused rustdoc command --- src/bootstrap/src/core/build_steps/doc.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index d1080775efe5..dc46af6cf486 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -258,10 +258,6 @@ impl Step for TheBook { // build the version info page and CSS let shared_assets = builder.ensure(SharedAssets { target }); - // build the command first so we don't nest GHA groups - // FIXME: this doesn't do anything! - builder.rustdoc_cmd(compiler); - // build the redirect pages let _guard = builder.msg_doc(compiler, "book redirect pages", target); for file in t!(fs::read_dir(redirect_path)) { From 0cab9626f416f0f6bcf65221a3ed8ee38e69e97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 16:59:14 +0200 Subject: [PATCH 269/361] Disarm drop bombs for unexecuted test Cargo commands The code for running tests uses a custom command machinery because it streams the output of the command. We thus need to mark the command as executed in a dry run, to avoid a drop bomb panic. --- src/bootstrap/src/utils/channel.rs | 2 +- src/bootstrap/src/utils/render_tests.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 8d5328c95eb2..f8bcb584991a 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -58,7 +58,7 @@ impl GitInfo { // Ok, let's scrape some info let ver_date = output( - &mut helpers::git(Some(dir)) + helpers::git(Some(dir)) .arg("log") .arg("-1") .arg("--date=short") diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 3a5776bdfe0d..a3d0d36e7547 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -33,6 +33,7 @@ pub(crate) fn try_run_tests( stream: bool, ) -> bool { if builder.config.dry_run() { + cmd.mark_as_executed(); return true; } From 1089de43394aace6ea7e88bd2bb3b7546a7883fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 18:26:15 +0200 Subject: [PATCH 270/361] Simplify command executions for plain source tarballs If we're in dry run mode, the command will return an empty string, so we can just execute it. --- src/bootstrap/src/core/build_steps/dist.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7bc5405e92f9..aebec60112fb 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1060,11 +1060,7 @@ impl Step for PlainSourceTarball { cmd.arg("--sync").arg(manifest_path); } - let config = if !builder.config.dry_run() { - cmd.capture().run(builder).stdout() - } else { - String::new() - }; + let config = cmd.capture().run(builder).stdout(); let cargo_config_dir = plain_dst_src.join(".cargo"); builder.create_dir(&cargo_config_dir); From 823ea0e9879c234ba9a9a50082180cec8d0634df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 12 Jul 2024 17:06:33 +0200 Subject: [PATCH 271/361] Modify FIXME comment --- src/bootstrap/src/utils/exec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index c8457f2d0c90..b05301649973 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -153,7 +153,7 @@ impl BootstrapCommand { } /// Provides access to the stdlib Command inside. - /// All usages of this function should be eventually removed from bootstrap. + /// FIXME: This function should be eventually removed from bootstrap. pub fn as_command_mut(&mut self) -> &mut Command { // We don't know what will happen with the returned command, so we need to mark this // command as executed proactively. From 72c354094d993ae65b9f292d3cb30c98f277e441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 12 Jul 2024 17:49:01 +0200 Subject: [PATCH 272/361] Test `build_helper` with the stage 0 compiler There is no need to build a stage N toolchain for testing it. --- src/bootstrap/src/core/build_steps/test.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 735706758703..e49c2cbe17b1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1372,13 +1372,12 @@ impl Step for CrateBuildHelper { /// Runs `cargo test` for build_helper. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(builder.top_stage, host); + let compiler = builder.compiler(0, host); - builder.ensure(compile::Std::new(compiler, host)); let mut cargo = tool::prepare_tool_cargo( builder, compiler, - Mode::ToolStd, + Mode::ToolBootstrap, host, "test", "src/tools/build_helper", From 776b0adaafa2198caa0ef6485e3e78a43620a58b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 12 Jul 2024 14:48:42 +0200 Subject: [PATCH 273/361] Fix incorrect NDEBUG handling in LLVM bindings We currently compile our LLVM bindings using `-DNDEBUG` if debuginfo for LLVM is disabled. However, `NDEBUG` doesn't have any relation to debuginfo, it controls whether assertions are enabled. Rename the environment variable to `LLVM_ASSERTIONS` and drive it using the `llvm_assertions` option. Also drop the explicit `debug(false)` call, as cc already sets this up using the cargo `DEBUG` environment variable. --- compiler/rustc_llvm/build.rs | 3 +-- src/bootstrap/src/core/build_steps/compile.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 3aa852c83045..4c1f78e6bee3 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -197,9 +197,8 @@ fn main() { cfg.define("LLVM_RUSTLLVM", None); } - if tracked_env_var_os("LLVM_NDEBUG").is_some() { + if tracked_env_var_os("LLVM_ASSERTIONS").is_none() { cfg.define("NDEBUG", None); - cfg.debug(false); } rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11a7a4045351..714a10042815 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1213,8 +1213,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_use_libcxx { cargo.env("LLVM_USE_LIBCXX", "1"); } - if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { - cargo.env("LLVM_NDEBUG", "1"); + if builder.config.llvm_assertions { + cargo.env("LLVM_ASSERTIONS", "1"); } } From 8dfd3a455dc7d309f0c82dcb2e2f41da14f6c4af Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 12 Jul 2024 14:52:26 +0200 Subject: [PATCH 274/361] Remove LLVMRustDIBuilderInsertDeclareAtEnd return value The return value changed from an Instruction to a DbgRecord in LLVM 19. As we don't actually use the result, drop the return value entirely to support both. --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 08e9e312827c..e0bf6110cdf0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2057,7 +2057,7 @@ extern "C" { AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, - ) -> &'a Value; + ); pub fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b6790b7df500..14757b27a375 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1137,20 +1137,15 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, Builder->getOrCreateArray(ArrayRef(DataValue, Count)).get()); } -extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( +extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { - auto Result = Builder->insertDeclare( - unwrap(V), unwrap(VarInfo), - Builder->createExpression( - llvm::ArrayRef(AddrOps, AddrOpsCount)), - DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd)); -#if LLVM_VERSION_GE(19, 0) - return wrap(Result.get()); -#else - return wrap(Result); -#endif + Builder->insertDeclare(unwrap(V), unwrap(VarInfo), + Builder->createExpression( + llvm::ArrayRef(AddrOps, AddrOpsCount)), + DebugLoc(cast(unwrap(DL))), + unwrap(InsertAtEnd)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( From 7fc69436a1226b254b3b6f9ed8c6d54965e0cfbf Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 12 Jul 2024 13:49:41 -0400 Subject: [PATCH 275/361] Use ManuallyDrop in BufWriter::into_parts --- library/std/src/io/buffered/bufwriter.rs | 14 +++++++------- library/std/src/io/buffered/tests.rs | 10 ++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 2d13230ffbab..1768bb05ddbc 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -3,7 +3,7 @@ use crate::fmt; use crate::io::{ self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, }; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::ptr; /// Wraps a writer and buffers its output. @@ -164,13 +164,13 @@ impl BufWriter { /// assert_eq!(&buffered_data.unwrap(), b"ata"); /// ``` #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] - pub fn into_parts(mut self) -> (W, Result, WriterPanicked>) { - let buf = mem::take(&mut self.buf); - let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; + pub fn into_parts(self) -> (W, Result, WriterPanicked>) { + let mut this = ManuallyDrop::new(self); + let buf = mem::take(&mut this.buf); + let buf = if !this.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; - // SAFETY: forget(self) prevents double dropping inner - let inner = unsafe { ptr::read(&self.inner) }; - mem::forget(self); + // SAFETY: double-drops are prevented by putting `this` in a ManuallyDrop that is never dropped + let inner = unsafe { ptr::read(&this.inner) }; (inner, buf) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index ee0db30e22c2..ab66deaf31d2 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1067,3 +1067,13 @@ fn bufreader_full_initialize() { // But we initialized the whole buffer! assert_eq!(reader.initialized(), reader.capacity()); } + +/// This is a regression test for https://github.com/rust-lang/rust/issues/127584. +#[test] +fn bufwriter_aliasing() { + use crate::io::{BufWriter, Cursor}; + let mut v = vec![0; 1024]; + let c = Cursor::new(&mut v); + let w = BufWriter::new(Box::new(c)); + let _ = w.into_parts(); +} From 163d98b2eaf8010b725ec198ad862e682025bcea Mon Sep 17 00:00:00 2001 From: Spencer Date: Fri, 12 Jul 2024 18:09:44 -0600 Subject: [PATCH 276/361] Updated slice documentation --- library/core/src/slice/iter.rs | 60 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index ca1920f98120..504676ce187a 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -388,6 +388,9 @@ pub(super) trait SplitIter: DoubleEndedIterator { /// ``` /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split(|num| num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40][..])); +/// assert_eq!(iter.next(), Some(&[20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`split`]: slice::split @@ -541,6 +544,9 @@ impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} /// ``` /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40, 33][..])); +/// assert_eq!(iter.next(), Some(&[20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`split_inclusive`]: slice::split_inclusive @@ -914,7 +920,10 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// /// ``` /// let slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit(|num| *num == 0); +/// let mut iter = slice.rsplit(|num| *num == 0); +/// assert_eq!(iter.next(), Some(&[44, 55][..])); +/// assert_eq!(iter.next(), Some(&[11, 22, 33][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rsplit`]: slice::rsplit @@ -1134,7 +1143,10 @@ impl> Iterator for GenericSplitN { /// /// ``` /// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// let mut iter = slice.splitn(2, |num| *num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40][..])); +/// assert_eq!(iter.next(), Some(&[20, 60, 50][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`splitn`]: slice::splitn @@ -1175,7 +1187,10 @@ where /// /// ``` /// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// let mut iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[50][..])); +/// assert_eq!(iter.next(), Some(&[10, 40, 30, 20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rsplitn`]: slice::rsplitn @@ -1300,7 +1315,11 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] } /// /// ``` /// let slice = ['r', 'u', 's', 't']; -/// let iter = slice.windows(2); +/// let mut iter = slice.windows(2); +/// assert_eq!(iter.next(), Some(&['r', 'u'][..])); +/// assert_eq!(iter.next(), Some(&['u', 's'][..])); +/// assert_eq!(iter.next(), Some(&['s', 't'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`windows`]: slice::windows @@ -1448,7 +1467,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.chunks(2); +/// let mut iter = slice.chunks(2); +/// assert_eq!(iter.next(), Some(&['l', 'o'][..])); +/// assert_eq!(iter.next(), Some(&['r', 'e'][..])); +/// assert_eq!(iter.next(), Some(&['m'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`chunks`]: slice::chunks @@ -1819,7 +1842,10 @@ unsafe impl Sync for ChunksMut<'_, T> where T: Sync {} /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.chunks_exact(2); +/// let mut iter = slice.chunks_exact(2); +/// assert_eq!(iter.next(), Some(&['l', 'o'][..])); +/// assert_eq!(iter.next(), Some(&['r', 'e'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`chunks_exact`]: slice::chunks_exact @@ -2163,7 +2189,11 @@ unsafe impl Sync for ChunksExactMut<'_, T> where T: Sync {} /// #![feature(array_windows)] /// /// let slice = [0, 1, 2, 3]; -/// let iter = slice.array_windows::<2>(); +/// let mut iter = slice.array_windows::<2>(); +/// assert_eq!(iter.next(), Some(&[0, 1])); +/// assert_eq!(iter.next(), Some(&[1, 2])); +/// assert_eq!(iter.next(), Some(&[2, 3])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`array_windows`]: slice::array_windows @@ -2285,7 +2315,10 @@ impl ExactSizeIterator for ArrayWindows<'_, T, N> { /// #![feature(array_chunks)] /// /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.array_chunks::<2>(); +/// let mut iter = slice.array_chunks::<2>(); +/// assert_eq!(iter.next(), Some(&['l', 'o'])); +/// assert_eq!(iter.next(), Some(&['r', 'e'])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`array_chunks`]: slice::array_chunks @@ -2526,7 +2559,11 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMu /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.rchunks(2); +/// let mut iter = slice.rchunks(2); +/// assert_eq!(iter.next(), Some(&['e', 'm'][..])); +/// assert_eq!(iter.next(), Some(&['o', 'r'][..])); +/// assert_eq!(iter.next(), Some(&['l'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rchunks`]: slice::rchunks @@ -2892,7 +2929,10 @@ unsafe impl Sync for RChunksMut<'_, T> where T: Sync {} /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.rchunks_exact(2); +/// let mut iter = slice.rchunks_exact(2); +/// assert_eq!(iter.next(), Some(&['e', 'm'][..])); +/// assert_eq!(iter.next(), Some(&['o', 'r'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rchunks_exact`]: slice::rchunks_exact From 4d35754c46b4e0183770f4d7272b0e70a6553b19 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 12 Jul 2024 17:36:21 -0700 Subject: [PATCH 277/361] Add URL and crate_name to test cases --- .../issue-100204-inline-impl-through-glob-import.rs | 1 + tests/rustdoc/issue-100241.rs | 2 ++ tests/rustdoc/issue-100620.rs | 2 ++ tests/rustdoc/issue-102154.rs | 2 ++ tests/rustdoc/issue-105735-overlapping-reexport-2.rs | 1 + tests/rustdoc/issue-105735-overlapping-reexport.rs | 1 + tests/rustdoc/issue-105952.rs | 1 + tests/rustdoc/issue-106142.rs | 7 +++++-- tests/rustdoc/issue-106421-not-internal.rs | 5 ++++- tests/rustdoc/issue-106421.rs | 4 +++- .../issue-99221-multiple-macro-rules-w-same-name.rs | 1 + tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs | 1 + tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs | 1 + tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs | 1 + 14 files changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs index 7f05e57ec09b..ba6ed4278716 100644 --- a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs +++ b/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/100204 #![crate_name="second"] extern crate first; diff --git a/tests/rustdoc/issue-100241.rs b/tests/rustdoc/issue-100241.rs index e4c613dd2791..eef4b8355bfd 100644 --- a/tests/rustdoc/issue-100241.rs +++ b/tests/rustdoc/issue-100241.rs @@ -3,6 +3,8 @@ // Check that this isn't an ICE //@ should-fail +// https://github.com/rust-lang/rust/issues/100241 + mod foo { pub use inner::S; //~^ ERROR unresolved imports `inner`, `foo::S` diff --git a/tests/rustdoc/issue-100620.rs b/tests/rustdoc/issue-100620.rs index 097666eb515d..39d70bab29e4 100644 --- a/tests/rustdoc/issue-100620.rs +++ b/tests/rustdoc/issue-100620.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/100620 + pub trait Bar {} pub trait Qux {} diff --git a/tests/rustdoc/issue-102154.rs b/tests/rustdoc/issue-102154.rs index b36f270806ff..58cabe769272 100644 --- a/tests/rustdoc/issue-102154.rs +++ b/tests/rustdoc/issue-102154.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/102154 + trait A { type B; } diff --git a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs b/tests/rustdoc/issue-105735-overlapping-reexport-2.rs index 946184c5a047..9f823ec5923c 100644 --- a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs +++ b/tests/rustdoc/issue-105735-overlapping-reexport-2.rs @@ -1,4 +1,5 @@ // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export. +// https://github.com/rust-lang/rust/issues/105735 #![crate_name = "foo"] #![no_std] diff --git a/tests/rustdoc/issue-105735-overlapping-reexport.rs b/tests/rustdoc/issue-105735-overlapping-reexport.rs index 0fd17fd9577c..2a2d0fa98309 100644 --- a/tests/rustdoc/issue-105735-overlapping-reexport.rs +++ b/tests/rustdoc/issue-105735-overlapping-reexport.rs @@ -1,4 +1,5 @@ // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export. +// https://github.com/rust-lang/rust/issues/105735 #![crate_name = "foo"] #![no_std] diff --git a/tests/rustdoc/issue-105952.rs b/tests/rustdoc/issue-105952.rs index 173efb82f4b9..1bcdfac73429 100644 --- a/tests/rustdoc/issue-105952.rs +++ b/tests/rustdoc/issue-105952.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/105952 #![crate_name = "foo"] #![feature(associated_const_equality)] diff --git a/tests/rustdoc/issue-106142.rs b/tests/rustdoc/issue-106142.rs index 52adc5dbbf1a..0d146a3c5cd0 100644 --- a/tests/rustdoc/issue-106142.rs +++ b/tests/rustdoc/issue-106142.rs @@ -1,5 +1,8 @@ -//@ has 'issue_106142/a/index.html' -//@ count 'issue_106142/a/index.html' '//ul[@class="item-table"]//li//a' 1 +// https://github.com/rust-lang/rust/issues/106142 +#![crate_name="foo"] + +//@ has 'foo/a/index.html' +//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1 #![allow(rustdoc::broken_intra_doc_links)] diff --git a/tests/rustdoc/issue-106421-not-internal.rs b/tests/rustdoc/issue-106421-not-internal.rs index f328a1036ebe..a85cfa78cdcd 100644 --- a/tests/rustdoc/issue-106421-not-internal.rs +++ b/tests/rustdoc/issue-106421-not-internal.rs @@ -2,7 +2,10 @@ //@ ignore-cross-compile // This is the version where a non-compiler-internal crate inlines a compiler-internal one. // In this case, the item shouldn't be documented, because regular users can't get at it. +// https://github.com/rust-lang/rust/issues/106421 +#![crate_name="bar"] + extern crate foo; -//@ !has issue_106421_not_internal/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +//@ !has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' pub use foo::FatalError; diff --git a/tests/rustdoc/issue-106421.rs b/tests/rustdoc/issue-106421.rs index c2064c710907..aa88a569aef2 100644 --- a/tests/rustdoc/issue-106421.rs +++ b/tests/rustdoc/issue-106421.rs @@ -1,8 +1,10 @@ //@ aux-build:issue-106421-force-unstable.rs //@ ignore-cross-compile //@ compile-flags: -Zforce-unstable-if-unmarked +// https://github.com/rust-lang/rust/issues/106421 +#![crate_name="bar"] extern crate foo; -//@ has issue_106421/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +//@ has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' pub use foo::FatalError; diff --git a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs index e7fb4fb3f0ea..4a1798a84969 100644 --- a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs +++ b/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99221 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs index 8758342fe073..4c2f77fec23d 100644 --- a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs +++ b/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99221 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs index d7c4f1db320c..60a2aa388ee1 100644 --- a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs +++ b/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99734 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs index 627cfc0b80b3..d48464c478f3 100644 --- a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs +++ b/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99734 #![crate_name = "foo"] #[macro_use] From 9c1a9e03d5e001543a21eaff5d616de8cb4e2220 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 00:54:00 +0000 Subject: [PATCH 278/361] add test for Result<&T, _> where T; Deref --- .../transforming-option-ref-issue-127545.rs | 4 ++++ ...ransforming-option-ref-issue-127545.stderr | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index 9125ffeeb066..f589e88f68e4 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -12,3 +12,7 @@ pub fn bar(arg: Option<&Vec>) -> &[i32] { pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] } + +pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 90a7cfdb4496..0a6d47339d8e 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -61,6 +61,26 @@ help: use `Option::map_or` to deref inner value of `Option` LL | arg.map_or(v, |v| v) | ~~~~~~~~~~~~~~~~ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:17:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:17:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From 17419f6499546443fd311cc81a0d44ae233c306f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 12 Jul 2024 18:12:32 -0700 Subject: [PATCH 279/361] rustdoc: rename `issue-\d+.rs` tests to have meaningful names --- tests/rustdoc/{issue-108281.rs => attributes-inlining-108281.rs} | 0 tests/rustdoc/{issue-101743-bold-tag.rs => bold-tag-101743.rs} | 0 ...ernal.rs => force-unstable-if-unmarked-106421-not-internal.rs} | 0 .../{issue-106421.rs => force-unstable-if-unmarked-106421.rs} | 0 tests/rustdoc/{issue-102154.rs => ice-assoc-type-loop-102154.rs} | 0 .../{issue-105952.rs => ice-associated-const-equality-105952.rs} | 0 tests/rustdoc/{issue-107995.rs => ice-intra-doc-links-107995.rs} | 0 ...issue-100620.rs => ice-method-where-clause-circular-100620.rs} | 0 .../rustdoc/{issue-100241.rs => ice-unresolved-import-100241.rs} | 0 ...h-glob-import.rs => inline-impl-through-glob-import-100204.rs} | 0 .../{issue-108231.rs => macro-export-crate-root-108231.rs} | 0 .../{issue-106142.rs => macro-rules-broken-intra-doc-106142.rs} | 0 ...igns-w-same-name.rs => multiple-foreigns-w-same-name-99734.rs} | 0 ...s-w-same-name.rs => multiple-macro-rules-w-same-name-99221.rs} | 0 ...ple-mods-w-same-name.rs => multiple-mods-w-same-name-99734.rs} | 0 ...ructs-w-same-name.rs => multiple-structs-w-same-name-99221.rs} | 0 ...overlapping-reexport-2.rs => overlapping-reexport-105735-2.rs} | 0 ...735-overlapping-reexport.rs => overlapping-reexport-105735.rs} | 0 tests/rustdoc/{issue-107350.rs => pub-use-loop-107350.rs} | 0 ...679-reexport-of-reexport.rs => reexport-of-reexport-108679.rs} | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{issue-108281.rs => attributes-inlining-108281.rs} (100%) rename tests/rustdoc/{issue-101743-bold-tag.rs => bold-tag-101743.rs} (100%) rename tests/rustdoc/{issue-106421-not-internal.rs => force-unstable-if-unmarked-106421-not-internal.rs} (100%) rename tests/rustdoc/{issue-106421.rs => force-unstable-if-unmarked-106421.rs} (100%) rename tests/rustdoc/{issue-102154.rs => ice-assoc-type-loop-102154.rs} (100%) rename tests/rustdoc/{issue-105952.rs => ice-associated-const-equality-105952.rs} (100%) rename tests/rustdoc/{issue-107995.rs => ice-intra-doc-links-107995.rs} (100%) rename tests/rustdoc/{issue-100620.rs => ice-method-where-clause-circular-100620.rs} (100%) rename tests/rustdoc/{issue-100241.rs => ice-unresolved-import-100241.rs} (100%) rename tests/rustdoc/{issue-100204-inline-impl-through-glob-import.rs => inline-impl-through-glob-import-100204.rs} (100%) rename tests/rustdoc/{issue-108231.rs => macro-export-crate-root-108231.rs} (100%) rename tests/rustdoc/{issue-106142.rs => macro-rules-broken-intra-doc-106142.rs} (100%) rename tests/rustdoc/{issue-99734-multiple-foreigns-w-same-name.rs => multiple-foreigns-w-same-name-99734.rs} (100%) rename tests/rustdoc/{issue-99221-multiple-macro-rules-w-same-name.rs => multiple-macro-rules-w-same-name-99221.rs} (100%) rename tests/rustdoc/{issue-99734-multiple-mods-w-same-name.rs => multiple-mods-w-same-name-99734.rs} (100%) rename tests/rustdoc/{issue-99221-multiple-structs-w-same-name.rs => multiple-structs-w-same-name-99221.rs} (100%) rename tests/rustdoc/{issue-105735-overlapping-reexport-2.rs => overlapping-reexport-105735-2.rs} (100%) rename tests/rustdoc/{issue-105735-overlapping-reexport.rs => overlapping-reexport-105735.rs} (100%) rename tests/rustdoc/{issue-107350.rs => pub-use-loop-107350.rs} (100%) rename tests/rustdoc/{issue-108679-reexport-of-reexport.rs => reexport-of-reexport-108679.rs} (100%) diff --git a/tests/rustdoc/issue-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs similarity index 100% rename from tests/rustdoc/issue-108281.rs rename to tests/rustdoc/attributes-inlining-108281.rs diff --git a/tests/rustdoc/issue-101743-bold-tag.rs b/tests/rustdoc/bold-tag-101743.rs similarity index 100% rename from tests/rustdoc/issue-101743-bold-tag.rs rename to tests/rustdoc/bold-tag-101743.rs diff --git a/tests/rustdoc/issue-106421-not-internal.rs b/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs similarity index 100% rename from tests/rustdoc/issue-106421-not-internal.rs rename to tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs diff --git a/tests/rustdoc/issue-106421.rs b/tests/rustdoc/force-unstable-if-unmarked-106421.rs similarity index 100% rename from tests/rustdoc/issue-106421.rs rename to tests/rustdoc/force-unstable-if-unmarked-106421.rs diff --git a/tests/rustdoc/issue-102154.rs b/tests/rustdoc/ice-assoc-type-loop-102154.rs similarity index 100% rename from tests/rustdoc/issue-102154.rs rename to tests/rustdoc/ice-assoc-type-loop-102154.rs diff --git a/tests/rustdoc/issue-105952.rs b/tests/rustdoc/ice-associated-const-equality-105952.rs similarity index 100% rename from tests/rustdoc/issue-105952.rs rename to tests/rustdoc/ice-associated-const-equality-105952.rs diff --git a/tests/rustdoc/issue-107995.rs b/tests/rustdoc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/issue-107995.rs rename to tests/rustdoc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/issue-100620.rs b/tests/rustdoc/ice-method-where-clause-circular-100620.rs similarity index 100% rename from tests/rustdoc/issue-100620.rs rename to tests/rustdoc/ice-method-where-clause-circular-100620.rs diff --git a/tests/rustdoc/issue-100241.rs b/tests/rustdoc/ice-unresolved-import-100241.rs similarity index 100% rename from tests/rustdoc/issue-100241.rs rename to tests/rustdoc/ice-unresolved-import-100241.rs diff --git a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/tests/rustdoc/inline-impl-through-glob-import-100204.rs similarity index 100% rename from tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs rename to tests/rustdoc/inline-impl-through-glob-import-100204.rs diff --git a/tests/rustdoc/issue-108231.rs b/tests/rustdoc/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/issue-108231.rs rename to tests/rustdoc/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/issue-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs similarity index 100% rename from tests/rustdoc/issue-106142.rs rename to tests/rustdoc/macro-rules-broken-intra-doc-106142.rs diff --git a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs rename to tests/rustdoc/multiple-foreigns-w-same-name-99734.rs diff --git a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs rename to tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs diff --git a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/tests/rustdoc/multiple-mods-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs rename to tests/rustdoc/multiple-mods-w-same-name-99734.rs diff --git a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/tests/rustdoc/multiple-structs-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs rename to tests/rustdoc/multiple-structs-w-same-name-99221.rs diff --git a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs similarity index 100% rename from tests/rustdoc/issue-105735-overlapping-reexport-2.rs rename to tests/rustdoc/overlapping-reexport-105735-2.rs diff --git a/tests/rustdoc/issue-105735-overlapping-reexport.rs b/tests/rustdoc/overlapping-reexport-105735.rs similarity index 100% rename from tests/rustdoc/issue-105735-overlapping-reexport.rs rename to tests/rustdoc/overlapping-reexport-105735.rs diff --git a/tests/rustdoc/issue-107350.rs b/tests/rustdoc/pub-use-loop-107350.rs similarity index 100% rename from tests/rustdoc/issue-107350.rs rename to tests/rustdoc/pub-use-loop-107350.rs diff --git a/tests/rustdoc/issue-108679-reexport-of-reexport.rs b/tests/rustdoc/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/issue-108679-reexport-of-reexport.rs rename to tests/rustdoc/reexport-of-reexport-108679.rs From 938ed369ada248e00d5ed906e5ba589c7cac9d2e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 12 Jul 2024 21:15:25 -0400 Subject: [PATCH 280/361] Gate the type length limit check behind a nightly flag --- compiler/rustc_middle/src/ty/instance.rs | 4 +++- compiler/rustc_session/src/options.rs | 2 ++ ...issue-72408-nested-closures-exponential.rs | 3 +-- ...e-72408-nested-closures-exponential.stderr | 10 ---------- tests/ui/codegen/overflow-during-mono.rs | 2 +- tests/ui/codegen/overflow-during-mono.stderr | 11 +++++++---- tests/ui/issues/issue-22638.rs | 2 +- tests/ui/issues/issue-22638.stderr | 17 +++++++++-------- .../issue-37311.rs | 2 +- .../issue-37311.stderr | 8 ++++++-- .../issue-58952-filter-type-length.rs | 3 +-- .../issue-58952-filter-type-length.stderr | 8 -------- tests/ui/recursion/issue-83150.rs | 2 +- tests/ui/recursion/issue-83150.stderr | 15 +++++++-------- .../traits/issue-91949-hangs-on-recursion.rs | 2 +- .../issue-91949-hangs-on-recursion.stderr | 19 ++++++++++++------- tests/ui/type_length_limit.rs | 2 +- 17 files changed, 54 insertions(+), 58 deletions(-) delete mode 100644 tests/ui/closures/issue-72408-nested-closures-exponential.stderr delete mode 100644 tests/ui/iterators/issue-58952-filter-type-length.stderr diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index c50a98e88fd6..6e64e9bc4f87 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -541,7 +541,9 @@ impl<'tcx> Instance<'tcx> { // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - if !tcx.type_length_limit().value_within_limit(type_length(args)) { + if tcx.sess.opts.unstable_opts.enforce_type_length_limit + && !tcx.type_length_limit().value_within_limit(type_length(args)) + { return Ok(None); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7421cae65e4f..7a203fb8f407 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1709,6 +1709,8 @@ options! { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), + enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], + "enforce the type length limit when monomorphizing instances in codegen"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), external_clangrt: bool = (false, parse_bool, [UNTRACKED], diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs index 033e42243386..45bc1ab5b1bb 100644 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,4 +1,4 @@ -//@ build-fail +//@ check-pass // Closures include captured types twice in a type tree. // @@ -45,7 +45,6 @@ fn main() { let f = dup(f); let f = dup(f); - //~^ ERROR reached the type-length limit let f = dup(f); let f = dup(f); let f = dup(f); diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr deleted file mode 100644 index 2120b4569639..000000000000 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>` - --> $DIR/issue-72408-nested-closures-exponential.rs:47:13 - | -LL | let f = dup(f); - | ^^^^^^ - | - = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate - -error: aborting due to 1 previous error - diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 4d3f2c18dc83..83a8b6b3ef6a 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,5 +1,5 @@ +//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` //@ build-fail -//@ error-pattern: reached the type-length limit while instantiating #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index e06fcd289669..f7a3e2df3dba 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,8 +1,11 @@ -error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL +error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` | - = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt' + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: 31 redundant requirements hidden + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs index 3e401e99fb48..be9304e5829f 100644 --- a/tests/ui/issues/issue-22638.rs +++ b/tests/ui/issues/issue-22638.rs @@ -40,7 +40,6 @@ impl C { pub fn matches(&self, f: &F) { let &C(ref base) = self; base.matches(&|| { - //~^ ERROR reached the type-length limit C(base.clone()).matches(f) }) } @@ -53,6 +52,7 @@ impl D { pub fn matches(&self, f: &F) { let &D(ref a) = self; a.matches(f) + //~^ ERROR reached the recursion limit while instantiating } } diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr index 1344409c7704..96f179448683 100644 --- a/tests/ui/issues/issue-22638.stderr +++ b/tests/ui/issues/issue-22638.stderr @@ -1,13 +1,14 @@ -error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` - --> $DIR/issue-22638.rs:42:9 +error: reached the recursion limit while instantiating `A::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` + --> $DIR/issue-22638.rs:54:9 | -LL | / base.matches(&|| { -LL | | -LL | | C(base.clone()).matches(f) -LL | | }) - | |__________^ +LL | a.matches(f) + | ^^^^^^^^^^^^ | - = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate +note: `A::matches` defined here + --> $DIR/issue-22638.rs:13:5 + | +LL | pub fn matches(&self, f: &F) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs index 131c7535537f..96e2691164ba 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -15,7 +15,7 @@ impl Foo for T { #[allow(unconditional_recursion)] fn recurse(&self) { (self, self).recurse(); - //~^ ERROR reached the type-length limit + //~^ ERROR reached the recursion limit while instantiating } } diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index 2978ced52794..84ed97572b3a 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,10 +1,14 @@ -error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` +error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate +note: `::recurse` defined here + --> $DIR/issue-37311.rs:16:5 + | +LL | fn recurse(&self) { + | ^^^^^^^^^^^^^^^^^ = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index 4f3ddce69d82..6730865b6c7f 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,5 +1,4 @@ -//@ build-fail -//@ error-pattern: reached the type-length limit while instantiating +//@ build-pass //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr deleted file mode 100644 index 975fcd4afffe..000000000000 --- a/tests/ui/iterators/issue-58952-filter-type-length.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: reached the type-length limit while instantiating ` as Iterator>::try_fold::, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL - | - = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt' - -error: aborting due to 1 previous error - diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs index b3ddf88c4493..f91698d06372 100644 --- a/tests/ui/recursion/issue-83150.rs +++ b/tests/ui/recursion/issue-83150.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator` //@ build-fail //@ compile-flags: -Copt-level=0 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" @@ -11,5 +12,4 @@ fn main() { fn func>(iter: &mut T) { //~^ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) - //~^ ERROR reached the type-length limit } diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr index 127de98ddc5b..fb66436dbbdd 100644 --- a/tests/ui/recursion/issue-83150.stderr +++ b/tests/ui/recursion/issue-83150.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-83150.rs:11:1 + --> $DIR/issue-83150.rs:12:1 | LL | fn func>(iter: &mut T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -10,14 +10,13 @@ LL | func(&mut iter.map(|x| x + 1)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>` - --> $DIR/issue-83150.rs:13:15 +error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator` | -LL | func(&mut iter.map(|x| x + 1)) - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt' + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) + = note: required for `&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator` + = note: 65 redundant requirements hidden + = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator` error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index d9c422e6f709..7c9ae09349aa 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow evaluating the requirement ` as Iterator>::Item == ()` //@ build-fail //@ compile-flags: -Zinline-mir=no @@ -23,7 +24,6 @@ where T: Iterator, { recurse(IteratorOfWrapped(elements).map(|t| t.0)) - //~^ ERROR reached the type-length limit } fn main() { diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index c46c78609d2c..c2f09371cf7f 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:20:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:21:1 | LL | / fn recurse(elements: T) -> Vec LL | | @@ -13,14 +13,19 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error: reached the type-length limit while instantiating `, ...>> as Iterator>::map::<..., ...>` - --> $DIR/issue-91949-hangs-on-recursion.rs:25:13 +error[E0275]: overflow evaluating the requirement ` as Iterator>::Item == ()` | -LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) +note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` + --> $DIR/issue-91949-hangs-on-recursion.rs:14:32 | - = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt' +LL | impl> Iterator for IteratorOfWrapped { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 256 redundant requirements hidden + = note: required for `IteratorOfWrapped<(), Map>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>` to implement `Iterator` error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs index d6937481a155..87f5ffd76d7a 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/type_length_limit.rs @@ -1,5 +1,5 @@ //@ build-fail -//@ compile-flags: -Copt-level=0 +//@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit //~^^ ERROR reached the type-length limit // Test that the type length limit can be changed. From 42ee400b0ffa7eeffb51e5b1e2e3fbcc6a130e0c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 12 Jul 2024 18:16:30 -0700 Subject: [PATCH 281/361] Move assertion-free rustdoc ice tests to rustdoc-ui --- tests/{rustdoc => rustdoc-ui}/ice-assoc-type-loop-102154.rs | 1 + .../ice-method-where-clause-circular-100620.rs | 1 + tests/{rustdoc => rustdoc-ui}/ice-unresolved-import-100241.rs | 0 3 files changed, 2 insertions(+) rename tests/{rustdoc => rustdoc-ui}/ice-assoc-type-loop-102154.rs (94%) rename tests/{rustdoc => rustdoc-ui}/ice-method-where-clause-circular-100620.rs (95%) rename tests/{rustdoc => rustdoc-ui}/ice-unresolved-import-100241.rs (100%) diff --git a/tests/rustdoc/ice-assoc-type-loop-102154.rs b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs similarity index 94% rename from tests/rustdoc/ice-assoc-type-loop-102154.rs rename to tests/rustdoc-ui/ice-assoc-type-loop-102154.rs index 58cabe769272..68e22ce6ea15 100644 --- a/tests/rustdoc/ice-assoc-type-loop-102154.rs +++ b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs @@ -1,3 +1,4 @@ +//@ check-pass // https://github.com/rust-lang/rust/issues/102154 trait A { diff --git a/tests/rustdoc/ice-method-where-clause-circular-100620.rs b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs similarity index 95% rename from tests/rustdoc/ice-method-where-clause-circular-100620.rs rename to tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs index 39d70bab29e4..e12b214410bc 100644 --- a/tests/rustdoc/ice-method-where-clause-circular-100620.rs +++ b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs @@ -1,3 +1,4 @@ +//@ check-pass // https://github.com/rust-lang/rust/issues/100620 pub trait Bar {} diff --git a/tests/rustdoc/ice-unresolved-import-100241.rs b/tests/rustdoc-ui/ice-unresolved-import-100241.rs similarity index 100% rename from tests/rustdoc/ice-unresolved-import-100241.rs rename to tests/rustdoc-ui/ice-unresolved-import-100241.rs From 69f6145ad82e931f730cca81f12a369d894121a6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 13 Jul 2024 11:15:40 +1000 Subject: [PATCH 282/361] Change `look` from a macro to a function. Using `#[track_caller]` works if the assertion is moved outside of the closure. --- compiler/rustc_parse/src/parser/tests.rs | 125 ++++++++++++----------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 5b2d119e42b4..ee2d39b03bd7 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1376,12 +1376,13 @@ fn ttdelim_span() { }); } -// Uses a macro rather than a function so that failure messages mention the -// correct line in the test function. -macro_rules! look { - ($p:ident, $dist:literal, $kind:expr) => { - $p.look_ahead($dist, |tok| assert_eq!($kind, tok.kind)); - }; +#[track_caller] +fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) { + // Do the `assert_eq` outside the closure so that `track_caller` works. + // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure + // doesn't give the line number in the test below if the assertion fails.) + let tok = p.look_ahead(dist, |tok| tok.clone()); + assert_eq!(kind, tok.kind); } #[test] @@ -1397,63 +1398,63 @@ fn look_ahead() { let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); // Current position is the `fn`. - look!(p, 0, token::Ident(kw::Fn, raw_no)); - look!(p, 1, token::Ident(sym_f, raw_no)); - look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); - look!(p, 3, token::Ident(sym_x, raw_no)); - look!(p, 4, token::Colon); - look!(p, 5, token::Ident(sym::u32, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 7, token::OpenDelim(Delimiter::Brace)); - look!(p, 8, token::Ident(sym_x, raw_no)); - look!(p, 9, token::CloseDelim(Delimiter::Brace)); - look!(p, 10, token::Ident(kw::Struct, raw_no)); - look!(p, 11, token::Ident(sym_S, raw_no)); - look!(p, 12, token::Semi); + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 13, token::Eof); - look!(p, 14, token::Eof); - look!(p, 15, token::Eof); - look!(p, 100, token::Eof); + look(&p, 13, token::Eof); + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); // Move forward to the first `x`. for _ in 0..3 { p.bump(); } - look!(p, 0, token::Ident(sym_x, raw_no)); - look!(p, 1, token::Colon); - look!(p, 2, token::Ident(sym::u32, raw_no)); - look!(p, 3, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 4, token::OpenDelim(Delimiter::Brace)); - look!(p, 5, token::Ident(sym_x, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Brace)); - look!(p, 7, token::Ident(kw::Struct, raw_no)); - look!(p, 8, token::Ident(sym_S, raw_no)); - look!(p, 9, token::Semi); - look!(p, 10, token::Eof); - look!(p, 11, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Ident(sym_x, raw_no)); + look(&p, 1, token::Colon); + look(&p, 2, token::Ident(sym::u32, raw_no)); + look(&p, 3, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 4, token::OpenDelim(Delimiter::Brace)); + look(&p, 5, token::Ident(sym_x, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Brace)); + look(&p, 7, token::Ident(kw::Struct, raw_no)); + look(&p, 8, token::Ident(sym_S, raw_no)); + look(&p, 9, token::Semi); + look(&p, 10, token::Eof); + look(&p, 11, token::Eof); + look(&p, 100, token::Eof); // Move forward to the `;`. for _ in 0..9 { p.bump(); } - look!(p, 0, token::Semi); + look(&p, 0, token::Semi); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); // Move one past the `;`, i.e. past the end of the token stream. p.bump(); - look!(p, 0, token::Eof); - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); // Bumping after Eof is idempotent. p.bump(); - look!(p, 0, token::Eof); - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); }); } @@ -1476,24 +1477,24 @@ fn look_ahead_non_outermost_stream() { for _ in 0..3 { p.bump(); } - look!(p, 0, token::Ident(kw::Fn, raw_no)); - look!(p, 1, token::Ident(sym_f, raw_no)); - look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); - look!(p, 3, token::Ident(sym_x, raw_no)); - look!(p, 4, token::Colon); - look!(p, 5, token::Ident(sym::u32, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 7, token::OpenDelim(Delimiter::Brace)); - look!(p, 8, token::Ident(sym_x, raw_no)); - look!(p, 9, token::CloseDelim(Delimiter::Brace)); - look!(p, 10, token::Ident(kw::Struct, raw_no)); - look!(p, 11, token::Ident(sym_S, raw_no)); - look!(p, 12, token::Semi); - look!(p, 13, token::CloseDelim(Delimiter::Brace)); + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); + look(&p, 13, token::CloseDelim(Delimiter::Brace)); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 14, token::Eof); - look!(p, 15, token::Eof); - look!(p, 100, token::Eof); + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); }); } From cf2dfb2ced7862077ceff468c679f44d1e6d56cc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 13 Jul 2024 13:17:14 +1000 Subject: [PATCH 283/361] Add a test for `Parser::debug_lookahead`. That method is currently badly broken, and the test output reflects this. The obtained tokens list is always empty, except in the case where we go two `bump`s past the final token, whereupon it will produce as many `Eof` tokens as asked for. --- compiler/rustc_parse/src/parser/tests.rs | 149 +++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index ee2d39b03bd7..8703d5b84905 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1498,6 +1498,155 @@ fn look_ahead_non_outermost_stream() { }); } +// FIXME(nnethercote) All the output is currently wrong. +#[test] +fn debug_lookahead() { + create_default_session_globals_then(|| { + let psess = psess(); + let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); + + // Current position is the `fn`. + assert_eq!( + &format!("{:#?}", p.debug_lookahead(0)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 1, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(7)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 1, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(15)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 1, + .. +}" + ); + + // Move forward to the second `x`. + for _ in 0..8 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(1)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 9, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(4)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 9, + .. +}" + ); + + // Move two past the final token (the `;`). + for _ in 0..6 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(3)), + "Parser { + prev_token: Token { + kind: Eof, + span: Span { + lo: BytePos( + 27, + ), + hi: BytePos( + 28, + ), + ctxt: #0, + }, + }, + tokens: [ + Eof, + Eof, + Eof, + ], + approx_token_stream_pos: 15, + .. +}" + ); + }); +} + // This tests that when parsing a string (rather than a file) we don't try // and read in a file for a module declaration and just parse a stub. // See `recurse_into_file_modules` in the parser. From aa0e8e147588c75fbb6ad158140c890582886027 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 13 Jul 2024 15:53:31 +1000 Subject: [PATCH 284/361] Fix `DebugParser`. It currently doesn't work at all. This commit changes it to a simpler imperative style that produces a valid `tokens` vec. (An aside: I find `Iterator::scan` to be a pretty wretched function, that produces code which is very hard to understand. Probably why this is just one of two uses of it in the entire compiler.) --- compiler/rustc_parse/src/parser/mod.rs | 18 ++-- compiler/rustc_parse/src/parser/tests.rs | 100 +++++++++++++++++++++-- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ef9b3aabc61c..6586baae00a2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1537,14 +1537,16 @@ impl<'a> Parser<'a> { // we don't need N spans, but we want at least one, so print all of prev_token dbg_fmt.field("prev_token", &parser.prev_token); - // make it easier to peek farther ahead by taking TokenKinds only until EOF - let tokens = (0..*lookahead) - .map(|i| parser.look_ahead(i, |tok| tok.kind.clone())) - .scan(parser.prev_token == TokenKind::Eof, |eof, tok| { - let current = eof.then_some(tok.clone()); // include a trailing EOF token - *eof |= &tok == &TokenKind::Eof; - current - }); + let mut tokens = vec![]; + for i in 0..*lookahead { + let tok = parser.look_ahead(i, |tok| tok.kind.clone()); + let is_eof = tok == TokenKind::Eof; + tokens.push(tok); + if is_eof { + // Don't look ahead past EOF. + break; + } + } dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish()); dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 8703d5b84905..cf791d332a2f 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1541,11 +1541,36 @@ fn debug_lookahead() { ctxt: #0, }, }, - tokens: [], + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + ], approx_token_stream_pos: 1, .. }" ); + // There are 13 tokens. We request 15, get 14; the last one is `Eof`. assert_eq!( &format!("{:#?}", p.debug_lookahead(15)), "Parser { @@ -1561,7 +1586,51 @@ fn debug_lookahead() { ctxt: #0, }, }, - tokens: [], + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + OpenDelim( + Brace, + ), + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + Semi, + Eof, + ], approx_token_stream_pos: 1, .. }" @@ -1588,7 +1657,12 @@ fn debug_lookahead() { ctxt: #0, }, }, - tokens: [], + tokens: [ + Ident( + \"x\", + No, + ), + ], approx_token_stream_pos: 9, .. }" @@ -1610,7 +1684,23 @@ fn debug_lookahead() { ctxt: #0, }, }, - tokens: [], + tokens: [ + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + ], approx_token_stream_pos: 9, .. }" @@ -1637,8 +1727,6 @@ fn debug_lookahead() { }, tokens: [ Eof, - Eof, - Eof, ], approx_token_stream_pos: 15, .. From 0cce0bb204dd6e4ff06a282b605c9ac416a8dbd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 13 Jul 2024 11:41:29 +0200 Subject: [PATCH 285/361] Avoid more instances of unused command execution in dry run --- src/bootstrap/src/core/build_steps/dist.rs | 6 +----- src/bootstrap/src/core/build_steps/test.rs | 16 ++++++---------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index aebec60112fb..1e9d2025bc78 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2068,11 +2068,7 @@ fn maybe_install_llvm( let mut cmd = command(llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); - let files = if builder.config.dry_run() { - "".into() - } else { - cmd.capture_stdout().run(builder).stdout() - }; + let files = cmd.capture_stdout().run(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); for file in files.trim_end().split(' ') { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e49c2cbe17b1..9b4c7c913497 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -471,16 +471,12 @@ impl Miri { // We re-use the `cargo` from above. cargo.arg("--print-sysroot"); - if builder.config.dry_run() { - String::new() - } else { - builder.verbose(|| println!("running: {cargo:?}")); - let stdout = cargo.capture_stdout().run(builder).stdout(); - // Output is "\n". - let sysroot = stdout.trim_end(); - builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); - sysroot.to_owned() - } + builder.verbose(|| println!("running: {cargo:?}")); + let stdout = cargo.capture_stdout().run(builder).stdout(); + // Output is "\n". + let sysroot = stdout.trim_end(); + builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + sysroot.to_owned() } } From 76f5bc6a9ffcd0b3255b5266cc963635a12f6016 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 27 Jun 2024 14:51:58 +0000 Subject: [PATCH 286/361] Create mapped places upon seeing them in the body. --- .../rustc_mir_dataflow/src/value_analysis.rs | 239 +++++++++--------- .../src/dataflow_const_prop.rs | 20 +- .../rustc_mir_transform/src/jump_threading.rs | 2 +- tests/coverage/try_error_result.cov-map | 199 ++++++++------- ...pr_transparent.main.DataflowConstProp.diff | 6 +- .../dataflow-const-prop/repr_transparent.rs | 2 +- .../struct.main.DataflowConstProp.32bit.diff | 29 +-- .../struct.main.DataflowConstProp.64bit.diff | 29 +-- tests/mir-opt/dataflow-const-prop/struct.rs | 6 +- .../tuple.main.DataflowConstProp.32bit.diff | 4 +- .../tuple.main.DataflowConstProp.64bit.diff | 4 +- tests/mir-opt/dataflow-const-prop/tuple.rs | 3 +- 12 files changed, 271 insertions(+), 272 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 1582c2e8a906..f21a24191444 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -32,15 +32,16 @@ //! Because of that, we can assume that the only way to change the value behind a tracked place is //! by direct assignment. -use std::collections::VecDeque; use std::fmt::{Debug, Formatter}; use std::ops::Range; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::bug; +use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -58,7 +59,7 @@ pub trait ValueAnalysis<'tcx> { const NAME: &'static str; - fn map(&self) -> ⤅ + fn map(&self) -> &Map<'tcx>; fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State) { self.super_statement(statement, state) @@ -523,12 +524,12 @@ impl State { } /// Assign `value` to all places that are contained in `place` or may alias one. - pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { + pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) { self.flood_with_tail_elem(place, None, map, value) } /// Assign `TOP` to all places that are contained in `place` or may alias one. - pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) + pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map<'_>) where V: HasTop, { @@ -536,12 +537,12 @@ impl State { } /// Assign `value` to the discriminant of `place` and all places that may alias it. - fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { + fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) { self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value) } /// Assign `TOP` to the discriminant of `place` and all places that may alias it. - pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) + pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map<'_>) where V: HasTop, { @@ -559,7 +560,7 @@ impl State { &mut self, place: PlaceRef<'_>, tail_elem: Option, - map: &Map, + map: &Map<'_>, value: V, ) { let State::Reachable(values) = self else { return }; @@ -570,7 +571,7 @@ impl State { /// This does nothing if the place is not tracked. /// /// The target place must have been flooded before calling this method. - fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace, map: &Map) { + fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace, map: &Map<'_>) { match result { ValueOrPlace::Value(value) => self.insert_value_idx(target, value, map), ValueOrPlace::Place(source) => self.insert_place_idx(target, source, map), @@ -581,7 +582,7 @@ impl State { /// This does nothing if the place is not tracked. /// /// The target place must have been flooded before calling this method. - pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { + pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map<'_>) { let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { values.insert(value_index, value) @@ -595,7 +596,7 @@ impl State { /// places that are non-overlapping or identical. /// /// The target place must have been flooded before calling this method. - pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) { + pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) { let State::Reachable(values) = self else { return }; // If both places are tracked, we copy the value to the target. @@ -616,7 +617,7 @@ impl State { } /// Helper method to interpret `target = result`. - pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map) + pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map<'_>) where V: HasTop, { @@ -627,7 +628,7 @@ impl State { } /// Helper method for assignments to a discriminant. - pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map) + pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map<'_>) where V: HasTop, { @@ -638,25 +639,25 @@ impl State { } /// Retrieve the value stored for a place, or `None` if it is not tracked. - pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find(place)?; self.try_get_idx(place, map) } /// Retrieve the discriminant stored for a place, or `None` if it is not tracked. - pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find_discr(place)?; self.try_get_idx(place, map) } /// Retrieve the slice length stored for a place, or `None` if it is not tracked. - pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find_len(place)?; self.try_get_idx(place, map) } /// Retrieve the value stored for a place index, or `None` if it is not tracked. - pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { + pub fn try_get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> Option { match self { State::Reachable(values) => { map.places[place].value_index.map(|v| values.get(v).clone()) @@ -668,7 +669,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ if the place is tracked and the state is unreachable. - pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -682,7 +683,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -696,7 +697,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -710,7 +711,7 @@ impl State { /// Retrieve the value stored for a place index, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V + pub fn get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -746,25 +747,25 @@ impl JoinSemiLattice for State { /// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children. /// - To directly get the child for a specific projection, there is a `projections` map. #[derive(Debug)] -pub struct Map { +pub struct Map<'tcx> { locals: IndexVec>, projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>, - places: IndexVec, + places: IndexVec>, value_count: usize, // The Range corresponds to a slice into `inner_values_buffer`. inner_values: IndexVec>, inner_values_buffer: Vec, } -impl Map { +impl<'tcx> Map<'tcx> { /// Returns a map that only tracks places whose type has scalar layout. /// /// This is currently the only way to create a [`Map`]. The way in which the tracked places are /// chosen is an implementation detail and may not be relied upon (other than that their type /// are scalars). - pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { + pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { let mut map = Self { - locals: IndexVec::new(), + locals: IndexVec::from_elem(None, &body.local_decls), projections: FxHashMap::default(), places: IndexVec::new(), value_count: 0, @@ -778,18 +779,15 @@ impl Map { } /// Register all non-excluded places that have scalar layout. - fn register<'tcx>( + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn register( &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, exclude: BitSet, value_limit: Option, ) { - let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len())); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - // Start by constructing the places for each bare local. - self.locals = IndexVec::from_elem(None, &body.local_decls); for (local, decl) in body.local_decls.iter_enumerated() { if exclude.contains(local) { continue; @@ -797,16 +795,15 @@ impl Map { // Create a place for the local. debug_assert!(self.locals[local].is_none()); - let place = self.places.push(PlaceInfo::new(None)); + let place = self.places.push(PlaceInfo::new(decl.ty, None)); self.locals[local] = Some(place); - - // And push the eventual children places to the worklist. - self.register_children(tcx, param_env, place, decl.ty, &mut worklist); } - // `place.elem1.elem2` with type `ty`. - // `elem1` is either `Some(Variant(i))` or `None`. - while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() { + PlaceCollector { tcx, body, map: self }.visit_body(body); + + // Create values for places whose type have scalar layout. + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + for place_info in self.places.iter_mut() { // The user requires a bound on the number of created values. if let Some(value_limit) = value_limit && self.value_count >= value_limit @@ -814,19 +811,18 @@ impl Map { break; } - // Create a place for this projection. - for elem in [elem1, Some(elem2)].into_iter().flatten() { - place = *self.projections.entry((place, elem)).or_insert_with(|| { - // Prepend new child to the linked list. - let next = self.places.push(PlaceInfo::new(Some(elem))); - self.places[next].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(next); - next - }); + if let Ok(ty) = tcx.try_normalize_erasing_regions(param_env, place_info.ty) { + place_info.ty = ty; } - // And push the eventual children places to the worklist. - self.register_children(tcx, param_env, place, ty, &mut worklist); + // Allocate a value slot if it doesn't have one, and the user requested one. + assert!(place_info.value_index.is_none()); + if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty)) + && layout.abi.is_scalar() + { + place_info.value_index = Some(self.value_count.into()); + self.value_count += 1; + } } // Pre-compute the tree of ValueIndex nested in each PlaceIndex. @@ -852,68 +848,14 @@ impl Map { self.projections.retain(|_, child| !self.inner_values[*child].is_empty()); } - /// Potentially register the (local, projection) place and its fields, recursively. - /// - /// Invariant: The projection must only contain trackable elements. - fn register_children<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - place: PlaceIndex, - ty: Ty<'tcx>, - worklist: &mut VecDeque<(PlaceIndex, Option, TrackElem, Ty<'tcx>)>, - ) { - // Allocate a value slot if it doesn't have one, and the user requested one. - assert!(self.places[place].value_index.is_none()); - if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.abi.is_scalar()) { - self.places[place].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - // For enums, directly create the `Discriminant`, as that's their main use. - if ty.is_enum() { - // Prepend new child to the linked list. - let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); - self.places[discr].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(discr); - let old = self.projections.insert((place, TrackElem::Discriminant), discr); - assert!(old.is_none()); - - // Allocate a value slot since it doesn't have one. - assert!(self.places[discr].value_index.is_none()); - self.places[discr].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind() - && let ty::Slice(..) = ref_ty.kind() - // The user may have written a predicate like `[T]: Sized` in their where clauses, - // which makes slices scalars. - && self.places[place].value_index.is_none() - { - // Prepend new child to the linked list. - let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen))); - self.places[len].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(len); - - let old = self.projections.insert((place, TrackElem::DerefLen), len); - assert!(old.is_none()); - - // Allocate a value slot since it doesn't have one. - assert!(self.places[len].value_index.is_none()); - self.places[len].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - // Recurse with all fields of this place. - iter_fields(ty, tcx, param_env, |variant, field, ty| { - worklist.push_back(( - place, - variant.map(TrackElem::Variant), - TrackElem::Field(field), - ty, - )) - }); + #[tracing::instrument(level = "trace", skip(self), ret)] + fn register_place(&mut self, ty: Ty<'tcx>, base: PlaceIndex, elem: TrackElem) -> PlaceIndex { + *self.projections.entry((base, elem)).or_insert_with(|| { + let next = self.places.push(PlaceInfo::new(ty, Some(elem))); + self.places[next].next_sibling = self.places[base].first_child; + self.places[base].first_child = Some(next); + next + }) } /// Precompute the list of values inside `root` and store it inside @@ -934,7 +876,54 @@ impl Map { let end = self.inner_values_buffer.len(); self.inner_values[root] = start..end; } +} +struct PlaceCollector<'a, 'b, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'b Body<'tcx>, + map: &'a mut Map<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { + #[tracing::instrument(level = "trace", skip(self))] + fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) { + if !ctxt.is_use() { + return; + } + + // Create a place for this projection. + let Some(mut place_index) = self.map.locals[place.local] else { return }; + let mut ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); + tracing::trace!(?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(self.tcx); + self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); + } + + for proj in place.projection { + let Ok(track_elem) = proj.try_into() else { return }; + ty = ty.projection_ty(self.tcx, proj); + place_index = self.map.register_place(ty.ty, place_index, track_elem); + tracing::trace!(?proj, ?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(self.tcx); + self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); + } + } + } +} + +impl<'tcx> Map<'tcx> { /// Applies a single projection element, yielding the corresponding child. pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option { self.projections.get(&(place, elem)).copied() @@ -974,7 +963,10 @@ impl Map { } /// Iterate over all direct children. - fn children(&self, parent: PlaceIndex) -> impl Iterator + '_ { + fn children( + &self, + parent: PlaceIndex, + ) -> impl Iterator + Captures<'_> + Captures<'tcx> { Children::new(self, parent) } @@ -1081,7 +1073,10 @@ impl Map { /// Together, `first_child` and `next_sibling` form an intrusive linked list, which is used to /// model a tree structure (a replacement for a member like `children: Vec`). #[derive(Debug)] -struct PlaceInfo { +struct PlaceInfo<'tcx> { + /// Type of the referenced place. + ty: Ty<'tcx>, + /// We store a [`ValueIndex`] if and only if the placed is tracked by the analysis. value_index: Option, @@ -1095,24 +1090,24 @@ struct PlaceInfo { next_sibling: Option, } -impl PlaceInfo { - fn new(proj_elem: Option) -> Self { - Self { next_sibling: None, first_child: None, proj_elem, value_index: None } +impl<'tcx> PlaceInfo<'tcx> { + fn new(ty: Ty<'tcx>, proj_elem: Option) -> Self { + Self { ty, next_sibling: None, first_child: None, proj_elem, value_index: None } } } -struct Children<'a> { - map: &'a Map, +struct Children<'a, 'tcx> { + map: &'a Map<'tcx>, next: Option, } -impl<'a> Children<'a> { - fn new(map: &'a Map, parent: PlaceIndex) -> Self { +impl<'a, 'tcx> Children<'a, 'tcx> { + fn new(map: &'a Map<'tcx>, parent: PlaceIndex) -> Self { Self { map, next: map.places[parent].first_child } } } -impl<'a> Iterator for Children<'a> { +impl Iterator for Children<'_, '_> { type Item = PlaceIndex; fn next(&mut self) -> Option { @@ -1261,7 +1256,7 @@ fn debug_with_context_rec( place_str: &str, new: &StateData, old: Option<&StateData>, - map: &Map, + map: &Map<'_>, f: &mut Formatter<'_>, ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { @@ -1305,7 +1300,7 @@ fn debug_with_context_rec( fn debug_with_context( new: &StateData, old: Option<&StateData>, - map: &Map, + map: &Map<'_>, f: &mut Formatter<'_>, ) -> std::fmt::Result { for (local, place) in map.locals.iter_enumerated() { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8b965f4d18e4..8303ef039d18 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -66,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { } struct ConstAnalysis<'a, 'tcx> { - map: Map, + map: Map<'tcx>, tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, @@ -78,7 +78,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { const NAME: &'static str = "ConstAnalysis"; - fn map(&self) -> &Map { + fn map(&self) -> &Map<'tcx> { &self.map } @@ -330,7 +330,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); Self { map, @@ -560,12 +560,13 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { Self { patch: Patch::new(tcx), local_decls } } + #[instrument(level = "trace", skip(self, ecx, map), ret)] fn try_make_constant( &self, ecx: &mut InterpCx<'tcx, DummyMachine>, place: Place<'tcx>, state: &State>, - map: &Map, + map: &Map<'tcx>, ) -> Option> { let ty = place.ty(self.local_decls, self.patch.tcx).ty; let layout = ecx.layout_of(ty).ok()?; @@ -598,10 +599,11 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { } } +#[instrument(level = "trace", skip(map), ret)] fn propagatable_scalar( place: PlaceIndex, state: &State>, - map: &Map, + map: &Map<'_>, ) -> Option { if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_scalar_int().is_ok() @@ -613,14 +615,14 @@ fn propagatable_scalar( } } -#[instrument(level = "trace", skip(ecx, state, map))] +#[instrument(level = "trace", skip(ecx, state, map), ret)] fn try_write_constant<'tcx>( ecx: &mut InterpCx<'tcx, DummyMachine>, dest: &PlaceTy<'tcx>, place: PlaceIndex, ty: Ty<'tcx>, state: &State>, - map: &Map, + map: &Map<'tcx>, ) -> InterpResult<'tcx> { let layout = ecx.layout_of(ty)?; @@ -719,6 +721,7 @@ impl<'mir, 'tcx> { type FlowState = State>; + #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, @@ -740,6 +743,7 @@ impl<'mir, 'tcx> } } + #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, @@ -834,7 +838,7 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> { state: &'a State>, visitor: &'a mut Collector<'tcx, 'locals>, ecx: &'map mut InterpCx<'tcx, DummyMachine>, - map: &'map Map, + map: &'map Map<'tcx>, } impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 97ec0cb39ded..2100f4b4a1af 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -123,7 +123,7 @@ struct TOFinder<'tcx, 'a> { param_env: ty::ParamEnv<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, - map: &'a Map, + map: &'a Map<'tcx>, loop_headers: &'a BitSet, /// We use an arena to avoid cloning the slices when cloning `state`. arena: &'a DroplessArena, diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 9c18827d8e68..11a99f5395ec 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -81,101 +81,130 @@ Number of file 0 mappings: 11 = (((c4 + Zero) + Zero) + c3) Function name: try_error_result::test2 -Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] +Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 36 +Number of expressions: 59 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) -- expression 1 operands: lhs = Zero, rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(16), rhs = Zero -- expression 4 operands: lhs = Expression(7, Sub), rhs = Zero -- expression 5 operands: lhs = Counter(16), rhs = Zero -- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero -- expression 7 operands: lhs = Counter(16), rhs = Zero -- expression 8 operands: lhs = Expression(18, Sub), rhs = Zero -- expression 9 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 10 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 12 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 14 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 17 operands: lhs = Expression(18, Sub), rhs = Zero -- expression 18 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 20 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 21 operands: lhs = Expression(25, Sub), rhs = Zero -- expression 22 operands: lhs = Counter(17), rhs = Zero -- expression 23 operands: lhs = Counter(17), rhs = Zero -- expression 24 operands: lhs = Expression(25, Sub), rhs = Zero -- expression 25 operands: lhs = Counter(17), rhs = Zero -- expression 26 operands: lhs = Expression(30, Sub), rhs = Zero -- expression 27 operands: lhs = Counter(19), rhs = Zero -- expression 28 operands: lhs = Counter(19), rhs = Zero -- expression 29 operands: lhs = Expression(30, Sub), rhs = Zero -- expression 30 operands: lhs = Counter(19), rhs = Zero -- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(3) -- expression 32 operands: lhs = Expression(33, Add), rhs = Zero -- expression 33 operands: lhs = Zero, rhs = Expression(34, Add) -- expression 34 operands: lhs = Expression(35, Add), rhs = Zero -- expression 35 operands: lhs = Counter(6), rhs = Zero +- expression 3 operands: lhs = Counter(16), rhs = Counter(4) +- expression 4 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 5 operands: lhs = Counter(16), rhs = Counter(4) +- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(7) +- expression 7 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 8 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(16), rhs = Counter(4) +- expression 10 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 11 operands: lhs = Counter(16), rhs = Counter(4) +- expression 12 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 14 operands: lhs = Counter(16), rhs = Counter(4) +- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(7) +- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 18 operands: lhs = Counter(16), rhs = Counter(4) +- expression 19 operands: lhs = Expression(23, Sub), rhs = Counter(9) +- expression 20 operands: lhs = Counter(18), rhs = Counter(8) +- expression 21 operands: lhs = Counter(18), rhs = Counter(8) +- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(9) +- expression 23 operands: lhs = Counter(18), rhs = Counter(8) +- expression 24 operands: lhs = Expression(34, Sub), rhs = Counter(11) +- expression 25 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 26 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 27 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 28 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 29 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 30 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 31 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 32 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 33 operands: lhs = Expression(34, Sub), rhs = Counter(11) +- expression 34 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 36 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 37 operands: lhs = Expression(41, Sub), rhs = Counter(13) +- expression 38 operands: lhs = Counter(17), rhs = Counter(12) +- expression 39 operands: lhs = Counter(17), rhs = Counter(12) +- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(13) +- expression 41 operands: lhs = Counter(17), rhs = Counter(12) +- expression 42 operands: lhs = Expression(46, Sub), rhs = Counter(15) +- expression 43 operands: lhs = Counter(19), rhs = Counter(14) +- expression 44 operands: lhs = Counter(19), rhs = Counter(14) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(15) +- expression 46 operands: lhs = Counter(19), rhs = Counter(14) +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(54, Add) +- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(51, Add) +- expression 50 operands: lhs = Counter(4), rhs = Counter(5) +- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 52 operands: lhs = Counter(6), rhs = Counter(7) +- expression 53 operands: lhs = Counter(8), rhs = Counter(9) +- expression 54 operands: lhs = Expression(55, Add), rhs = Expression(56, Add) +- expression 55 operands: lhs = Counter(10), rhs = Counter(11) +- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(58, Add) +- expression 57 operands: lhs = Counter(12), rhs = Counter(13) +- expression 58 operands: lhs = Counter(14), rhs = Counter(15) Number of file 0 mappings: 40 - Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) - = (c0 + (Zero + c2)) -- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26) - = ((c0 + (Zero + c2)) - c3) + = (c0 + (c1 + c2)) +- Code(Expression(36, Sub)) at (prev + 2, 9) to (start + 4, 26) + = ((c0 + (c1 + c2)) - c3) - Code(Counter(16)) at (prev + 6, 13) to (start + 0, 47) -- Code(Zero) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(7, Sub)) at (prev + 0, 49) to (start + 3, 53) - = (c16 - Zero) -- Code(Zero) at (prev + 4, 17) to (start + 0, 18) -- Code(Expression(6, Sub)) at (prev + 2, 17) to (start + 4, 18) - = ((c16 - Zero) - Zero) -- Code(Zero) at (prev + 5, 17) to (start + 0, 20) -- Code(Expression(6, Sub)) at (prev + 0, 23) to (start + 0, 65) - = ((c16 - Zero) - Zero) +- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(18, Sub)) at (prev + 0, 49) to (start + 3, 53) + = (c16 - c4) +- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) +- Code(Expression(17, Sub)) at (prev + 2, 17) to (start + 4, 18) + = ((c16 - c4) - c5) +- Code(Expression(15, Sub)) at (prev + 5, 17) to (start + 0, 20) + = ((((c16 - c4) - c5) - c6) - c7) +- Code(Expression(17, Sub)) at (prev + 0, 23) to (start + 0, 65) + = ((c16 - c4) - c5) - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Zero) at (prev + 0, 67) to (start + 0, 95) -- Code(Zero) at (prev + 0, 95) to (start + 0, 96) -- Code(Zero) at (prev + 1, 13) to (start + 0, 32) -- Code(Zero) at (prev + 1, 17) to (start + 0, 20) -- Code(Zero) at (prev + 0, 23) to (start + 0, 65) -- Code(Zero) at (prev + 0, 65) to (start + 0, 66) -- Code(Zero) at (prev + 0, 67) to (start + 0, 96) -- Code(Zero) at (prev + 0, 96) to (start + 0, 97) -- Code(Zero) at (prev + 1, 13) to (start + 0, 32) -- Code(Expression(17, Sub)) at (prev + 4, 17) to (start + 0, 20) - = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero) -- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 66) - = (((c0 + (Zero + c2)) - c3) - c16) -- Code(Zero) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(18, Sub)) at (prev + 0, 68) to (start + 0, 97) - = ((((c0 + (Zero + c2)) - c3) - c16) - Zero) -- Code(Zero) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(17, Sub)) at (prev + 1, 13) to (start + 0, 32) - = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero) -- Code(Expression(24, Sub)) at (prev + 1, 17) to (start + 0, 20) - = ((c17 - Zero) - Zero) +- Code(Expression(16, Sub)) at (prev + 0, 67) to (start + 0, 95) + = (((c16 - c4) - c5) - c6) +- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) +- Code(Expression(15, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((((c16 - c4) - c5) - c6) - c7) +- Code(Expression(22, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c18 - c8) - c9) +- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 65) +- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) +- Code(Expression(23, Sub)) at (prev + 0, 67) to (start + 0, 96) + = (c18 - c8) +- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) +- Code(Expression(22, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((c18 - c8) - c9) +- Code(Expression(33, Sub)) at (prev + 4, 17) to (start + 0, 20) + = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) +- Code(Expression(35, Sub)) at (prev + 0, 23) to (start + 0, 66) + = (((c0 + (c1 + c2)) - c3) - c16) +- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) +- Code(Expression(34, Sub)) at (prev + 0, 68) to (start + 0, 97) + = ((((c0 + (c1 + c2)) - c3) - c16) - c10) +- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) +- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32) + = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) +- 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, 54) -- Code(Zero) at (prev + 1, 54) to (start + 0, 55) -- Code(Expression(25, Sub)) at (prev + 1, 18) to (start + 0, 47) - = (c17 - Zero) -- Code(Zero) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(24, Sub)) at (prev + 1, 13) to (start + 0, 32) - = ((c17 - Zero) - Zero) -- Code(Expression(29, Sub)) at (prev + 1, 17) to (start + 0, 20) - = ((c19 - Zero) - Zero) +- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) +- Code(Expression(41, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c17 - c12) +- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((c17 - c12) - c13) +- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c19 - c14) - c15) - Code(Counter(19)) at (prev + 0, 23) to (start + 1, 54) -- Code(Zero) at (prev + 2, 17) to (start + 0, 18) -- Code(Expression(30, Sub)) at (prev + 1, 18) to (start + 0, 47) - = (c19 - Zero) -- Code(Zero) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(29, Sub)) at (prev + 2, 13) to (start + 0, 32) - = ((c19 - Zero) - Zero) +- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) +- Code(Expression(46, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c19 - c14) +- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 32) + = ((c19 - c14) - c15) - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) -- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2) - = (((Zero + ((c6 + Zero) + Zero)) + Zero) + c3) +- Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((((c4 + c5) + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15)))) + c3) diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff index 98bd40ab2c3d..a77eb4708f2f 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff @@ -32,7 +32,7 @@ StorageDead(_5); StorageDead(_4); - _2 = I32(move _3); -+ _2 = const I32(0_i32); ++ _2 = I32(const 0_i32); StorageDead(_3); _0 = const (); StorageDead(_2); @@ -42,10 +42,6 @@ + } + + ALLOC0 (size: 4, align: 4) { -+ 00 00 00 00 │ .... -+ } -+ -+ ALLOC1 (size: 4, align: 4) { + 00 00 00 00 │ .... } diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs index 6152724c98f6..6e3c48c81dc2 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs @@ -15,6 +15,6 @@ fn main() { // CHECK: [[x]] = const I32(0_i32); let x = I32(0); - // CHECK: [[y]] = const I32(0_i32); + // CHECK: [[y]] = I32(const 0_i32); let y = I32(x.0 + x.0); } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index a6da1483c1ac..5e89382ea8f4 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -106,8 +106,7 @@ - _7 = (_10.0: f32); + _7 = const 4f32; StorageLive(_8); -- _8 = (_10.1: std::option::Option); -+ _8 = const Option::::Some(S(1_i32)); + _8 = (_10.1: std::option::Option); StorageLive(_9); _9 = (_10.2: &[f32]); StorageDead(_10); @@ -157,8 +156,7 @@ + _23 = const 82f32; StorageLive(_24); _37 = deref_copy (*_26); -- _24 = ((*_37).1: std::option::Option); -+ _24 = const Option::::Some(S(35_i32)); + _24 = ((*_37).1: std::option::Option); StorageLive(_25); _38 = deref_copy (*_26); _25 = ((*_38).2: &[f32]); @@ -168,12 +166,11 @@ - _28 = _23; + _28 = const 82f32; StorageLive(_29); -- _29 = _24; -+ _29 = const Option::::Some(S(35_i32)); + _29 = _24; StorageLive(_30); _30 = _25; - _27 = BigStruct(move _28, move _29, move _30); -+ _27 = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move _30); ++ _27 = BigStruct(const 82f32, move _29, move _30); StorageDead(_30); StorageDead(_29); StorageDead(_28); @@ -199,29 +196,21 @@ } } -+ ALLOC2 (size: 8, align: 4) { .. } -+ -+ ALLOC3 (size: 8, align: 4) { .. } -+ -+ ALLOC4 (size: 8, align: 4) { .. } -+ -+ ALLOC5 (size: 8, align: 4) { .. } -+ -+ ALLOC6 (size: 4, align: 4) { .. } ++ ALLOC2 (size: 4, align: 4) { .. } + ALLOC1 (static: BIG_STAT, size: 4, align: 4) { .. } - ALLOC2 (size: 20, align: 4) { .. } -+ ALLOC7 (size: 20, align: 4) { .. } ++ ALLOC3 (size: 20, align: 4) { .. } - ALLOC3 (size: 8, align: 4) { .. } -+ ALLOC8 (size: 8, align: 4) { .. } ++ ALLOC4 (size: 8, align: 4) { .. } ALLOC0 (static: SMALL_STAT, size: 4, align: 4) { .. } - ALLOC4 (size: 20, align: 4) { .. } -+ ALLOC9 (size: 20, align: 4) { .. } ++ ALLOC5 (size: 20, align: 4) { .. } - ALLOC5 (size: 4, align: 4) { .. } -+ ALLOC10 (size: 4, align: 4) { .. } ++ ALLOC6 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index 7ca25e442995..a707d7e5e76e 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -106,8 +106,7 @@ - _7 = (_10.0: f32); + _7 = const 4f32; StorageLive(_8); -- _8 = (_10.1: std::option::Option); -+ _8 = const Option::::Some(S(1_i32)); + _8 = (_10.1: std::option::Option); StorageLive(_9); _9 = (_10.2: &[f32]); StorageDead(_10); @@ -157,8 +156,7 @@ + _23 = const 82f32; StorageLive(_24); _37 = deref_copy (*_26); -- _24 = ((*_37).1: std::option::Option); -+ _24 = const Option::::Some(S(35_i32)); + _24 = ((*_37).1: std::option::Option); StorageLive(_25); _38 = deref_copy (*_26); _25 = ((*_38).2: &[f32]); @@ -168,12 +166,11 @@ - _28 = _23; + _28 = const 82f32; StorageLive(_29); -- _29 = _24; -+ _29 = const Option::::Some(S(35_i32)); + _29 = _24; StorageLive(_30); _30 = _25; - _27 = BigStruct(move _28, move _29, move _30); -+ _27 = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move _30); ++ _27 = BigStruct(const 82f32, move _29, move _30); StorageDead(_30); StorageDead(_29); StorageDead(_28); @@ -199,29 +196,21 @@ } } -+ ALLOC2 (size: 8, align: 4) { .. } -+ -+ ALLOC3 (size: 8, align: 4) { .. } -+ -+ ALLOC4 (size: 8, align: 4) { .. } -+ -+ ALLOC5 (size: 8, align: 4) { .. } -+ -+ ALLOC6 (size: 4, align: 4) { .. } ++ ALLOC2 (size: 4, align: 4) { .. } + ALLOC1 (static: BIG_STAT, size: 8, align: 8) { .. } - ALLOC2 (size: 32, align: 8) { .. } -+ ALLOC7 (size: 32, align: 8) { .. } ++ ALLOC3 (size: 32, align: 8) { .. } - ALLOC3 (size: 8, align: 4) { .. } -+ ALLOC8 (size: 8, align: 4) { .. } ++ ALLOC4 (size: 8, align: 4) { .. } ALLOC0 (static: SMALL_STAT, size: 8, align: 8) { .. } - ALLOC4 (size: 32, align: 8) { .. } -+ ALLOC9 (size: 32, align: 8) { .. } ++ ALLOC5 (size: 32, align: 8) { .. } - ALLOC5 (size: 4, align: 4) { .. } -+ ALLOC10 (size: 4, align: 4) { .. } ++ ALLOC6 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index 4b160c3dab7e..89ad1b870294 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -46,7 +46,7 @@ fn main() { const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); // CHECK: [[a1]] = const 4f32; - // CHECK: [[b1]] = const Option::::Some(S(1_i32)); + // CHECK: [[b1]] = ({{_.*}}.1: std::option::Option); // CHECK: [[c1]] = ({{_.*}}.2: &[f32]); let SmallStruct(a1, b1, c1) = SMALL_VAL; @@ -69,12 +69,12 @@ fn main() { static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]); // CHECK: [[a4]] = const 82f32; - // CHECK: [[b4]] = const Option::::Some(S(35_i32)); + // CHECK: [[b4]] = ((*{{_.*}}).1: std::option::Option); // CHECK: [[c4]] = ((*{{_.*}}).2: &[f32]); let BigStruct(a4, b4, c4) = *BIG_STAT; // We arbitrarily limit the size of synthetized values to 4 pointers. // `BigStruct` can be read, but we will keep a MIR aggregate for this. - // CHECK: [[bs]] = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move {{_.*}}); + // CHECK: [[bs]] = BigStruct(const 82f32, move {{.*}}, move {{_.*}}); let bs = BigStruct(a4, b4, c4); } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff index e4031b65caaf..0e14676efdf7 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff @@ -81,7 +81,7 @@ - _14 = _6; - _11 = (move _12, move _13, move _14); + _14 = const 11_i32; -+ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); ++ _11 = (const 6_i32, move _13, const 11_i32); StorageDead(_14); StorageDead(_13); StorageDead(_12); @@ -99,6 +99,4 @@ + ALLOC1 (size: 8, align: 4) { .. } + + ALLOC2 (size: 8, align: 4) { .. } -+ -+ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff index e4031b65caaf..0e14676efdf7 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff @@ -81,7 +81,7 @@ - _14 = _6; - _11 = (move _12, move _13, move _14); + _14 = const 11_i32; -+ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); ++ _11 = (const 6_i32, move _13, const 11_i32); StorageDead(_14); StorageDead(_13); StorageDead(_12); @@ -99,6 +99,4 @@ + ALLOC1 (size: 8, align: 4) { .. } + + ALLOC2 (size: 8, align: 4) { .. } -+ -+ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index 19b675770abe..ed794ca658ce 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -23,6 +23,7 @@ fn main() { // CHECK: [[c]] = const 11_i32; let c = a.0 + a.1 + b; - // CHECK: [[d]] = (const 6_i32, const (2_i32, 3_i32), const 11_i32); + // CHECK: [[a2:_.*]] = const (2_i32, 3_i32); + // CHECK: [[d]] = (const 6_i32, move [[a2]], const 11_i32); let d = (b, a, c); } From af876626b057bd4c1cf73897b8313f1d09ea6176 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 28 Jun 2024 13:01:27 +0000 Subject: [PATCH 287/361] Add test for copying aggregates. --- .../aggregate_copy.foo.DataflowConstProp.diff | 55 +++++++++++++++++++ .../dataflow-const-prop/aggregate_copy.rs | 40 ++++++++++++++ ...regate_copy.JumpThreading.panic-abort.diff | 55 +++++++++++++++++++ ...egate_copy.JumpThreading.panic-unwind.diff | 55 +++++++++++++++++++ tests/mir-opt/jump_threading.rs | 16 ++++++ 5 files changed, 221 insertions(+) create mode 100644 tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff create mode 100644 tests/mir-opt/dataflow-const-prop/aggregate_copy.rs create mode 100644 tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff create mode 100644 tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff new file mode 100644 index 000000000000..19bbbad51230 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -0,0 +1,55 @@ +- // MIR for `foo` before DataflowConstProp ++ // MIR for `foo` after DataflowConstProp + + fn foo() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Ge(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs new file mode 100644 index 000000000000..595f38132ee1 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -0,0 +1,40 @@ +//! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning +//! the contained scalars. +//@ test-mir-pass: DataflowConstProp + +const Foo: (u32, u32) = (5, 3); + +fn foo() -> u32 { + // CHECK-LABEL: fn foo( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + + // CHECK:bb0: { + // CHECK: [[a]] = const Foo; + // CHECK: [[b]] = [[a]]; + // CHECK: [[c]] = ([[b]].1: u32); + // CHECK: switchInt(move {{_.*}}) -> [0: bb2, otherwise: bb1]; + + // CHECK:bb1: { + // CHECK: _0 = ([[b]].0: u32); + // CHECK: goto -> bb3; + + // CHECK:bb2: { + // CHECK: _0 = const 13_u32; + // CHECK: goto -> bb3; + + let a = Foo; + // This copies the struct in `a`. We want to ensure that we do track the contents of `a` + // because we need to read `b` later. + let b = a; + let c = b.1; + if c >= 2 { b.0 } else { 13 } +} + +fn main() { + // CHECK-LABEL: fn main( + foo(); +} + +// EMIT_MIR aggregate_copy.foo.DataflowConstProp.diff diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..ec62ba2feeaa --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff @@ -0,0 +1,55 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..ec62ba2feeaa --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff @@ -0,0 +1,55 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index b4c133716800..59b5b2c6eea3 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -506,6 +506,21 @@ fn assume(a: u8, b: bool) -> u8 { } } +/// Verify that jump threading succeeds seeing through copies of aggregates. +fn aggregate_copy() -> u32 { + // CHECK-LABEL: fn aggregate_copy( + // CHECK: switchInt( + + const Foo: (u32, u32) = (5, 3); + + let a = Foo; + // This copies a tuple, we want to ensure that the threading condition on `b.1` propagates to a + // condition on `a.1`. + let b = a; + let c = b.1; + if c == 2 { b.0 } else { 13 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -534,3 +549,4 @@ fn main() { // EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff // EMIT_MIR jump_threading.aggregate.JumpThreading.diff // EMIT_MIR jump_threading.assume.JumpThreading.diff +// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff From 7ac7f135e3938c55e2fccb194ece52519c1797d2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 28 Jun 2024 13:02:08 +0000 Subject: [PATCH 288/361] Propagate places through assignments. --- .../rustc_mir_dataflow/src/value_analysis.rs | 119 ++++++++++++++++-- .../aggregate_copy.foo.DataflowConstProp.diff | 22 +++- .../dataflow-const-prop/aggregate_copy.rs | 10 +- ...pr_transparent.main.DataflowConstProp.diff | 6 +- .../dataflow-const-prop/repr_transparent.rs | 2 +- ...te.less_as_i8.DataflowConstProp.32bit.diff | 14 ++- ...te.less_as_i8.DataflowConstProp.64bit.diff | 14 ++- .../tuple.main.DataflowConstProp.32bit.diff | 4 +- .../tuple.main.DataflowConstProp.64bit.diff | 4 +- tests/mir-opt/dataflow-const-prop/tuple.rs | 3 +- ...regate_copy.JumpThreading.panic-abort.diff | 3 +- ...egate_copy.JumpThreading.panic-unwind.diff | 3 +- tests/mir-opt/jump_threading.rs | 2 +- 13 files changed, 173 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index f21a24191444..c9f5d38fe2c1 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -36,7 +36,7 @@ use std::fmt::{Debug, Formatter}; use std::ops::Range; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, StdEntry}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -799,7 +799,52 @@ impl<'tcx> Map<'tcx> { self.locals[local] = Some(place); } - PlaceCollector { tcx, body, map: self }.visit_body(body); + // Collect syntactic places and assignments between them. + let mut collector = + PlaceCollector { tcx, body, map: self, assignments: Default::default() }; + collector.visit_body(body); + let PlaceCollector { mut assignments, .. } = collector; + + // Just collecting syntactic places is not enough. We may need to propagate this pattern: + // _1 = (const 5u32, const 13i64); + // _2 = _1; + // _3 = (_2.0 as u32); + // + // `_1.0` does not appear, but we still need to track it. This is achieved by propagating + // projections from assignments. We recorded an assignment between `_2` and `_1`, so we + // want `_1` and `_2` to have the same sub-places. + // + // This is what this fixpoint loop does. While we are still creating places, run through + // all the assignments, and register places for children. + let mut num_places = 0; + while num_places < self.places.len() { + num_places = self.places.len(); + + for assign in 0.. { + let Some(&(lhs, rhs)) = assignments.get_index(assign) else { break }; + + // Mirror children from `lhs` in `rhs`. + let mut child = self.places[lhs].first_child; + while let Some(lhs_child) = child { + let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[lhs_child]; + let rhs_child = + self.register_place(ty, rhs, proj_elem.expect("child is not a projection")); + assignments.insert((lhs_child, rhs_child)); + child = next_sibling; + } + + // Conversely, mirror children from `rhs` in `lhs`. + let mut child = self.places[rhs].first_child; + while let Some(rhs_child) = child { + let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[rhs_child]; + let lhs_child = + self.register_place(ty, lhs, proj_elem.expect("child is not a projection")); + assignments.insert((lhs_child, rhs_child)); + child = next_sibling; + } + } + } + drop(assignments); // Create values for places whose type have scalar layout. let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); @@ -882,17 +927,14 @@ struct PlaceCollector<'a, 'b, 'tcx> { tcx: TyCtxt<'tcx>, body: &'b Body<'tcx>, map: &'a mut Map<'tcx>, + assignments: FxIndexSet<(PlaceIndex, PlaceIndex)>, } -impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { +impl<'tcx> PlaceCollector<'_, '_, 'tcx> { #[tracing::instrument(level = "trace", skip(self))] - fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) { - if !ctxt.is_use() { - return; - } - + fn register_place(&mut self, place: Place<'tcx>) -> Option { // Create a place for this projection. - let Some(mut place_index) = self.map.locals[place.local] else { return }; + let mut place_index = self.map.locals[place.local]?; let mut ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); tracing::trace!(?place_index, ?ty); @@ -906,7 +948,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { } for proj in place.projection { - let Ok(track_elem) = proj.try_into() else { return }; + let track_elem = proj.try_into().ok()?; ty = ty.projection_ty(self.tcx, proj); place_index = self.map.register_place(ty.ty, place_index, track_elem); tracing::trace!(?proj, ?place_index, ?ty); @@ -920,6 +962,63 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); } } + + Some(place_index) + } +} + +impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { + #[tracing::instrument(level = "trace", skip(self))] + fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) { + if !ctxt.is_use() { + return; + } + + self.register_place(*place); + } + + fn visit_assign(&mut self, lhs: &Place<'tcx>, rhs: &Rvalue<'tcx>, location: Location) { + self.super_assign(lhs, rhs, location); + + match rhs { + Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) | Rvalue::CopyForDeref(rhs) => { + let Some(lhs) = self.register_place(*lhs) else { return }; + let Some(rhs) = self.register_place(*rhs) else { return }; + self.assignments.insert((lhs, rhs)); + } + Rvalue::Aggregate(kind, fields) => { + let Some(mut lhs) = self.register_place(*lhs) else { return }; + match **kind { + // Do not propagate unions. + AggregateKind::Adt(_, _, _, _, Some(_)) => return, + AggregateKind::Adt(_, variant, _, _, None) => { + let ty = self.map.places[lhs].ty; + if ty.is_enum() { + lhs = self.map.register_place(ty, lhs, TrackElem::Variant(variant)); + } + } + AggregateKind::RawPtr(..) + | AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(..) + | AggregateKind::Coroutine(..) + | AggregateKind::CoroutineClosure(..) => {} + } + for (index, field) in fields.iter_enumerated() { + if let Some(rhs) = field.place() + && let Some(rhs) = self.register_place(rhs) + { + let lhs = self.map.register_place( + self.map.places[rhs].ty, + lhs, + TrackElem::Field(index), + ); + self.assignments.insert((lhs, rhs)); + } + } + } + _ => {} + } } } diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff index 19bbbad51230..1aeaaff21dce 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -22,19 +22,25 @@ StorageLive(_1); _1 = const Foo; StorageLive(_2); - _2 = _1; +- _2 = _1; ++ _2 = const (5_u32, 3_u32); StorageLive(_3); - _3 = (_2.1: u32); +- _3 = (_2.1: u32); ++ _3 = const 3_u32; StorageLive(_4); StorageLive(_5); - _5 = _3; - _4 = Ge(move _5, const 2_u32); - switchInt(move _4) -> [0: bb2, otherwise: bb1]; +- _5 = _3; +- _4 = Ge(move _5, const 2_u32); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ _5 = const 3_u32; ++ _4 = const true; ++ switchInt(const true) -> [0: bb2, otherwise: bb1]; } bb1: { StorageDead(_5); - _0 = (_2.0: u32); +- _0 = (_2.0: u32); ++ _0 = const 5_u32; goto -> bb3; } @@ -51,5 +57,9 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 05 00 00 00 03 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs index 595f38132ee1..aca5f047222f 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -12,12 +12,14 @@ fn foo() -> u32 { // CHECK:bb0: { // CHECK: [[a]] = const Foo; - // CHECK: [[b]] = [[a]]; - // CHECK: [[c]] = ([[b]].1: u32); - // CHECK: switchInt(move {{_.*}}) -> [0: bb2, otherwise: bb1]; + // CHECK: [[b]] = const (5_u32, 3_u32); + // CHECK: [[c]] = const 3_u32; + // CHECK: {{_.*}} = const 3_u32; + // CHECK: {{_.*}} = const true; + // CHECK: switchInt(const true) -> [0: bb2, otherwise: bb1]; // CHECK:bb1: { - // CHECK: _0 = ([[b]].0: u32); + // CHECK: _0 = const 5_u32; // CHECK: goto -> bb3; // CHECK:bb2: { diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff index a77eb4708f2f..98bd40ab2c3d 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff @@ -32,7 +32,7 @@ StorageDead(_5); StorageDead(_4); - _2 = I32(move _3); -+ _2 = I32(const 0_i32); ++ _2 = const I32(0_i32); StorageDead(_3); _0 = const (); StorageDead(_2); @@ -42,6 +42,10 @@ + } + + ALLOC0 (size: 4, align: 4) { ++ 00 00 00 00 │ .... ++ } ++ ++ ALLOC1 (size: 4, align: 4) { + 00 00 00 00 │ .... } diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs index 6e3c48c81dc2..6152724c98f6 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs @@ -15,6 +15,6 @@ fn main() { // CHECK: [[x]] = const I32(0_i32); let x = I32(0); - // CHECK: [[y]] = I32(const 0_i32); + // CHECK: [[y]] = const I32(0_i32); let y = I32(x.0 + x.0); } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff index 44dd40174092..a023243ad9da 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff @@ -7,10 +7,20 @@ bb0: { StorageLive(_1); - _1 = Less; - _0 = move _1 as i8 (Transmute); +- _1 = Less; +- _0 = move _1 as i8 (Transmute); ++ _1 = const Less; ++ _0 = const std::cmp::Ordering::Less as i8 (Transmute); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 1, align: 1) { ++ ff │ . ++ } ++ ++ ALLOC1 (size: 1, align: 1) { ++ ff │ . } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff index 44dd40174092..a023243ad9da 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff @@ -7,10 +7,20 @@ bb0: { StorageLive(_1); - _1 = Less; - _0 = move _1 as i8 (Transmute); +- _1 = Less; +- _0 = move _1 as i8 (Transmute); ++ _1 = const Less; ++ _0 = const std::cmp::Ordering::Less as i8 (Transmute); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 1, align: 1) { ++ ff │ . ++ } ++ ++ ALLOC1 (size: 1, align: 1) { ++ ff │ . } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff index 0e14676efdf7..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff @@ -81,7 +81,7 @@ - _14 = _6; - _11 = (move _12, move _13, move _14); + _14 = const 11_i32; -+ _11 = (const 6_i32, move _13, const 11_i32); ++ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); StorageDead(_14); StorageDead(_13); StorageDead(_12); @@ -99,4 +99,6 @@ + ALLOC1 (size: 8, align: 4) { .. } + + ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff index 0e14676efdf7..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff @@ -81,7 +81,7 @@ - _14 = _6; - _11 = (move _12, move _13, move _14); + _14 = const 11_i32; -+ _11 = (const 6_i32, move _13, const 11_i32); ++ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); StorageDead(_14); StorageDead(_13); StorageDead(_12); @@ -99,4 +99,6 @@ + ALLOC1 (size: 8, align: 4) { .. } + + ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index ed794ca658ce..19b675770abe 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -23,7 +23,6 @@ fn main() { // CHECK: [[c]] = const 11_i32; let c = a.0 + a.1 + b; - // CHECK: [[a2:_.*]] = const (2_i32, 3_i32); - // CHECK: [[d]] = (const 6_i32, move [[a2]], const 11_i32); + // CHECK: [[d]] = (const 6_i32, const (2_i32, 3_i32), const 11_i32); let d = (b, a, c); } diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff index ec62ba2feeaa..0c8e04a1e74d 100644 --- a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff @@ -29,7 +29,8 @@ StorageLive(_5); _5 = _3; _4 = Eq(move _5, const 2_u32); - switchInt(move _4) -> [0: bb2, otherwise: bb1]; +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff index ec62ba2feeaa..0c8e04a1e74d 100644 --- a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff @@ -29,7 +29,8 @@ StorageLive(_5); _5 = _3; _4 = Eq(move _5, const 2_u32); - switchInt(move _4) -> [0: bb2, otherwise: bb1]; +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 59b5b2c6eea3..de290c1ef447 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -509,7 +509,7 @@ fn assume(a: u8, b: bool) -> u8 { /// Verify that jump threading succeeds seeing through copies of aggregates. fn aggregate_copy() -> u32 { // CHECK-LABEL: fn aggregate_copy( - // CHECK: switchInt( + // CHECK-NOT: switchInt( const Foo: (u32, u32) = (5, 3); From 6e3cff70948b2292467f2e3e1b14d14372956034 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 Jul 2024 11:18:58 +0000 Subject: [PATCH 289/361] Bless coverage. --- tests/coverage/closure.cov-map | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index f36ef7af7ac3..6edd35921fe9 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -31,16 +31,18 @@ Number of file 0 mappings: 24 = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) -Function name: closure::main::{closure#0} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +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, 0a, 00, 0b, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Zero) at (prev + 40, 5) to (start + 2, 20) -- Code(Zero) at (prev + 2, 21) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) -- Code(Zero) at (prev + 1, 9) to (start + 1, 6) +- 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, 10) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Function name: closure::main::{closure#10} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] From 6cd19116bce6484cdcc8092cf809600762f78203 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 13 Jul 2024 13:28:55 +0100 Subject: [PATCH 290/361] std::unix::fs: removing, now useless, layers predating macOs 10.10. fdopendir, openat and unlinkat are available since yosemite but we support sierra as minimum. --- library/std/src/sys/pal/unix/fs.rs | 60 +----------------------------- 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index f9d6b5fbc86a..8308a48f16a9 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -2010,56 +2010,10 @@ mod remove_dir_impl { use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::{cvt, cvt_r}; - #[cfg(not(any( - all(target_os = "linux", target_env = "gnu"), - all(target_os = "macos", not(target_arch = "aarch64")) - )))] + #[cfg(not(all(target_os = "linux", target_env = "gnu")))] use libc::{fdopendir, openat, unlinkat}; #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{fdopendir, openat64 as openat, unlinkat}; - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - use macos_weak::{fdopendir, openat, unlinkat}; - - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - mod macos_weak { - use crate::sys::weak::weak; - use libc::{c_char, c_int, DIR}; - - fn get_openat_fn() -> Option c_int> { - weak!(fn openat(c_int, *const c_char, c_int) -> c_int); - openat.get() - } - - pub fn has_openat() -> bool { - get_openat_fn().is_some() - } - - pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { - get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - -1 - }) - } - - pub unsafe fn fdopendir(fd: c_int) -> *mut DIR { - #[cfg(all(target_os = "macos", target_arch = "x86"))] - weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64$UNIX2003"); - #[cfg(all(target_os = "macos", target_arch = "x86_64"))] - weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); - fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - crate::ptr::null_mut() - }) - } - - pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { - weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); - unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - -1 - }) - } - } pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { let fd = cvt_r(|| unsafe { @@ -2172,19 +2126,7 @@ mod remove_dir_impl { } } - #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64"))))] pub fn remove_dir_all(p: &Path) -> io::Result<()> { remove_dir_all_modern(p) } - - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - pub fn remove_dir_all(p: &Path) -> io::Result<()> { - if macos_weak::has_openat() { - // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() - remove_dir_all_modern(p) - } else { - // fall back to classic implementation - crate::sys_common::fs::remove_dir_all(p) - } - } } From 90c9e32ad26b1ff6d683047a552d8cf2448fe2ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2024 14:40:30 +0200 Subject: [PATCH 291/361] consolidate miri-unleashed tests for mutable refs into one file --- .../miri_unleashed/mutable_references.rs | 90 ++++- .../miri_unleashed/mutable_references.stderr | 333 ++++++++++++++++-- .../miri_unleashed/mutable_references_err.rs | 95 ----- .../mutable_references_err.stderr | 308 ---------------- 4 files changed, 399 insertions(+), 427 deletions(-) delete mode 100644 tests/ui/consts/miri_unleashed/mutable_references_err.rs delete mode 100644 tests/ui/consts/miri_unleashed/mutable_references_err.stderr diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index efb346f91aef..7e759a1a1e42 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -2,13 +2,20 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +#![allow(static_mut_refs)] #![deny(const_eval_mutable_ptr_in_final_value)] use std::cell::UnsafeCell; +use std::sync::atomic::*; + +// # Plain `&mut` in the final value // This requires walking nested statics. static FOO: &&mut u32 = &&mut 42; //~^ ERROR it is undefined behavior to use this value - +//~| pointing to read-only memory +static OH_YES: &mut i32 = &mut 42; +//~^ ERROR it is undefined behavior to use this value +//~| pointing to read-only memory static BAR: &mut () = &mut (); //~^ ERROR encountered mutable pointer in final value of static //~| WARNING this was previously accepted by the compiler @@ -19,15 +26,92 @@ static BOO: &mut Foo<()> = &mut Foo(()); //~^ ERROR encountered mutable pointer in final value of static //~| WARNING this was previously accepted by the compiler +const BLUNT: &mut i32 = &mut 42; +//~^ ERROR: it is undefined behavior to use this value +//~| pointing to read-only memory + +const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; +//~^ ERROR: it is undefined behavior to use this value +//~| static + +// # Interior mutability + struct Meh { x: &'static UnsafeCell, } unsafe impl Sync for Meh {} static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; //~^ ERROR it is undefined behavior to use this value +//~| `UnsafeCell` in read-only memory +// Same with a const: +// the following will never be ok! no interior mut behind consts, because +// all allocs interned here will be marked immutable. +const MUH: Meh = Meh { + //~^ ERROR it is undefined behavior to use this value + //~| `UnsafeCell` in read-only memory + x: &UnsafeCell::new(42), +}; + +struct Synced { + x: UnsafeCell, +} +unsafe impl Sync for Synced {} + +// Make sure we also catch this behind a type-erased `dyn Trait` reference. +const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; +//~^ ERROR: it is undefined behavior to use this value +//~| `UnsafeCell` in read-only memory + +// # Check for mutable references to read-only memory + +static READONLY: i32 = 0; +static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; +//~^ ERROR: it is undefined behavior to use this value +//~| pointing to read-only memory + +// # Check for consts pointing to mutable memory + +static mut MUTABLE: i32 = 42; +const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior +//~| encountered reference to mutable memory +static mut MUTABLE_REF: &mut i32 = &mut 42; +const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; +//~^ ERROR: evaluation of constant value failed +//~| accesses mutable global memory + +const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +struct SyncPtr { + x: *const T, +} +unsafe impl Sync for SyncPtr {} + +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// However, we intern the inner memory as read-only, so this must be rejected. +// (Also see `static-no-inner-mut` for similar tests on `static`.) +const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler -static OH_YES: &mut i32 = &mut 42; -//~^ ERROR it is undefined behavior to use this value fn main() { unsafe { diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index b207e3869ac8..620953ffa3e2 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:9:1 + --> $DIR/mutable_references.rs:13:1 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered mutable reference or box pointing to read-only memory @@ -9,8 +9,19 @@ LL | static FOO: &&mut u32 = &&mut 42; HEX_DUMP } +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:16:1 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:12:1 + --> $DIR/mutable_references.rs:19:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ @@ -18,13 +29,13 @@ LL | static BAR: &mut () = &mut (); = 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 #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:18:1 + --> $DIR/mutable_references.rs:25:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +44,29 @@ LL | static BOO: &mut Foo<()> = &mut Foo(()); = note: for more information, see issue #122153 error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:26:1 + --> $DIR/mutable_references.rs:29:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:33:1 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:43:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -44,18 +77,111 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:29:1 + --> $DIR/mutable_references.rs:49:1 | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:61:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:68:1 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:75:1 + | +LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/mutable_references.rs:78:43 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^^^ constant accesses mutable global memory + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:82:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:86:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:90:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:103:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:107:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:111:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 + error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:36:5 + --> $DIR/mutable_references.rs:120:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -63,38 +189,113 @@ LL | *OH_YES = 99; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:9:26 + --> $DIR/mutable_references.rs:13:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:12:23 + --> $DIR/mutable_references.rs:16:27 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:19:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:18:28 + --> $DIR/mutable_references.rs:25:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:26:28 + --> $DIR/mutable_references.rs:29:25 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:33:68 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:33:63 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:43:28 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:29:27 + --> $DIR/mutable_references.rs:52:8 | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^ +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:61:27 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:68:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:68:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:75:43 + | +LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:78:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:82:45 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:86:46 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:90:47 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:103:51 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:107:49 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:111:51 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 19 previous errors; 1 warning emitted Some errors have detailed explanations: E0080, E0594. For more information about an error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:12:1 + --> $DIR/mutable_references.rs:19:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ @@ -102,14 +303,14 @@ LL | static BAR: &mut () = &mut (); = 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 #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Future breakage diagnostic: error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:18:1 + --> $DIR/mutable_references.rs:25:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +318,97 @@ LL | static BOO: &mut Foo<()> = &mut Foo(()); = 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 #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:82:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:86:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:90:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:103:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:107:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:111:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs deleted file mode 100644 index 8398b0758ddd..000000000000 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs +++ /dev/null @@ -1,95 +0,0 @@ -//@ compile-flags: -Zunleash-the-miri-inside-of-you -//@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -//@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![allow(invalid_reference_casting, static_mut_refs)] -#![deny(const_eval_mutable_ptr_in_final_value)] -use std::cell::UnsafeCell; -use std::sync::atomic::*; - -// this test ensures that our mutability story is sound - -struct Meh { - x: &'static UnsafeCell, -} -unsafe impl Sync for Meh {} - -// the following will never be ok! no interior mut behind consts, because -// all allocs interned here will be marked immutable. -const MUH: Meh = Meh { - //~^ ERROR it is undefined behavior to use this value - x: &UnsafeCell::new(42), -}; - -struct Synced { - x: UnsafeCell, -} -unsafe impl Sync for Synced {} - -// Make sure we also catch this behind a type-erased `dyn Trait` reference. -const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; -//~^ ERROR: it is undefined behavior to use this value - -// Make sure we also catch mutable references in values that shouldn't have them. -static mut FOO: i32 = 0; -const SUBTLE: &mut i32 = unsafe { &mut FOO }; -//~^ ERROR: it is undefined behavior to use this value -//~| static - -const BLUNT: &mut i32 = &mut 42; -//~^ ERROR: it is undefined behavior to use this value - -// Check for mutable references to read-only memory. -static READONLY: i32 = 0; -static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; -//~^ ERROR: it is undefined behavior to use this value -//~| pointing to read-only memory - -// Check for consts pointing to mutable memory. -// These are fine as long as they are not being read. -static mut MUTABLE: i32 = 42; -const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior -//~| encountered reference to mutable memory -const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1; -static mut MUTABLE_REF: &mut i32 = &mut 42; -const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; -//~^ ERROR: evaluation of constant value failed -//~| accesses mutable global memory - -const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -struct SyncPtr { - x: *const T, -} -unsafe impl Sync for SyncPtr {} - -// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. -// (This relies on `SyncPtr` being a curly brace struct.) -// However, we intern the inner memory as read-only, so this must be rejected. -// (Also see `static-no-inner-mut` for similar tests on `static`.) -const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -fn main() { - unsafe { - *MUH.x.get() = 99; - } -} diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.stderr deleted file mode 100644 index d385b45a3df9..000000000000 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr +++ /dev/null @@ -1,308 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:18:1 - | -LL | const MUH: Meh = Meh { - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:29:1 - | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:34:1 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:38:1 - | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:43:1 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:50:1 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -note: erroneous constant encountered - --> $DIR/mutable_references_err.rs:52:34 - | -LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1; - | ^^^^^^^^^^^^^^^^^^ - -error[E0080]: evaluation of constant value failed - --> $DIR/mutable_references_err.rs:54:43 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^^^ constant accesses mutable global memory - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:58:1 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:62:1 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:66:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:79:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:83:1 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:87:1 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 - -warning: skipping const checks - | -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:20:8 - | -LL | x: &UnsafeCell::new(42), - | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:29:27 - | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:34:40 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:34:35 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:38:25 - | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:43:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:43:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:50:44 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:54:45 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:58:45 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:62:46 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:66:47 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:79:51 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:83:49 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:87:51 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^ - -error: aborting due to 13 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0080`. -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:58:1 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:62:1 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:66:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:79:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:83:1 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:87:1 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - From f5c3195e92d436e49132d193210bd268901f6fa1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jul 2024 13:52:56 +0000 Subject: [PATCH 292/361] Nicer error message when using raw-dylib cc rust-lang/rustc_codegen_cranelift#1510 --- src/archive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 414d3db1c51a..3f23e0d9e046 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -14,12 +14,12 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn create_dll_import_lib( &self, - _sess: &Session, + sess: &Session, _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &Path, _is_direct_dependency: bool, ) -> PathBuf { - unimplemented!("creating dll imports is not yet supported"); + sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift"); } } From fc0d1dc99bc579b07ad59733d74e9ec6e823d6e9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 13 Jul 2024 10:04:33 +0300 Subject: [PATCH 293/361] use `ModeToolBootstrap` for run-make-support's crate tests We don't need to ensure std (and rustc) for testing run-make-support's unit tests. Using stage 0 compiler is already enough and speeds up `x test run-make-support` invocations on a clean build. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0b60587bb792..33517c5e2e44 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1325,13 +1325,12 @@ impl Step for CrateRunMakeSupport { /// Runs `cargo test` for run-make-support. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(builder.top_stage, host); + let compiler = builder.compiler(0, host); - builder.ensure(compile::Std::new(compiler, host)); let mut cargo = tool::prepare_tool_cargo( builder, compiler, - Mode::ToolStd, + Mode::ToolBootstrap, host, "test", "src/tools/run-make-support", From 41070bd9381bc0604171eba9308869eecd94b20b Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 13 Jul 2024 19:58:36 +0300 Subject: [PATCH 294/361] explain why we use in-tree std for compiletest Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 33517c5e2e44..1fa58040a119 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -686,6 +686,8 @@ impl Step for CompiletestTest { let mut cargo = tool::prepare_tool_cargo( builder, compiler, + // compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks + // when std sources change. Mode::ToolStd, host, "test", From 739dfcab8e6ee3e3c736d43bdbea8f1cb0710bfc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:32:48 +0000 Subject: [PATCH 295/361] Rustup to rustc 1.81.0-nightly (c6727fc9b 2024-07-12) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 92ea4fc4b270..db9b551bd2a2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-07-09" +channel = "nightly-2024-07-13" components = ["rust-src", "rustc-dev", "llvm-tools"] From 659243d85c7489412bd0faa1c068d904a6042941 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:38:35 +0000 Subject: [PATCH 296/361] Fix rustc test suite --- scripts/test_rustc_tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index ebe0b634e8b2..f0550c23b177 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -64,7 +64,6 @@ rm -r tests/run-make/cdylib rm -r tests/run-make/codegen-options-parsing rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 -rm -r tests/run-make/issue-109934-lto-debuginfo rm -r tests/run-make/no-builtins-lto rm -r tests/run-make/reachable-extern-fn-available-lto From e2c15fe03bcfec07233e8c61dfbb652602c07100 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 14 Jul 2024 00:41:05 +0300 Subject: [PATCH 297/361] use std for file mtime and atime modifications Since 1.75 std provides an interface to set access and modified times on files. This change replaces the external dependency previously used for these operations with the corresponding std functions. Signed-off-by: onur-ozkan --- src/bootstrap/Cargo.lock | 1 - src/bootstrap/Cargo.toml | 1 - src/bootstrap/src/core/build_steps/compile.rs | 7 ++++--- src/bootstrap/src/core/download.rs | 8 ++++++-- src/bootstrap/src/lib.rs | 11 +++++++---- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index c095127da140..de0924c0f423 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -48,7 +48,6 @@ dependencies = [ "clap_complete", "cmake", "fd-lock", - "filetime", "home", "ignore", "junction", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index df7b5b881931..f723407c3ce3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,7 +44,6 @@ build_helper = { path = "../tools/build_helper" } clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.4" fd-lock = "4.0" -filetime = "0.2" home = "0.5" ignore = "0.4" libc = "0.2" diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11a7a4045351..df463966d205 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -33,7 +33,6 @@ use crate::utils::helpers::{ }; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; -use filetime::FileTime; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { @@ -2160,9 +2159,11 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) return; } - let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap()); + let previous_mtime = t!(t!(path.metadata()).modified()); command("strip").capture().arg("--strip-debug").arg(path).run(builder); + let file = t!(fs::File::open(path)); + // After running `strip`, we have to set the file modification time to what it was before, // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time // bootstrap is invoked. @@ -2175,5 +2176,5 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) // In the second invocation of bootstrap, Cargo will see that the mtime of librustc_driver.so // is greater than the mtime of rustc-main, and will rebuild rustc-main. That will then cause // everything else (standard library, future stages...) to be rebuilt. - t!(filetime::set_file_mtime(path, previous_mtime)); + t!(file.set_modified(previous_mtime)); } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index a7f4bb0cf146..d01a910e815d 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -702,9 +702,13 @@ download-rustc = false // time `rustc_llvm` build script ran. However, the timestamps of the // files in the tarball are in the past, so it doesn't trigger a // rebuild. - let now = filetime::FileTime::from_system_time(std::time::SystemTime::now()); + let now = std::time::SystemTime::now(); + let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now); + let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build)); - t!(filetime::set_file_times(llvm_config, now, now)); + let llvm_config_file = t!(File::open(llvm_config)); + + t!(llvm_config_file.set_times(file_times)); if self.should_fix_bins_and_dylibs() { let llvm_lib = llvm_root.join("lib"); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index f16afb297965..4b30b460f262 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -30,7 +30,6 @@ use std::time::SystemTime; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; -use filetime::FileTime; use sha2::digest::Digest; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::channel::GitInfo; @@ -1693,9 +1692,13 @@ impl Build { panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) } t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); + + let file_times = fs::FileTimes::new() + .set_accessed(t!(metadata.accessed())) + .set_modified(t!(metadata.modified())); + + let dst_file = t!(fs::File::open(dst)); + t!(dst_file.set_times(file_times)); } } From 99a5964b737bd78b471cca5da39e0d0f54e9eb36 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 13 Jul 2024 16:56:13 -0700 Subject: [PATCH 298/361] Fix minor typos in std::process doc on Win argv --- library/std/src/process.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f351dab78dc1..fc86578a5ff2 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -96,9 +96,9 @@ //! child processes must agree on how the commandline string is encoded. //! //! Most programs use the standard C run-time `argv`, which in practice results -//! in consistent argument handling. However some programs have their own way of +//! in consistent argument handling. However, some programs have their own way of //! parsing the commandline string. In these cases using [`arg`] or [`args`] may -//! result in the child process seeing a different array of arguments then the +//! result in the child process seeing a different array of arguments than the //! parent process intended. //! //! Two ways of mitigating this are: From 193767e6505120dfdb3373525ba2bc0d958378dc Mon Sep 17 00:00:00 2001 From: tesuji <15225902+tesuji@users.noreply.github.com> Date: Sun, 14 Jul 2024 00:51:08 +0000 Subject: [PATCH 299/361] doc: Suggest `str::repeat` over `iter::repeat().take().collect()` Using ../../std syntax because of difficulty link alloc stuff to core. --- library/core/src/iter/sources/repeat.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 0168b11c7394..243f938bce2a 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -8,11 +8,15 @@ use crate::num::NonZero; /// Infinite iterators like `repeat()` are often used with adapters like /// [`Iterator::take()`], in order to make them finite. /// +/// Use [`str::repeat()`] instead of this function if you just want to repeat +/// a char/string `n`th times. +/// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can /// instead use the [`repeat_with()`] function. /// /// [`repeat_with()`]: crate::iter::repeat_with +/// [`str::repeat()`]: ../../std/primitive.str.html#method.repeat /// /// # Examples /// From 8f73091166546dd3641d046979d608643b64cbea Mon Sep 17 00:00:00 2001 From: Boxy Date: Sun, 14 Jul 2024 04:52:15 +0100 Subject: [PATCH 300/361] Add 1.80 release notes Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- RELEASES.md | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 305da6a3550e..9e658568dc9a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,161 @@ +Version 1.80 (2024-07-25) +========================== + + + +Language +-------- +- [Document maximum allocation size](https://github.com/rust-lang/rust/pull/116675/) +- [Allow zero-byte offsets and ZST read/writes on arbitrary pointers](https://github.com/rust-lang/rust/pull/117329/) +- [Support C23's variadics without a named parameter](https://github.com/rust-lang/rust/pull/124048/) +- [Stabilize `exclusive_range_pattern` feature](https://github.com/rust-lang/rust/pull/124459/) +- [Guarantee layout and ABI of `Result` in some scenarios](https://github.com/rust-lang/rust/pull/124870) + + + +Compiler +-------- +- [Update cc crate to v1.0.97 allowing additional spectre mitigations on MSVC targets](https://github.com/rust-lang/rust/pull/124892/) +- [Allow field reordering on types marked `repr(packed(1))`](https://github.com/rust-lang/rust/pull/125360/) +- [Add a lint against never type fallback affecting unsafe code](https://github.com/rust-lang/rust/pull/123939/) +- [Disallow cast with trailing braced macro in let-else](https://github.com/rust-lang/rust/pull/125049/) +- [Expand `for_loops_over_fallibles` lint to lint on fallibles behind references.](https://github.com/rust-lang/rust/pull/125156/) +- [self-contained linker: retry linking without `-fuse-ld=lld` on CCs that don't support it](https://github.com/rust-lang/rust/pull/125417/) +- [Do not parse CVarArgs (`...`) as a type in trait bounds](https://github.com/rust-lang/rust/pull/125863/) +- Improvements to LLDB formatting [#124458](https://github.com/rust-lang/rust/pull/124458) [#124500](https://github.com/rust-lang/rust/pull/124500) +- [For the wasm32-wasip2 target default to PIC and do not use `-fuse-ld=lld`](https://github.com/rust-lang/rust/pull/124858/) +- [Add x86_64-unknown-linux-none as a tier 3 target](https://github.com/rust-lang/rust/pull/125023/) +- [Lint on `foo.into_iter()` resolving to `&Box<[T]>: IntoIterator`](https://github.com/rust-lang/rust/pull/124097/) + + + +Libraries +--------- +- [Add `size_of` and `size_of_val` and `align_of` and `align_of_val` to the prelude](https://github.com/rust-lang/rust/pull/123168/) +- [Abort a process when FD ownership is violated](https://github.com/rust-lang/rust/pull/124210/) +- [io::Write::write_fmt: panic if the formatter fails when the stream does not fail](https://github.com/rust-lang/rust/pull/125012/) +- [Panic if `PathBuf::set_extension` would add a path separator](https://github.com/rust-lang/rust/pull/125070/) +- [Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods](https://github.com/rust-lang/rust/pull/121571/) +- [Update `c_char` on AIX to use the correct type](https://github.com/rust-lang/rust/pull/122986/) +- [`offset_of!` no longer returns a temporary](https://github.com/rust-lang/rust/pull/124484/) +- [Handle sigma in `str.to_lowercase` correctly](https://github.com/rust-lang/rust/pull/124773/) +- [Raise `DEFAULT_MIN_STACK_SIZE` to at least 64KiB](https://github.com/rust-lang/rust/pull/126059/) + + + +Stabilized APIs +--------------- +- [`impl Default for Rc`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3CCStr%3E) +- [`impl Default for Rc`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3Cstr%3E) +- [`impl Default for Rc<[T]>`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3C%5BT%5D%3E) +- [`impl Default for Arc`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3Cstr%3E) +- [`impl Default for Arc`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E) +- [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E) +- [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E) +- [`impl FromIterator for Box`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) +- [`impl FromIterator for Box`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E) +- [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html) +- [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html) +- [`Duration::div_duration_f32`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f32) +- [`Duration::div_duration_f64`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f64) +- [`Option::take_if`](https://doc.rust-lang.org/beta/std/option/enum.Option.html#method.take_if) +- [`Seek::seek_relative`](https://doc.rust-lang.org/beta/std/io/trait.Seek.html#method.seek_relative) +- [`BinaryHeap::as_slice`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.as_slice) +- [`NonNull::offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset) +- [`NonNull::byte_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset) +- [`NonNull::add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.add) +- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add) +- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub) +- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub) +- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) +- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from) +- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read) +- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile) +- [`NonNull::read_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_unaligned) +- [`NonNull::write`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write) +- [`NonNull::write_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_volatile) +- [`NonNull::write_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_unaligned) +- [`NonNull::write_bytes`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_bytes) +- [`NonNull::copy_to`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to) +- [`NonNull::copy_to_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to_nonoverlapping) +- [`NonNull::copy_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from) +- [`NonNull::copy_from_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from_nonoverlapping) +- [`NonNull::replace`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.replace) +- [`NonNull::swap`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.swap) +- [`NonNull::drop_in_place`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.drop_in_place) +- [`NonNull::align_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.align_offset) +- [`<[T]>::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_checked) +- [`<[T]>::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_mut_checked) +- [`str::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_checked) +- [`str::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_mut_checked) +- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii) +- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start) +- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end) +- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) +- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) +- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) +- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS) +- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits) +- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits) +- [`Ipv6Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#associatedconstant.BITS) +- [`Ipv6Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.to_bits) +- [`Ipv6Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.from_bits) +- [`Vec::<[T; N]>::into_flattened`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html#method.into_flattened) +- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened) +- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened_mut) + +These APIs are now stable in const contexts: + +- [`<[T]>::last_chunk`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.last_chunk) +- [`BinaryHeap::new`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.new) + + + +Cargo +----- +- [Stabilize `-Zcheck-cfg` as always enabled](https://github.com/rust-lang/cargo/pull/13571/) +- [Warn, rather than fail publish, if a target is excluded](https://github.com/rust-lang/cargo/pull/13713/) +- [Add special `check-cfg` lint config for the `unexpected_cfgs` lint](https://github.com/rust-lang/cargo/pull/13913/) +- [Stabilize `cargo update --precise `](https://github.com/rust-lang/cargo/pull/13974/) +- [Don't change file permissions on `Cargo.toml` when using `cargo add`](https://github.com/rust-lang/cargo/pull/13898/) +- [Support using `cargo fix` on IPv6-only networks](https://github.com/rust-lang/cargo/pull/13907/) + + + +Rustdoc +----- + +- [Allow searching for references](https://github.com/rust-lang/rust/pull/124148/) +- [Stabilize `custom_code_classes_in_docs` feature](https://github.com/rust-lang/rust/pull/124577/) +- [fix: In cross-crate scenarios show enum variants on type aliases of enums](https://github.com/rust-lang/rust/pull/125300/) + + + +Compatibility Notes +------------------- +- [rustfmt estimates line lengths differently when using non-ascii characters](https://github.com/rust-lang/rustfmt/issues/6203) +- [Type aliases are now handled correctly in orphan check](https://github.com/rust-lang/rust/pull/117164/) +- [Allow instructing rustdoc to read from stdin via `-`](https://github.com/rust-lang/rust/pull/124611/) +- [`std::env::{set_var, remove_var}` can no longer be converted to safe function pointers and no longer implement the `Fn` family of traits](https://github.com/rust-lang/rust/pull/124636) +- [Warn (or error) when `Self` constructor from outer item is referenced in inner nested item](https://github.com/rust-lang/rust/pull/124187/) +- [Turn `indirect_structural_match` and `pointer_structural_match` lints into hard errors](https://github.com/rust-lang/rust/pull/124661/) +- [Make `where_clause_object_safety` lint a regular object safety violation](https://github.com/rust-lang/rust/pull/125380/) +- [Turn `proc_macro_back_compat` lint into a hard error.](https://github.com/rust-lang/rust/pull/125596/) +- [Detect unused structs even when implementing private traits](https://github.com/rust-lang/rust/pull/122382/) +- [`std::sync::ReentrantLockGuard` is no longer `Sync` if `T: !Sync`](https://github.com/rust-lang/rust/pull/125527) which means [`std::io::StdoutLock` and `std::io::StderrLock` are no longer Sync](https://github.com/rust-lang/rust/issues/127340) + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- Misc improvements to size of generated html by rustdoc e.g. [#124738](https://github.com/rust-lang/rust/pull/124738/) and [#123734](https://github.com/rust-lang/rust/pull/123734/) +- [MSVC targets no longer depend on libc](https://github.com/rust-lang/rust/pull/124050/) + Version 1.79.0 (2024-06-13) ========================== From ce86b2ae962f3d6643153533d7bf722741d9e01f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 9 Jul 2024 14:45:47 +1000 Subject: [PATCH 301/361] Move `MatchPair` tree creation to its own module This makes it easier to see that `MatchPair::new` has only one non-recursive caller, because the recursive callers are all in this module. --- .../src/build/matches/match_pair.rs | 245 ++++++++++++++++++ .../rustc_mir_build/src/build/matches/mod.rs | 1 + .../rustc_mir_build/src/build/matches/util.rs | 242 +---------------- 3 files changed, 248 insertions(+), 240 deletions(-) create mode 100644 compiler/rustc_mir_build/src/build/matches/match_pair.rs diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs new file mode 100644 index 000000000000..a26b6d49aed7 --- /dev/null +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -0,0 +1,245 @@ +use rustc_middle::mir::*; +use rustc_middle::thir::{self, *}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; + +use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::matches::{FlatPat, MatchPair, TestCase}; +use crate::build::Builder; + +impl<'a, 'tcx> Builder<'a, 'tcx> { + fn field_match_pairs<'pat>( + &mut self, + place: PlaceBuilder<'tcx>, + subpatterns: &'pat [FieldPat<'tcx>], + ) -> Vec> { + subpatterns + .iter() + .map(|fieldpat| { + let place = + place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); + MatchPair::new(place, &fieldpat.pattern, self) + }) + .collect() + } + + fn prefix_slice_suffix<'pat>( + &mut self, + match_pairs: &mut Vec>, + place: &PlaceBuilder<'tcx>, + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], + ) { + let tcx = self.tcx; + let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { + match place_resolved.ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; + + match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + let elem = + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + MatchPair::new(place.clone_project(elem), subpattern, self) + })); + + if let Some(subslice_pat) = opt_slice { + let suffix_len = suffix.len() as u64; + let subslice = place.clone_project(PlaceElem::Subslice { + from: prefix.len() as u64, + to: if exact_size { min_length - suffix_len } else { suffix_len }, + from_end: !exact_size, + }); + match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); + } + + match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { + let end_offset = (idx + 1) as u64; + let elem = ProjectionElem::ConstantIndex { + offset: if exact_size { min_length - end_offset } else { end_offset }, + min_length, + from_end: !exact_size, + }; + let place = place.clone_project(elem); + MatchPair::new(place, subpattern, self) + })); + } +} + +impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { + /// Recursively builds a `MatchPair` tree for the given pattern and its + /// subpatterns. + pub(in crate::build) fn new( + mut place_builder: PlaceBuilder<'tcx>, + pattern: &'pat Pat<'tcx>, + cx: &mut Builder<'_, 'tcx>, + ) -> MatchPair<'pat, 'tcx> { + // Force the place type to the pattern's type. + // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? + if let Some(resolved) = place_builder.resolve_upvar(cx) { + place_builder = resolved; + } + + // Only add the OpaqueCast projection if the given place is an opaque type and the + // expected type from the pattern is not. + let may_need_cast = match place_builder.base() { + PlaceBase::Local(local) => { + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; + ty != pattern.ty && ty.has_opaque_types() + } + _ => true, + }; + if may_need_cast { + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); + } + + let place = place_builder.try_to_place(cx); + let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; + let mut subpairs = Vec::new(); + let test_case = match pattern.kind { + PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + + PatKind::Or { ref pats } => TestCase::Or { + pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), + }, + + PatKind::Range(ref range) => { + if range.is_full_range(cx.tcx) == Some(true) { + default_irrefutable() + } else { + TestCase::Range(range) + } + } + + PatKind::Constant { value } => TestCase::Constant { value }, + + PatKind::AscribeUserType { + ascription: thir::Ascription { ref annotation, variance }, + ref subpattern, + .. + } => { + // Apply the type ascription to the value at `match_pair.place` + let ascription = place.map(|source| super::Ascription { + annotation: annotation.clone(), + source, + variance, + }); + + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Binding { mode, var, ref subpattern, .. } => { + let binding = place.map(|source| super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + + if let Some(subpattern) = subpattern.as_ref() { + // this is the `x @ P` case; have to keep matching against `P` now + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + } + TestCase::Irrefutable { ascription: None, binding } + } + + PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + let ascription = place.map(|source| { + let span = pattern.span; + let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + cx.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), + ty: cx.infcx.next_ty_var(span), + }, + ) + .args; + let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + super::Ascription { annotation, source, variance: ty::Contravariant } + }); + + subpairs.push(MatchPair::new(place_builder, pattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Array { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + default_irrefutable() + } + PatKind::Slice { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + + if prefix.is_empty() && slice.is_some() && suffix.is_empty() { + default_irrefutable() + } else { + TestCase::Slice { + len: prefix.len() + suffix.len(), + variable_length: slice.is_some(), + } + } + } + + PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { + let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` + subpairs = cx.field_match_pairs(downcast_place, subpatterns); + + let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { + i == variant_index || { + (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && !v + .inhabited_predicate(cx.tcx, adt_def) + .instantiate(cx.tcx, args) + .apply_ignore_module(cx.tcx, cx.param_env) + } + }) && (adt_def.did().is_local() + || !adt_def.is_variant_list_non_exhaustive()); + if irrefutable { + default_irrefutable() + } else { + TestCase::Variant { adt_def, variant_index } + } + } + + PatKind::Leaf { ref subpatterns } => { + subpairs = cx.field_match_pairs(place_builder, subpatterns); + default_irrefutable() + } + + PatKind::Deref { ref subpattern } => { + subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); + default_irrefutable() + } + + PatKind::DerefPattern { ref subpattern, mutability } => { + // Create a new temporary for each deref pattern. + // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? + let temp = cx.temp( + Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), + pattern.span, + ); + subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); + TestCase::Deref { temp, mutability } + } + + PatKind::Never => TestCase::Never, + }; + + MatchPair { place, test_case, subpairs, pattern } + } +} diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 841ef2719c99..7c655ecde023 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -24,6 +24,7 @@ use tracing::{debug, instrument}; use util::visit_bindings; // helper functions, broken out by category: +mod match_pair; mod simplify; mod test; mod util; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 3bec154e1df5..e67fc843285e 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,78 +1,15 @@ use std::marker::PhantomData; -use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::expr::as_place::PlaceBase; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; impl<'a, 'tcx> Builder<'a, 'tcx> { - pub(crate) fn field_match_pairs<'pat>( - &mut self, - place: PlaceBuilder<'tcx>, - subpatterns: &'pat [FieldPat<'tcx>], - ) -> Vec> { - subpatterns - .iter() - .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPair::new(place, &fieldpat.pattern, self) - }) - .collect() - } - - pub(crate) fn prefix_slice_suffix<'pat>( - &mut self, - match_pairs: &mut Vec>, - place: &PlaceBuilder<'tcx>, - prefix: &'pat [Box>], - opt_slice: &'pat Option>>, - suffix: &'pat [Box>], - ) { - let tcx = self.tcx; - let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { - match place_resolved.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; - - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPair::new(place.clone_project(elem), subpattern, self) - })); - - if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u64; - let subslice = place.clone_project(PlaceElem::Subslice { - from: prefix.len() as u64, - to: if exact_size { min_length - suffix_len } else { suffix_len }, - from_end: !exact_size, - }); - match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); - } - - match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u64; - let elem = ProjectionElem::ConstantIndex { - offset: if exact_size { min_length - end_offset } else { end_offset }, - min_length, - from_end: !exact_size, - }; - let place = place.clone_project(elem); - MatchPair::new(place, subpattern, self) - })); - } - /// Creates a false edge to `imaginary_target` and a real edge to /// real_target. If `imaginary_target` is none, or is the same as the real /// target, a Goto is generated instead to simplify the generated MIR. @@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - /// Recursively builds a `MatchPair` tree for the given pattern and its - /// subpatterns. - pub(in crate::build) fn new( - mut place_builder: PlaceBuilder<'tcx>, - pattern: &'pat Pat<'tcx>, - cx: &mut Builder<'_, 'tcx>, - ) -> MatchPair<'pat, 'tcx> { - // Force the place type to the pattern's type. - // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - if let Some(resolved) = place_builder.resolve_upvar(cx) { - place_builder = resolved; - } - - // Only add the OpaqueCast projection if the given place is an opaque type and the - // expected type from the pattern is not. - let may_need_cast = match place_builder.base() { - PlaceBase::Local(local) => { - let ty = - Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; - ty != pattern.ty && ty.has_opaque_types() - } - _ => true, - }; - if may_need_cast { - place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); - } - - let place = place_builder.try_to_place(cx); - let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; - let mut subpairs = Vec::new(); - let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => default_irrefutable(), - - PatKind::Or { ref pats } => TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }, - - PatKind::Range(ref range) => { - if range.is_full_range(cx.tcx) == Some(true) { - default_irrefutable() - } else { - TestCase::Range(range) - } - } - - PatKind::Constant { value } => TestCase::Constant { value }, - - PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - // Apply the type ascription to the value at `match_pair.place` - let ascription = place.map(|source| super::Ascription { - annotation: annotation.clone(), - source, - variance, - }); - - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Binding { mode, var, ref subpattern, .. } => { - let binding = place.map(|source| super::Binding { - span: pattern.span, - source, - var_id: var, - binding_mode: mode, - }); - - if let Some(subpattern) = subpattern.as_ref() { - // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - } - TestCase::Irrefutable { ascription: None, binding } - } - - PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { - // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.map(|source| { - let span = pattern.span; - let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - cx.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx.infcx.next_ty_var(span), - }, - ) - .args; - let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), - ty::UserArgs { args, user_self_ty: None }, - )); - let annotation = ty::CanonicalUserTypeAnnotation { - inferred_ty: pattern.ty, - span, - user_ty: Box::new(user_ty), - }; - super::Ascription { annotation, source, variance: ty::Contravariant } - }); - - subpairs.push(MatchPair::new(place_builder, pattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - default_irrefutable() - } - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - - if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - default_irrefutable() - } else { - TestCase::Slice { - len: prefix.len() + suffix.len(), - variable_length: slice.is_some(), - } - } - } - - PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { - let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - subpairs = cx.field_match_pairs(downcast_place, subpatterns); - - let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { - i == variant_index || { - (cx.tcx.features().exhaustive_patterns - || cx.tcx.features().min_exhaustive_patterns) - && !v - .inhabited_predicate(cx.tcx, adt_def) - .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.param_env) - } - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - default_irrefutable() - } else { - TestCase::Variant { adt_def, variant_index } - } - } - - PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place_builder, subpatterns); - default_irrefutable() - } - - PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); - default_irrefutable() - } - - PatKind::DerefPattern { ref subpattern, mutability } => { - // Create a new temporary for each deref pattern. - // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? - let temp = cx.temp( - Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), - pattern.span, - ); - subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); - TestCase::Deref { temp, mutability } - } - - PatKind::Never => TestCase::Never, - }; - - MatchPair { place, test_case, subpairs, pattern } - } -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. From f7508f881676a3e123245bcf99f9f0d21d4d6b49 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Jul 2024 12:31:39 +1000 Subject: [PATCH 302/361] Improve internal docs for `MatchPair` --- .../src/build/matches/match_pair.rs | 9 +++++++++ .../rustc_mir_build/src/build/matches/mod.rs | 20 ++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index a26b6d49aed7..2f540478674d 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -7,6 +7,11 @@ use crate::build::matches::{FlatPat, MatchPair, TestCase}; use crate::build::Builder; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Builds and returns [`MatchPair`] trees, one for each pattern in + /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or + /// [`PatKind::Leaf`]. + /// + /// Used internally by [`MatchPair::new`]. fn field_match_pairs<'pat>( &mut self, place: PlaceBuilder<'tcx>, @@ -22,6 +27,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } + /// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an + /// array pattern or slice pattern, and adds those trees to `match_pairs`. + /// + /// Used internally by [`MatchPair::new`]. fn prefix_slice_suffix<'pat>( &mut self, match_pairs: &mut Vec>, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7c655ecde023..98de4df3ce39 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1196,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> { } } +/// Node in a tree of "match pairs", where each pair consists of a place to be +/// tested, and a test to perform on that place. +/// +/// Each node also has a list of subpairs (possibly empty) that must also match, +/// and a reference to the THIR pattern it represents. #[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { /// This place... - // This can be `None` if it referred to a non-captured place in a closure. - // Invariant: place.is_none() => test_case is Irrefutable - // In other words this must be `Some(_)` after simplification. + /// + /// --- + /// This can be `None` if it referred to a non-captured place in a closure. + /// + /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. + /// Therefore this must be `Some(_)` after simplification. place: Option>, /// ... must pass this test... - // Invariant: after creation and simplification in `Candidate::new()`, this must not be - // `Irrefutable`. + /// + /// --- + /// Invariant: after creation and simplification in [`FlatPat::new`], + /// this must not be [`TestCase::Irrefutable`]. test_case: TestCase<'pat, 'tcx>, /// ... and these subpairs must match. From 2dd5369eda4337f44a8bb666bfd38b2c5e3b0fde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Jul 2024 08:18:03 +0200 Subject: [PATCH 303/361] clarify the meaning of the version number for accepted/removed features --- compiler/rustc_feature/src/accepted.rs | 4 ++++ compiler/rustc_feature/src/lib.rs | 4 ++++ compiler/rustc_feature/src/removed.rs | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index f082cc2b5699..e671c7682391 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -42,6 +42,10 @@ declare_features! ( // feature-group-start: accepted features // ------------------------------------------------------------------------- + // Note that the version indicates when it got *stabilized*. + // When moving an unstable feature here, set the version number to + // `CURRENT RUSTC VERSION` with ` ` replaced by `_`. + /// Allows `#[target_feature(...)]` on aarch64 platforms (accepted, aarch64_target_feature, "1.61.0", Some(44839)), /// Allows using the `efiapi` ABI. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index bf4293643183..e9d3ce0a0749 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -31,6 +31,10 @@ use std::num::NonZero; #[derive(Debug, Clone)] pub struct Feature { pub name: Symbol, + /// For unstable features: the version the feature was added in. + /// For accepted features: the version the feature got stabilized in. + /// For removed features we are inconsistent; sometimes this is the + /// version it got added, sometimes the version it got removed. pub since: &'static str, issue: Option>, } diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index f13aa506c1ec..80a108d2fc87 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -32,6 +32,12 @@ declare_features! ( // feature-group-start: removed features // ------------------------------------------------------------------------- + // Note that the version indicates when it got *removed*. + // When moving an unstable feature here, set the version number to + // `CURRENT RUSTC VERSION` with ` ` replaced by `_`. + // (But not all features below do this properly; many indicate the + // version they got originally added in.) + /// Allows using the `amdgpu-kernel` ABI. (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None), (removed, advanced_slice_patterns, "1.0.0", Some(62254), From a54dbbfd0e66b10601883fecdb16c2eaed0c32ca Mon Sep 17 00:00:00 2001 From: Boxy Date: Sun, 14 Jul 2024 07:57:53 +0100 Subject: [PATCH 304/361] add_effects_test --- .../effects/mismatched_generic_args.rs | 24 +++++++ .../effects/mismatched_generic_args.stderr | 64 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs new file mode 100644 index 000000000000..21e91c731b36 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs @@ -0,0 +1,24 @@ +#![feature(generic_const_exprs)] +//~^ WARN: the feature `generic_const_exprs` is incomplete + +// Regression test for #125770 which would ICE under the old effects desugaring that +// created a const generic parameter for constness on `Add`. + +use std::ops::Add; + +pub struct Dimension; + +pub struct Quantity(S); +//~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + +impl Add for Quantity {} +//~^ ERROR: trait takes at most 1 generic argument +//~| ERROR: `Dimension` is forbidden as the type of a const generic parameter + +pub fn add(x: Quantity) -> Quantity { + //~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + x + y + //~^ ERROR: cannot find value `y` in this scope +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr new file mode 100644 index 000000000000..8c814295de46 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr @@ -0,0 +1,64 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/mismatched_generic_args.rs:20:9 + | +LL | pub fn add(x: Quantity) -> Quantity { + | - similarly named const parameter `U` defined here +LL | +LL | x + y + | ^ help: a const parameter with a similar name exists: `U` + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mismatched_generic_args.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:11:33 + | +LL | pub struct Quantity(S); + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied + --> $DIR/mismatched_generic_args.rs:14:36 + | +LL | impl Add for Quantity {} + | ^^^ expected at most 1 generic argument + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:14:15 + | +LL | impl Add for Quantity {} + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:18:21 + | +LL | pub fn add(x: Quantity) -> Quantity { + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0107, E0425. +For more information about an error, try `rustc --explain E0107`. From e31709345c82542e14eae079303c1b09a42a811f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 20:12:19 +0200 Subject: [PATCH 305/361] Port all remaining simple command usages in bootstrap to `BootstrapCommand` --- src/bootstrap/src/core/build_steps/compile.rs | 26 ++++------- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- src/bootstrap/src/core/build_steps/setup.rs | 46 +++++++++---------- src/bootstrap/src/core/build_steps/test.rs | 14 ++---- src/bootstrap/src/utils/helpers.rs | 6 +-- 5 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 039a7b2fc276..e6c15f27ea91 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -14,7 +14,7 @@ use std::fs; use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Stdio; use std::str; use serde_derive::Deserialize; @@ -696,10 +696,10 @@ fn copy_sanitizers( || target == "x86_64-apple-ios" { // Update the library’s install name to reflect that it has been renamed. - apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name)); + apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name)); // Upon renaming the install name, the code signature of the file will invalidate, // so we will sign it again. - apple_darwin_sign_file(&dst); + apple_darwin_sign_file(builder, &dst); } target_deps.push(dst); @@ -708,25 +708,17 @@ fn copy_sanitizers( target_deps } -fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) { - let status = Command::new("install_name_tool") - .arg("-id") - .arg(new_name) - .arg(library_path) - .status() - .expect("failed to execute `install_name_tool`"); - assert!(status.success()); +fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) { + command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder); } -fn apple_darwin_sign_file(file_path: &Path) { - let status = Command::new("codesign") +fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) { + command("codesign") .arg("-f") // Force to rewrite the existing signature .arg("-s") .arg("-") .arg(file_path) - .status() - .expect("failed to execute `codesign`"); - assert!(status.success()); + .run(builder); } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1172,7 +1164,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_profile_generate && target.is_msvc() { if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { // Add clang's runtime library directory to the search path - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); } } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 41dff2123f13..876d73dce3ce 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -912,7 +912,7 @@ impl Step for Lld { if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() { // Find clang's runtime library directory and push that as a search path to the // cmake linker flags. - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display())); } } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 29cc5e00637e..e155b3025783 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -8,6 +8,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; +use crate::utils::exec::command; use crate::utils::helpers::{self, hex_encode}; use crate::Config; use sha2::Digest; @@ -16,7 +17,6 @@ use std::fmt::Write as _; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; -use std::process::Command; use std::str::FromStr; use std::{fmt, fs, io}; @@ -266,20 +266,16 @@ impl Step for Link { } let stage_path = ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR); - if !rustup_installed() { + if !rustup_installed(builder) { eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() { - attempt_toolchain_link(&stage_path[..]); + attempt_toolchain_link(builder, &stage_path[..]); } } } -fn rustup_installed() -> bool { - Command::new("rustup") - .arg("--version") - .stdout(std::process::Stdio::null()) - .output() - .map_or(false, |output| output.status.success()) +fn rustup_installed(builder: &Builder<'_>) -> bool { + command("rustup").capture_stdout().arg("--version").run(builder).is_success() } fn stage_dir_exists(stage_path: &str) -> bool { @@ -289,8 +285,8 @@ fn stage_dir_exists(stage_path: &str) -> bool { } } -fn attempt_toolchain_link(stage_path: &str) { - if toolchain_is_linked() { +fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { + if toolchain_is_linked(builder) { return; } @@ -301,7 +297,7 @@ fn attempt_toolchain_link(stage_path: &str) { return; } - if try_link_toolchain(stage_path) { + if try_link_toolchain(builder, stage_path) { println!( "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); @@ -315,14 +311,16 @@ fn attempt_toolchain_link(stage_path: &str) { } } -fn toolchain_is_linked() -> bool { - match Command::new("rustup") +fn toolchain_is_linked(builder: &Builder<'_>) -> bool { + match command("rustup") + .capture_stdout() + .allow_failure() .args(["toolchain", "list"]) - .stdout(std::process::Stdio::piped()) - .output() + .run(builder) + .stdout_if_ok() { - Ok(toolchain_list) => { - if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") { + Some(toolchain_list) => { + if !toolchain_list.contains("stage1") { return false; } // The toolchain has already been linked. @@ -330,7 +328,7 @@ fn toolchain_is_linked() -> bool { "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" ); } - Err(_) => { + None => { // In this case, we don't know if the `stage1` toolchain has been linked; // but `rustup` failed, so let's not go any further. println!( @@ -341,12 +339,12 @@ fn toolchain_is_linked() -> bool { true } -fn try_link_toolchain(stage_path: &str) -> bool { - Command::new("rustup") - .stdout(std::process::Stdio::null()) +fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool { + command("rustup") + .capture_stdout() .args(["toolchain", "link", "stage1", stage_path]) - .output() - .map_or(false, |output| output.status.success()) + .run(builder) + .is_success() } fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4d69d6b52311..118b6b876ed1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -9,7 +9,6 @@ use std::ffi::OsString; use std::fs; use std::iter; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; use clap_complete::shells; @@ -169,12 +168,8 @@ You can skip linkcheck with --skip src/tools/linkchecker" } } -fn check_if_tidy_is_installed() -> bool { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) +fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool { + command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -188,8 +183,9 @@ impl Step for HtmlCheck { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; let run = run.path("src/tools/html-checker"); - run.lazy_default_condition(Box::new(check_if_tidy_is_installed)) + run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder))) } fn make_run(run: RunConfig<'_>) { @@ -197,7 +193,7 @@ impl Step for HtmlCheck { } fn run(self, builder: &Builder<'_>) { - if !check_if_tidy_is_installed() { + if !check_if_tidy_is_installed(builder) { eprintln!("not running HTML-check tool because `tidy` is missing"); eprintln!( "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager." diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 15133e441b49..3c82fa189be3 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -338,13 +338,13 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime /// missing. This function returns the path to that directory. -pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { +pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> PathBuf { // Similar to how LLVM does it, to find clang's library runtime directory: // - we ask `clang-cl` to locate the `clang_rt.builtins` lib. - let mut builtins_locator = Command::new(clang_cl_path); + let mut builtins_locator = command(clang_cl_path); builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]); - let clang_rt_builtins = output(&mut builtins_locator); + let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout(); let clang_rt_builtins = Path::new(clang_rt_builtins.trim()); assert!( clang_rt_builtins.exists(), From 8cffb475fd490785ea44367d91161aba9b98a490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 17:10:58 +0200 Subject: [PATCH 306/361] Remove several usages of the `as_command_mut` method Passes `&Builder<'_>` to additional places, so that they could use the `BootstrapCommand` APIs directly, rather than going through `as_command_mut`. --- src/bootstrap/src/core/build_steps/llvm.rs | 1 + src/bootstrap/src/core/build_steps/setup.rs | 14 ++- .../src/core/build_steps/toolstate.rs | 100 ++++++------------ src/bootstrap/src/lib.rs | 64 ++++++----- src/bootstrap/src/utils/tarball.rs | 14 +-- 5 files changed, 78 insertions(+), 115 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 876d73dce3ce..888290a0479b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -125,6 +125,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { generate_smart_stamp_hash( + builder, &builder.config.src.join("src/llvm-project"), builder.in_tree_llvm_info.sha().unwrap_or_default(), ) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index e155b3025783..226b3729c10c 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -474,20 +474,18 @@ impl Step for Hook { if config.dry_run() { return; } - t!(install_git_hook_maybe(config)); + t!(install_git_hook_maybe(builder, config)); } } // install a git hook to automatically run tidy, if they want -fn install_git_hook_maybe(config: &Config) -> io::Result<()> { +fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) + .capture() .args(["rev-parse", "--git-common-dir"]) - .as_command_mut() - .output() - .map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })?; + .run(builder) + .stdout(); + let git = PathBuf::from(git.trim()); let hooks_dir = git.join("hooks"); let dst = hooks_dir.join("pre-push"); if dst.exists() { diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 9ddd68da59d1..2ab0ce7454b1 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -99,24 +99,16 @@ fn print_error(tool: &str, submodule: &str) { crate::exit!(3); } -fn check_changed_files(toolstates: &HashMap, ToolState>) { +fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap, ToolState>) { // Changed files let output = helpers::git(None) + .capture() .arg("diff") .arg("--name-status") .arg("HEAD") .arg("HEAD^") - .as_command_mut() - .output(); - let output = match output { - Ok(o) => o, - Err(e) => { - eprintln!("Failed to get changed files: {e:?}"); - crate::exit!(1); - } - }; - - let output = t!(String::from_utf8(output.stdout)); + .run(builder) + .stdout(); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule)); @@ -186,8 +178,8 @@ impl Step for ToolStateCheck { crate::exit!(1); } - check_changed_files(&toolstates); - checkout_toolstate_repo(); + check_changed_files(builder, &toolstates); + checkout_toolstate_repo(builder); let old_toolstate = read_old_toolstate(); for (tool, _) in STABLE_TOOLS.iter() { @@ -231,7 +223,7 @@ impl Step for ToolStateCheck { } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { - commit_toolstate_change(&toolstates); + commit_toolstate_change(builder, &toolstates); } } @@ -315,55 +307,34 @@ fn toolstate_repo() -> String { const TOOLSTATE_DIR: &str = "rust-toolstate"; /// Checks out the toolstate repo into `TOOLSTATE_DIR`. -fn checkout_toolstate_repo() { +fn checkout_toolstate_repo(builder: &Builder<'_>) { if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") { - prepare_toolstate_config(&token); + prepare_toolstate_config(builder, &token); } if Path::new(TOOLSTATE_DIR).exists() { eprintln!("Cleaning old toolstate directory..."); t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = helpers::git(None) + helpers::git(None) .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) .arg(TOOLSTATE_DIR) - .as_command_mut() - .status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git clone unsuccessful (status: {status:?})"); - } + .run(builder); } /// Sets up config and authentication for modifying the toolstate repo. -fn prepare_toolstate_config(token: &str) { - fn git_config(key: &str, value: &str) { - let status = helpers::git(None) - .arg("config") - .arg("--global") - .arg(key) - .arg(value) - .as_command_mut() - .status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git config key={key} value={value} failed (status: {status:?})"); - } +fn prepare_toolstate_config(builder: &Builder<'_>, token: &str) { + fn git_config(builder: &Builder<'_>, key: &str, value: &str) { + helpers::git(None).arg("config").arg("--global").arg(key).arg(value).run(builder); } // If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date // as well. - git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); - git_config("user.name", "Rust Toolstate Update"); - git_config("credential.helper", "store"); + git_config(builder, "user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); + git_config(builder, "user.name", "Rust Toolstate Update"); + git_config(builder, "credential.helper", "store"); let credential = format!("https://{token}:x-oauth-basic@github.com\n",); let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials"); @@ -403,55 +374,51 @@ fn read_old_toolstate() -> Vec { /// /// * See /// if a private email by GitHub is wanted. -fn commit_toolstate_change(current_toolstate: &ToolstateData) { +fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) { let message = format!("({} CI update)", OS.expect("linux/windows only")); let mut success = false; for _ in 1..=5 { // Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo. // This does *not* change the "current toolstate"; that only happens post-landing // via `src/ci/docker/publish_toolstate.sh`. - publish_test_results(current_toolstate); + publish_test_results(builder, current_toolstate); // `git commit` failing means nothing to commit. - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("commit") .arg("-a") .arg("-m") .arg(&message) - .as_command_mut() - .status()); - if !status.success() { + .run(builder); + if !status.is_success() { success = true; break; } - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("push") .arg("origin") .arg("master") - .as_command_mut() - .status()); + .run(builder); // If we successfully push, exit. - if status.success() { + if status.is_success() { success = true; break; } eprintln!("Sleeping for 3 seconds before retrying push"); std::thread::sleep(std::time::Duration::from_secs(3)); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("fetch") .arg("origin") .arg("master") - .as_command_mut() - .status()); - assert!(status.success()); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .run(builder); + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") - .as_command_mut() - .status()); - assert!(status.success()); + .run(builder); } if !success { @@ -464,9 +431,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// These results will later be promoted to `latest.json` by the /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. -fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").as_command_mut().output()); - let commit = t!(String::from_utf8(commit.stdout)); +fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) { + let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout(); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index daa916ce0a07..52e28fbd0598 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,7 +23,7 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Command; use std::str; use std::sync::OnceLock; use std::time::SystemTime; @@ -37,7 +37,7 @@ use utils::channel::GitInfo; use utils::helpers::hex_encode; use crate::core::builder; -use crate::core::builder::Kind; +use crate::core::builder::{Builder, Kind}; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; @@ -490,18 +490,18 @@ impl Build { return; } - let submodule_git = || helpers::git(Some(&absolute_path)); + let submodule_git = || helpers::git(Some(&absolute_path)).capture_stdout(); // Determine commit checked out in submodule. - let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut()); + let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout(); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. - let recorded = output( - helpers::git(Some(&self.src)) - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .as_command_mut(), - ); + let recorded = helpers::git(Some(&self.src)) + .capture_stdout() + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .run(self) + .stdout(); let actual_hash = recorded .split_whitespace() .nth(2) @@ -522,21 +522,14 @@ impl Build { let update = |progress: bool| { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. - let current_branch = { - let output = helpers::git(Some(&self.src)) - .args(["symbolic-ref", "--short", "HEAD"]) - .as_command_mut() - .stderr(Stdio::inherit()) - .output(); - let output = t!(output); - if output.status.success() { - Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) - } else { - None - } - }; + let current_branch = helpers::git(Some(&self.src)) + .capture_stdout() + .args(["symbolic-ref", "--short", "HEAD"]) + .run(self) + .stdout_if_ok() + .map(|s| s.trim().to_owned()); - let mut git = helpers::git(Some(&self.src)); + let mut git = helpers::git(Some(&self.src)).allow_failure(); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. @@ -550,8 +543,7 @@ impl Build { git.arg(relative_path); git }; - // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. - if !update(true).as_command_mut().status().map_or(false, |status| status.success()) { + if !update(true).run(self).is_success() { update(false).run(self); } @@ -1943,22 +1935,28 @@ fn envify(s: &str) -> String { /// /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. -pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { +pub fn generate_smart_stamp_hash( + builder: &Builder<'_>, + dir: &Path, + additional_input: &str, +) -> String { let diff = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("diff") - .as_command_mut() - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let status = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .as_command_mut() - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let mut hasher = sha2::Sha256::new(); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index f5fc94273c9a..9378c35127f2 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -369,13 +369,13 @@ impl<'a> Tarball<'a> { // gets the same timestamp. if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date - let timestamp = helpers::output( - helpers::git(Some(&self.builder.src)) - .arg("log") - .arg("-1") - .arg("--format=%ct") - .as_command_mut(), - ); + let timestamp = helpers::git(Some(&self.builder.src)) + .capture_stdout() + .arg("log") + .arg("-1") + .arg("--format=%ct") + .run(self.builder) + .stdout(); cmd.args(["--override-file-mtime", timestamp.trim()]); } From b494d98b188619551cd2a61d0b2b78618a2277ee Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 14 Jul 2024 12:36:58 +0000 Subject: [PATCH 307/361] find_field does not need to be a query. --- compiler/rustc_hir_analysis/src/collect.rs | 19 ---- compiler/rustc_hir_typeck/src/expr.rs | 104 ++++++++++++++------- compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 4 - 4 files changed, 73 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0acc119115a7..e0aad2991632 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -35,7 +35,6 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::FieldIdx; use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; @@ -85,7 +84,6 @@ pub fn provide(providers: &mut Providers) { coroutine_kind, coroutine_for_closure, is_type_alias_impl_trait, - find_field, ..*providers }; } @@ -914,23 +912,6 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } -fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { - let adt = tcx.adt_def(def_id); - if adt.is_enum() { - return None; - } - - adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { - if field.is_unnamed() { - let field_ty = tcx.type_of(field.did).instantiate_identity(); - let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); - tcx.find_field((adt_def.did(), ident)).map(|_| idx) - } else { - (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) - } - }) -} - #[derive(Clone, Copy)] struct NestedSpan { span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f057dbc013fc..035a3429ed76 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -59,6 +59,8 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use smallvec::SmallVec; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_expr_has_type_or_error( &self, @@ -2318,6 +2320,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { display } + /// Find the position of a field named `ident` in `base_def`, accounting for unnammed fields. + /// Return whether such a field has been found. The path to it is stored in `nested_fields`. + /// `ident` must have been adjusted beforehand. + fn find_adt_field( + &self, + base_def: ty::AdtDef<'tcx>, + ident: Ident, + nested_fields: &mut SmallVec<[(FieldIdx, &'tcx ty::FieldDef); 1]>, + ) -> bool { + // No way to find a field in an enum. + if base_def.is_enum() { + return false; + } + + for (field_idx, field) in base_def.non_enum_variant().fields.iter_enumerated() { + if field.is_unnamed() { + // We have an unnamed field, recurse into the nested ADT to find `ident`. + // If we find it there, return immediately, and `nested_fields` will contain the + // correct path. + nested_fields.push((field_idx, field)); + + let field_ty = self.tcx.type_of(field.did).instantiate_identity(); + let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + if self.find_adt_field(adt_def, ident, &mut *nested_fields) { + return true; + } + + nested_fields.pop(); + } else if field.ident(self.tcx).normalize_to_macros_2_0() == ident { + // We found the field we wanted. + nested_fields.push((field_idx, field)); + return true; + } + } + + false + } + // Check field access expressions fn check_field( &self, @@ -2339,44 +2379,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); - let mut adt_def = *base_def; - let mut last_ty = None; - let mut nested_fields = Vec::new(); - let mut index = None; // we don't care to report errors for a struct if the struct itself is tainted - if let Err(guar) = adt_def.non_enum_variant().has_errors() { + if let Err(guar) = base_def.non_enum_variant().has_errors() { return Ty::new_error(self.tcx(), guar); } - while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) { - let &mut first_idx = index.get_or_insert(idx); - let field = &adt_def.non_enum_variant().fields[idx]; - let field_ty = self.field_ty(expr.span, field, args); - if let Some(ty) = last_ty { - nested_fields.push((ty, idx)); - } - if field.ident(self.tcx).normalize_to_macros_2_0() == ident { - // Save the index of all fields regardless of their visibility in case - // of error recovery. - self.write_field_index(expr.hir_id, first_idx, nested_fields); - let adjustments = self.adjust_steps(&autoderef); - if field.vis.is_accessible_from(def_scope, self.tcx) { - self.apply_adjustments(base, adjustments); - self.register_predicates(autoderef.into_obligations()); - self.tcx.check_stability( - field.did, - Some(expr.hir_id), - expr.span, - None, - ); - return field_ty; - } - private_candidate = Some((adjustments, base_def.did())); - break; + let mut field_path = SmallVec::new(); + if self.find_adt_field(*base_def, ident, &mut field_path) { + let (first_idx, _) = field_path[0]; + let (_, last_field) = field_path.last().unwrap(); + + // Save the index of all fields regardless of their visibility in case + // of error recovery. + let nested_fields = field_path[..] + .array_windows() + .map(|[(_, outer), (inner_idx, _)]| { + let outer_ty = self.field_ty(expr.span, outer, args); + (outer_ty, *inner_idx) + }) + .collect(); + self.write_field_index(expr.hir_id, first_idx, nested_fields); + + let adjustments = self.adjust_steps(&autoderef); + if last_field.vis.is_accessible_from(def_scope, self.tcx) { + self.apply_adjustments(base, adjustments); + self.register_predicates(autoderef.into_obligations()); + + self.tcx.check_stability( + last_field.did, + Some(expr.hir_id), + expr.span, + None, + ); + return self.field_ty(expr.span, last_field, args); } - last_ty = Some(field_ty); - adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + + // The field is not accessible, fall through to error reporting. + private_candidate = Some((adjustments, base_def.did())); } } ty::Tuple(tys) => { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a87ee7b45548..bdbdcee6446d 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 33c27d41d864..817c7157b682 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2280,10 +2280,6 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } - - query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option { - desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) } - } } rustc_query_append! { define_callbacks! } From 306d5788a684e71cc5dc03c71da3b2e26672b6a3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 3 Jun 2024 18:48:59 +0200 Subject: [PATCH 308/361] Merge Apple `std::os` extensions modules into `std::os::darwin` The functionality available on Apple platforms are very similar, and were duplicated for each platform. Additionally, this fixes a warning when compiling the standard library for tvOS, watchOS and visionOS by marking the corresponding code as dead code. --- library/std/src/fs/tests.rs | 23 +-- library/std/src/os/{macos => darwin}/fs.rs | 6 +- library/std/src/os/darwin/mod.rs | 20 +++ library/std/src/os/{ios => darwin}/raw.rs | 14 +- library/std/src/os/ios/fs.rs | 160 --------------------- library/std/src/os/ios/mod.rs | 28 +++- library/std/src/os/macos/mod.rs | 28 +++- library/std/src/os/macos/raw.rs | 83 ----------- library/std/src/os/mod.rs | 11 +- library/std/src/os/unix/mod.rs | 12 +- library/std/src/os/visionos/fs.rs | 160 --------------------- library/std/src/os/visionos/mod.rs | 6 - library/std/src/os/visionos/raw.rs | 83 ----------- library/std/src/os/watchos/fs.rs | 160 --------------------- library/std/src/os/watchos/mod.rs | 6 - library/std/src/os/watchos/raw.rs | 83 ----------- triagebot.toml | 19 +-- 17 files changed, 93 insertions(+), 809 deletions(-) rename library/std/src/os/{macos => darwin}/fs.rs (98%) create mode 100644 library/std/src/os/darwin/mod.rs rename library/std/src/os/{ios => darwin}/raw.rs (87%) delete mode 100644 library/std/src/os/ios/fs.rs delete mode 100644 library/std/src/os/macos/raw.rs delete mode 100644 library/std/src/os/visionos/fs.rs delete mode 100644 library/std/src/os/visionos/mod.rs delete mode 100644 library/std/src/os/visionos/raw.rs delete mode 100644 library/std/src/os/watchos/fs.rs delete mode 100644 library/std/src/os/watchos/mod.rs delete mode 100644 library/std/src/os/watchos/raw.rs diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 62a268facb63..f1749efdfa95 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1638,16 +1638,8 @@ fn rename_directory() { #[test] fn test_file_times() { - #[cfg(target_os = "ios")] - use crate::os::ios::fs::FileTimesExt; - #[cfg(target_os = "macos")] - use crate::os::macos::fs::FileTimesExt; - #[cfg(target_os = "tvos")] - use crate::os::tvos::fs::FileTimesExt; - #[cfg(target_os = "visionos")] - use crate::os::visionos::fs::FileTimesExt; - #[cfg(target_os = "watchos")] - use crate::os::watchos::fs::FileTimesExt; + #[cfg(target_vendor = "apple")] + use crate::os::darwin::fs::FileTimesExt; #[cfg(windows)] use crate::os::windows::fs::FileTimesExt; @@ -1693,16 +1685,7 @@ fn test_file_times() { #[test] #[cfg(target_vendor = "apple")] fn test_file_times_pre_epoch_with_nanos() { - #[cfg(target_os = "ios")] - use crate::os::ios::fs::FileTimesExt; - #[cfg(target_os = "macos")] - use crate::os::macos::fs::FileTimesExt; - #[cfg(target_os = "tvos")] - use crate::os::tvos::fs::FileTimesExt; - #[cfg(target_os = "visionos")] - use crate::os::visionos::fs::FileTimesExt; - #[cfg(target_os = "watchos")] - use crate::os::watchos::fs::FileTimesExt; + use crate::os::darwin::fs::FileTimesExt; let tmp = tmpdir(); let file = File::create(tmp.join("foo")).unwrap(); diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/darwin/fs.rs similarity index 98% rename from library/std/src/os/macos/fs.rs rename to library/std/src/os/darwin/fs.rs index 573426d1a864..2032cca311a1 100644 --- a/library/std/src/os/macos/fs.rs +++ b/library/std/src/os/darwin/fs.rs @@ -1,4 +1,4 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] +#![allow(dead_code)] use crate::fs::{self, Metadata}; use crate::sealed::Sealed; @@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; #[allow(deprecated)] -use crate::os::macos::raw; +use super::raw; /// OS-specific extensions to [`fs::Metadata`]. /// @@ -70,6 +70,7 @@ pub trait MetadataExt { fn st_gen(&self) -> u32; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_lspare(&self) -> u32; + #[cfg(target_os = "macos")] #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_qspare(&self) -> [u64; 2]; } @@ -143,6 +144,7 @@ impl MetadataExt for Metadata { fn st_lspare(&self) -> u32 { self.as_inner().as_inner().st_lspare as u32 } + #[cfg(target_os = "macos")] fn st_qspare(&self) -> [u64; 2] { let qspare = self.as_inner().as_inner().st_qspare; [qspare[0] as u64, qspare[1] as u64] diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs new file mode 100644 index 000000000000..03401fe8895b --- /dev/null +++ b/library/std/src/os/darwin/mod.rs @@ -0,0 +1,20 @@ +//! Platform-specific extensions to `std` for Darwin / Apple platforms. +//! +//! This is available on the following operating systems: +//! - macOS +//! - iOS +//! - tvOS +//! - watchOS +//! - visionOS +//! +//! Note: This module is called "Darwin" as that's the name of the underlying +//! core OS of the above operating systems, but it should not be confused with +//! the `-darwin` suffix in the `x86_64-apple-darwin` and +//! `aarch64-apple-darwin` target names, which are mostly named that way for +//! legacy reasons. + +pub(crate) mod fs; +// deprecated, but used for public reexport under `std::os::unix::raw`, as +// well as `std::os::macos`/`std::os::ios`, because those modules precede the +// decision to remove these. +pub(super) mod raw; diff --git a/library/std/src/os/ios/raw.rs b/library/std/src/os/darwin/raw.rs similarity index 87% rename from library/std/src/os/ios/raw.rs rename to library/std/src/os/darwin/raw.rs index af12aeebe5d0..047727f45325 100644 --- a/library/std/src/os/ios/raw.rs +++ b/library/std/src/os/darwin/raw.rs @@ -1,15 +1,4 @@ -//! iOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - +//! Apple-specific raw type definitions use crate::os::raw::c_long; #[stable(feature = "raw_ext", since = "1.1.0")] @@ -35,6 +24,7 @@ pub type pthread_t = usize; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(dead_code)] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] pub st_dev: i32, diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs deleted file mode 100644 index e5df4de0b7f7..000000000000 --- a/library/std/src/os/ios/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use super::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/ios/mod.rs b/library/std/src/os/ios/mod.rs index fdefa1f6b21c..5e130d77b7bf 100644 --- a/library/std/src/os/ios/mod.rs +++ b/library/std/src/os/ios/mod.rs @@ -2,5 +2,29 @@ #![stable(feature = "raw_ext", since = "1.1.0")] -pub mod fs; -pub mod raw; +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub mod fs { + #[doc(inline)] + #[stable(feature = "file_set_times", since = "1.75.0")] + pub use crate::os::darwin::fs::FileTimesExt; + + #[doc(inline)] + #[stable(feature = "metadata_ext", since = "1.1.0")] + pub use crate::os::darwin::fs::MetadataExt; +} + +/// iOS-specific raw type definitions +#[stable(feature = "raw_ext", since = "1.1.0")] +#[deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#[allow(deprecated)] +pub mod raw { + #[doc(inline)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub use crate::os::darwin::raw::*; +} diff --git a/library/std/src/os/macos/mod.rs b/library/std/src/os/macos/mod.rs index 791d703b142c..3638406b1807 100644 --- a/library/std/src/os/macos/mod.rs +++ b/library/std/src/os/macos/mod.rs @@ -2,5 +2,29 @@ #![stable(feature = "raw_ext", since = "1.1.0")] -pub mod fs; -pub mod raw; +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub mod fs { + #[doc(inline)] + #[stable(feature = "file_set_times", since = "1.75.0")] + pub use crate::os::darwin::fs::FileTimesExt; + + #[doc(inline)] + #[stable(feature = "metadata_ext", since = "1.1.0")] + pub use crate::os::darwin::fs::MetadataExt; +} + +/// macOS-specific raw type definitions +#[stable(feature = "raw_ext", since = "1.1.0")] +#[deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#[allow(deprecated)] +pub mod raw { + #[doc(inline)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub use crate::os::darwin::raw::*; +} diff --git a/library/std/src/os/macos/raw.rs b/library/std/src/os/macos/raw.rs deleted file mode 100644 index 0b21f6ee5e49..000000000000 --- a/library/std/src/os/macos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! macOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index d2a7b316b813..455fdd3c34d7 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -14,7 +14,7 @@ pub mod raw; // documented don't compile (missing things in `libc` which is empty), // so just omit them with an empty module and add the "unstable" attribute. -// Unix, linux, wasi and windows are handled a bit differently. +// unix, linux, wasi and windows are handled a bit differently. #[cfg(all( doc, any( @@ -104,6 +104,8 @@ pub mod windows; pub mod aix; #[cfg(target_os = "android")] pub mod android; +#[cfg(target_vendor = "apple")] +pub(crate) mod darwin; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "emscripten")] @@ -144,19 +146,12 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; -#[cfg(target_os = "tvos")] -#[path = "ios/mod.rs"] -pub(crate) mod tvos; #[cfg(target_os = "uefi")] pub mod uefi; -#[cfg(target_os = "visionos")] -pub(crate) mod visionos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] pub mod vxworks; -#[cfg(target_os = "watchos")] -pub(crate) mod watchos; #[cfg(target_os = "xous")] pub mod xous; diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index d7a622012a5a..c6581b9c4c8c 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -41,6 +41,8 @@ mod platform { pub use crate::os::aix::*; #[cfg(target_os = "android")] pub use crate::os::android::*; + #[cfg(target_vendor = "apple")] + pub(super) use crate::os::darwin::*; #[cfg(target_os = "dragonfly")] pub use crate::os::dragonfly::*; #[cfg(target_os = "emscripten")] @@ -59,14 +61,10 @@ mod platform { pub use crate::os::hurd::*; #[cfg(target_os = "illumos")] pub use crate::os::illumos::*; - #[cfg(target_os = "ios")] - pub use crate::os::ios::*; #[cfg(target_os = "l4re")] pub use crate::os::l4re::*; #[cfg(target_os = "linux")] pub use crate::os::linux::*; - #[cfg(target_os = "macos")] - pub use crate::os::macos::*; #[cfg(target_os = "netbsd")] pub use crate::os::netbsd::*; #[cfg(target_os = "nto")] @@ -77,16 +75,10 @@ mod platform { pub use crate::os::redox::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; - #[cfg(target_os = "tvos")] - pub use crate::os::tvos::*; - #[cfg(target_os = "visionos")] - pub use crate::os::visionos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] pub use crate::os::vxworks::*; - #[cfg(target_os = "watchos")] - pub use crate::os::watchos::*; } pub mod ffi; diff --git a/library/std/src/os/visionos/fs.rs b/library/std/src/os/visionos/fs.rs deleted file mode 100644 index e5df4de0b7f7..000000000000 --- a/library/std/src/os/visionos/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use super::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/visionos/mod.rs b/library/std/src/os/visionos/mod.rs deleted file mode 100644 index f4b061ffda89..000000000000 --- a/library/std/src/os/visionos/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! visionos-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod fs; -pub mod raw; diff --git a/library/std/src/os/visionos/raw.rs b/library/std/src/os/visionos/raw.rs deleted file mode 100644 index 2b3eca6f493d..000000000000 --- a/library/std/src/os/visionos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! visionos-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/library/std/src/os/watchos/fs.rs b/library/std/src/os/watchos/fs.rs deleted file mode 100644 index ee215dd59844..000000000000 --- a/library/std/src/os/watchos/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use crate::os::watchos::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/watchos/mod.rs b/library/std/src/os/watchos/mod.rs deleted file mode 100644 index cd6454ebbf99..000000000000 --- a/library/std/src/os/watchos/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! watchOS-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod fs; -pub mod raw; diff --git a/library/std/src/os/watchos/raw.rs b/library/std/src/os/watchos/raw.rs deleted file mode 100644 index 630a533d9aaf..000000000000 --- a/library/std/src/os/watchos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! watchOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/triagebot.toml b/triagebot.toml index 3abff0f1c784..a065fe228bc4 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -221,6 +221,13 @@ trigger_files = [ "library/std/src/os/android" ] +[autolabel."O-apple"] +trigger_files = [ + "library/std/src/os/darwin", + "library/std/src/sys/pal/unix/thread_parking/darwin.rs", + "compiler/rustc_target/src/spec/base/apple", +] + [autolabel."O-fuchsia"] trigger_files = [ "library/std/src/os/fuchsia" @@ -250,8 +257,6 @@ trigger_files = [ [autolabel."O-macos"] trigger_files = [ "library/std/src/os/macos", - "library/std/src/sys/pal/unix/thread_parking/darwin.rs", - "compiler/rustc_target/src/spec/base/apple", ] [autolabel."O-netbsd"] @@ -299,22 +304,12 @@ trigger_files = [ "library/std/src/os/wasm" ] -[autolabel."O-watchos"] -trigger_files = [ - "library/std/src/os/watchos" -] - [autolabel."O-windows"] trigger_files = [ "library/std/src/sys/pal/windows", "library/std/src/os/windows" ] -[autolabel."O-visionos"] -trigger_files = [ - "library/std/src/os/visionos" -] - [autolabel."T-bootstrap"] trigger_files = [ "x.py", From e595f3d13f0491186577d7b6e0290f31791f5059 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 12 Jul 2024 13:08:05 +0800 Subject: [PATCH 309/361] Add cache for `allocate_str` --- .../rustc_const_eval/src/interpret/place.rs | 14 +++++++++++++- compiler/rustc_middle/src/mir/interpret/mod.rs | 17 +++++++++++------ compiler/rustc_middle/src/ty/context.rs | 5 +++-- .../src/build/expr/as_constant.rs | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index baaee67e7871..33c25b746ccc 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -995,13 +995,25 @@ where } /// Returns a wide MPlace of type `str` to a new 1-aligned allocation. + /// Immutable strings are deduplicated and stored in global memory. pub fn allocate_str( &mut self, str: &str, kind: MemoryKind, mutbl: Mutability, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; + let tcx = self.tcx.tcx; + + // Use cache for immutable strings. + let ptr = if mutbl.is_not() { + // Use dedup'd allocation function. + let id = tcx.allocate_bytes_dedup(str.as_bytes()); + + // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation. + M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))? + } else { + self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)? + }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 4e95e600b5ab..bdd1eb11a38e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -393,7 +393,6 @@ pub(crate) struct AllocMap<'tcx> { alloc_map: FxHashMap>, /// Used to ensure that statics and functions only get one associated `AllocId`. - /// Should never contain a `GlobalAlloc::Memory`! // // FIXME: Should we just have two separate dedup maps for statics and functions each? dedup: FxHashMap, AllocId>, @@ -433,13 +432,13 @@ impl<'tcx> TyCtxt<'tcx> { } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we - /// don't want to dedup IDs for "real" memory! + /// Should not be used for mutable memory. fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); - match alloc { - GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} - GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), + if let GlobalAlloc::Memory(mem) = alloc { + if mem.inner().mutability.is_mut() { + bug!("trying to dedup-reserve mutable memory"); + } } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { return alloc_id; @@ -451,6 +450,12 @@ impl<'tcx> TyCtxt<'tcx> { id } + /// Generates an `AllocId` for a memory allocation. If the exact same memory has been + /// allocated before, this will return the same `AllocId`. + pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Memory(mem)) + } + /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9e24ea485b26..25070e6b042c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1442,11 +1442,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Allocates a read-only byte or string literal for `mir::interpret`. - pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { + /// Returns the same `AllocId` if called again with the same bytes. + pub fn allocate_bytes_dedup(self, bytes: &[u8]) -> interpret::AllocId { // Create an allocation that just contains these bytes. let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes); let alloc = self.mk_const_alloc(alloc); - self.reserve_and_set_memory_alloc(alloc) + self.reserve_and_set_memory_dedup(alloc) } /// Returns a range of the start/end indices specified with the diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3b69058d3cb4..be62a3d37365 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -140,7 +140,7 @@ fn lit_to_mir_constant<'tcx>( ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes(data); + let id = tcx.allocate_bytes_dedup(data); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => From 9a23878ea7486cf1667e4f30cbc58d3bed5e86e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Jul 2024 18:43:15 +0200 Subject: [PATCH 310/361] add test for intermediate reference in '&(*x).0 as *const i32' --- .../dangling_pointer_to_raw_pointer.rs | 20 +++++++++++++++++++ .../dangling_pointer_to_raw_pointer.stderr | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs create mode 100644 src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs new file mode 100644 index 000000000000..023bce1616b8 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs @@ -0,0 +1,20 @@ +#![feature(raw_ref_op)] +#![feature(strict_provenance)] +use std::ptr; + +fn direct_raw(x: *const (i32, i32)) -> *const i32 { + unsafe { &raw const (*x).0 } +} + +// Ensure that if a raw pointer is created via an intermediate +// reference, we catch that. (Just in case someone decides to +// desugar this differenly or so.) +fn via_ref(x: *const (i32, i32)) -> *const i32 { + unsafe { &(*x).0 as *const i32 } //~ERROR: dangling pointer +} + +fn main() { + let ptr = ptr::without_provenance(0x10); + direct_raw(ptr); // this is fine + via_ref(ptr); // this is not +} 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 new file mode 100644 index 000000000000..37f2bb395576 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) + --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + | +LL | unsafe { &(*x).0 as *const i32 } + | ^^^^^^^ out-of-bounds pointer use: 0x10[noalloc] 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 + = note: BACKTRACE: + = note: inside `via_ref` at $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC +note: inside `main` + --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + | +LL | via_ref(ptr); // this is not + | ^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 32221c3a10070822921cbc3f5f3e261f76658130 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 13 Jul 2024 18:25:41 +0200 Subject: [PATCH 311/361] implement the `os_unfair_lock` functions on macOS --- src/tools/miri/src/concurrency/sync.rs | 21 +++- src/tools/miri/src/provenance_gc.rs | 11 ++ .../src/shims/unix/macos/foreign_items.rs | 22 ++++ src/tools/miri/src/shims/unix/macos/mod.rs | 1 + src/tools/miri/src/shims/unix/macos/sync.rs | 107 ++++++++++++++++++ src/tools/miri/src/shims/unix/sync.rs | 2 +- .../apple_os_unfair_lock_assert_not_owner.rs | 13 +++ ...ple_os_unfair_lock_assert_not_owner.stderr | 13 +++ .../apple_os_unfair_lock_assert_owner.rs | 12 ++ .../apple_os_unfair_lock_assert_owner.stderr | 13 +++ .../apple_os_unfair_lock_reentrant.rs | 13 +++ .../apple_os_unfair_lock_reentrant.stderr | 13 +++ .../apple_os_unfair_lock_unowned.rs | 12 ++ .../apple_os_unfair_lock_unowned.stderr | 13 +++ .../concurrency/apple-os-unfair-lock.rs | 25 ++++ 15 files changed, 284 insertions(+), 7 deletions(-) create mode 100644 src/tools/miri/src/shims/unix/macos/sync.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr create mode 100644 src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 91865a2192cf..d0c9a4600e85 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -269,7 +269,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); if this.mutex_is_locked(mutex) { assert_ne!(this.mutex_get_owner(mutex), this.active_thread()); - this.mutex_enqueue_and_block(mutex, retval, dest); + this.mutex_enqueue_and_block(mutex, Some((retval, dest))); } else { // We can have it right now! this.mutex_lock(mutex); @@ -390,9 +390,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Put the thread into the queue waiting for the mutex. - /// Once the Mutex becomes available, `retval` will be written to `dest`. + /// + /// Once the Mutex becomes available and if it exists, `retval_dest.0` will + /// be written to `retval_dest.1`. #[inline] - fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) { + fn mutex_enqueue_and_block( + &mut self, + id: MutexId, + retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, + ) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); let thread = this.active_thread(); @@ -403,13 +409,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: MutexId, - retval: Scalar, - dest: MPlaceTy<'tcx>, + retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, } @unblock = |this| { assert!(!this.mutex_is_locked(id)); this.mutex_lock(id); - this.write_scalar(retval, &dest)?; + + if let Some((retval, dest)) = retval_dest { + this.write_scalar(retval, &dest)?; + } + Ok(()) } ), diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index af980ca48197..8edd80744ddc 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -30,6 +30,17 @@ impl VisitProvenance for Option { } } +impl VisitProvenance for (A, B) +where + A: VisitProvenance, + B: VisitProvenance, +{ + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + self.0.visit_provenance(visit); + self.1.visit_provenance(visit); + } +} + impl VisitProvenance for std::cell::RefCell { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { self.borrow().visit_provenance(visit) diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index aefb5b2de56f..47b887dec947 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -1,6 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use super::sync::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -174,6 +175,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + "os_unfair_lock_lock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_lock(lock_op)?; + } + "os_unfair_lock_trylock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_trylock(lock_op, dest)?; + } + "os_unfair_lock_unlock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_unlock(lock_op)?; + } + "os_unfair_lock_assert_owner" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_assert_owner(lock_op)?; + } + "os_unfair_lock_assert_not_owner" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_assert_not_owner(lock_op)?; + } + _ => return Ok(EmulateItemResult::NotSupported), }; diff --git a/src/tools/miri/src/shims/unix/macos/mod.rs b/src/tools/miri/src/shims/unix/macos/mod.rs index 09c6507b24f8..50fb2b9d3287 100644 --- a/src/tools/miri/src/shims/unix/macos/mod.rs +++ b/src/tools/miri/src/shims/unix/macos/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod sync; diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs new file mode 100644 index 000000000000..5e5fccb587b4 --- /dev/null +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -0,0 +1,107 @@ +//! Contains macOS-specific synchronization functions. +//! +//! For `os_unfair_lock`, see the documentation +//! +//! and in case of underspecification its implementation +//! . +//! +//! Note that we don't emulate every edge-case behaviour of the locks. Notably, +//! we don't abort when locking a lock owned by a thread that has already exited +//! and we do not detect copying of the lock, but macOS doesn't guarantee anything +//! in that case either. + +use crate::*; + +impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} +trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> { + let this = self.eval_context_mut(); + // os_unfair_lock holds a 32-bit value, is initialized with zero and + // must be assumed to be opaque. Therefore, we can just store our + // internal mutex ID in the structure without anyone noticing. + this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0) + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) { + if this.mutex_get_owner(id) == this.active_thread() { + // Matching the current macOS implementation: abort on reentrant locking. + throw_machine_stop!(TerminationInfo::Abort( + "attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned() + )); + } + + this.mutex_enqueue_and_block(id, None); + } else { + this.mutex_lock(id); + } + + Ok(()) + } + + fn os_unfair_lock_trylock( + &mut self, + lock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) { + // Contrary to the blocking lock function, this does not check for + // reentrancy. + this.write_scalar(Scalar::from_bool(false), dest)?; + } else { + this.mutex_lock(id); + this.write_scalar(Scalar::from_bool(true), dest)?; + } + + Ok(()) + } + + fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_unlock(id)?.is_none() { + // Matching the current macOS implementation: abort. + throw_machine_stop!(TerminationInfo::Abort( + "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned() + )); + } + + Ok(()) + } + + fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() { + throw_machine_stop!(TerminationInfo::Abort( + "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned() + )); + } + + Ok(()) + } + + fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() { + throw_machine_stop!(TerminationInfo::Abort( + "called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned() + )); + } + + Ok(()) + } +} diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index be6732b1b67e..e8653117ae94 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -473,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ret = if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != this.active_thread() { - this.mutex_enqueue_and_block(id, Scalar::from_i32(0), dest.clone()); + this.mutex_enqueue_and_block(id, Some((Scalar::from_i32(0), dest.clone()))); return Ok(()); } else { // Trying to acquire the same mutex again. diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs new file mode 100644 index 000000000000..d6604f371394 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs @@ -0,0 +1,13 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_assert_not_owner(lock.get()); + //~^ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr new file mode 100644 index 000000000000..7e890681c436 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + --> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC + | +LL | libc::os_unfair_lock_assert_not_owner(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.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/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs new file mode 100644 index 000000000000..ddd8b572eaf0 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs @@ -0,0 +1,12 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_assert_owner(lock.get()); + //~^ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr new file mode 100644 index 000000000000..3724f7996fb8 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + --> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC + | +LL | libc::os_unfair_lock_assert_owner(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.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/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs new file mode 100644 index 000000000000..eb98adeba073 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs @@ -0,0 +1,13 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_lock(lock.get()); + //~^ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr new file mode 100644 index 000000000000..644462a1b05f --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread + --> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC + | +LL | libc::os_unfair_lock_lock(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.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/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs new file mode 100644 index 000000000000..aed467552ab9 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs @@ -0,0 +1,12 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_unlock(lock.get()); + //~^ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr new file mode 100644 index 000000000000..6a8d12fa8076 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread + --> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC + | +LL | libc::os_unfair_lock_unlock(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_unowned.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-dep/concurrency/apple-os-unfair-lock.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs new file mode 100644 index 000000000000..c2b9c37bbfb2 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs @@ -0,0 +1,25 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_assert_owner(lock.get()); + assert!(!libc::os_unfair_lock_trylock(lock.get())); + libc::os_unfair_lock_unlock(lock.get()); + + libc::os_unfair_lock_assert_not_owner(lock.get()); + } + + // `os_unfair_lock`s can be moved and leaked. + // In the real implementation, even moving it while locked is possible + // (and "forks" the lock, i.e. old and new location have independent wait queues); + // Miri behavior differs here and anyway none of this is documented. + let lock = lock; + let locked = unsafe { libc::os_unfair_lock_trylock(lock.get()) }; + assert!(locked); + let _lock = lock; +} From dc207339137a766d7f45590a97cfa0f2a0314e2f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 13:50:27 -0400 Subject: [PATCH 312/361] Stop using the gen keyword in the compiler --- compiler/rustc_borrowck/src/dataflow.rs | 2 +- compiler/rustc_hir/src/hir.rs | 18 +++++------ .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_middle/src/mir/visit.rs | 6 ++-- .../rustc_mir_dataflow/src/framework/mod.rs | 30 +++++++++---------- .../src/impls/borrowed_locals.rs | 8 ++--- .../src/impls/initialized.rs | 18 +++++------ .../rustc_mir_dataflow/src/impls/liveness.rs | 4 +-- .../src/impls/storage_liveness.rs | 12 ++++---- src/bootstrap/src/core/builder.rs | 3 ++ 10 files changed, 53 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 00a30dc2240a..59b3c6916cbd 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -553,7 +553,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> { panic!("could not find BorrowIndex for location {location:?}"); }); - trans.gen(index); + trans.gen_(index); } // Make sure there are no remaining borrows for variables diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4561f9d9b49d..3bd7b300758c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3218,10 +3218,10 @@ impl<'hir> Item<'hir> { ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body); expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Const(ty, gen, body), (ty, gen, *body); + ItemKind::Const(ty, generics, body), (ty, generics, *body); expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Fn(sig, gen, body), (sig, gen, *body); + ItemKind::Fn(sig, generics, body), (sig, generics, *body); expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk); @@ -3233,25 +3233,25 @@ impl<'hir> Item<'hir> { expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm; expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), - ItemKind::TyAlias(ty, gen), (ty, gen); + ItemKind::TyAlias(ty, generics), (ty, generics); expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty; - expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, gen), (def, gen); + expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics); expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Struct(data, gen), (data, gen); + ItemKind::Struct(data, generics), (data, generics); expect_union, (&VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Union(data, gen), (data, gen); + ItemKind::Union(data, generics), (data, generics); expect_trait, (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), - ItemKind::Trait(is_auto, safety, gen, bounds, items), - (*is_auto, *safety, gen, bounds, items); + ItemKind::Trait(is_auto, safety, generics, bounds, items), + (*is_auto, *safety, generics, bounds, items); expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>), - ItemKind::TraitAlias(gen, bounds), (gen, bounds); + ItemKind::TraitAlias(generics, bounds), (generics, bounds); expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ab0f356ce91f..9c5880912393 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2554,7 +2554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|node| node.generics()) .into_iter() .flat_map(|generics| generics.params) - .find(|gen| &gen.def_id.to_def_id() == res_def_id) + .find(|param| ¶m.def_id.to_def_id() == res_def_id) } else { None } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 0d3c419748b7..0031ded24406 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1016,14 +1016,14 @@ macro_rules! extra_body_methods { macro_rules! super_body { ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => { let span = $body.span; - if let Some(gen) = &$($mutability)? $body.coroutine { - if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { + if let Some(coroutine) = &$($mutability)? $body.coroutine { + if let Some(yield_ty) = $(& $mutability)? coroutine.yield_ty { $self.visit_ty( yield_ty, TyContext::YieldTy(SourceInfo::outermost(span)) ); } - if let Some(resume_ty) = $(& $mutability)? gen.resume_ty { + if let Some(resume_ty) = $(& $mutability)? coroutine.resume_ty { $self.visit_ty( resume_ty, TyContext::ResumeTy(SourceInfo::outermost(span)) diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 09cdb055a3e8..6eaed0f77533 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -402,7 +402,7 @@ where /// building up a `GenKillSet` and then throwing it away. pub trait GenKill { /// Inserts `elem` into the state vector. - fn gen(&mut self, elem: T); + fn gen_(&mut self, elem: T); /// Removes `elem` from the state vector. fn kill(&mut self, elem: T); @@ -410,7 +410,7 @@ pub trait GenKill { /// Calls `gen` for each element in `elems`. fn gen_all(&mut self, elems: impl IntoIterator) { for elem in elems { - self.gen(elem); + self.gen_(elem); } } @@ -424,12 +424,12 @@ pub trait GenKill { /// Stores a transfer function for a gen/kill problem. /// -/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be -/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for +/// Calling `gen_`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be +/// applied multiple times efficiently. When there are multiple calls to `gen_` and/or `kill` for /// the same element, the most recent one takes precedence. #[derive(Clone)] pub struct GenKillSet { - gen: HybridBitSet, + gen_: HybridBitSet, kill: HybridBitSet, } @@ -437,31 +437,31 @@ impl GenKillSet { /// Creates a new transfer function that will leave the dataflow state unchanged. pub fn identity(universe: usize) -> Self { GenKillSet { - gen: HybridBitSet::new_empty(universe), + gen_: HybridBitSet::new_empty(universe), kill: HybridBitSet::new_empty(universe), } } pub fn apply(&self, state: &mut impl BitSetExt) { - state.union(&self.gen); + state.union(&self.gen_); state.subtract(&self.kill); } } impl GenKill for GenKillSet { - fn gen(&mut self, elem: T) { - self.gen.insert(elem); + fn gen_(&mut self, elem: T) { + self.gen_.insert(elem); self.kill.remove(elem); } fn kill(&mut self, elem: T) { self.kill.insert(elem); - self.gen.remove(elem); + self.gen_.remove(elem); } } impl GenKill for BitSet { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.insert(elem); } @@ -471,7 +471,7 @@ impl GenKill for BitSet { } impl GenKill for ChunkedBitSet { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.insert(elem); } @@ -481,11 +481,11 @@ impl GenKill for ChunkedBitSet { } impl> GenKill for MaybeReachable { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { match self { // If the state is not reachable, adding an element does nothing. MaybeReachable::Unreachable => {} - MaybeReachable::Reachable(set) => set.gen(elem), + MaybeReachable::Reachable(set) => set.gen_(elem), } } @@ -499,7 +499,7 @@ impl> GenKill for MaybeReachable { } impl GenKill for lattice::Dual> { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.0.insert(elem); } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 574da949b0ed..885fdd0d58be 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -97,7 +97,7 @@ where Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => { if !borrowed_place.is_indirect() { - self.trans.gen(borrowed_place.local); + self.trans.gen_(borrowed_place.local); } } @@ -131,7 +131,7 @@ where // // [#61069]: https://github.com/rust-lang/rust/pull/61069 if !dropped_place.is_indirect() { - self.trans.gen(dropped_place.local); + self.trans.gen_(dropped_place.local); } } @@ -159,8 +159,8 @@ pub fn borrowed_locals(body: &Body<'_>) -> BitSet { impl GenKill for Borrowed { #[inline] - fn gen(&mut self, elem: Local) { - self.0.gen(elem) + fn gen_(&mut self, elem: Local) { + self.0.gen_(elem) } #[inline] fn kill(&mut self, _: Local) { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index ffcf630b653c..a9bceeccdce2 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -283,7 +283,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { ) { match state { DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), + DropFlagState::Present => trans.gen_(path), } } } @@ -295,7 +295,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, '_, 'tcx> { state: DropFlagState, ) { match state { - DropFlagState::Absent => trans.gen(path), + DropFlagState::Absent => trans.gen_(path), DropFlagState::Present => trans.kill(path), } } @@ -309,7 +309,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { ) { match state { DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), + DropFlagState::Present => trans.gen_(path), } } } @@ -331,7 +331,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len())); drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - state.gen(path); + state.gen_(path); }); } } @@ -362,7 +362,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) { on_all_children_bits(self.move_data(), mpi, |child| { - trans.gen(child); + trans.gen_(child); }) } } @@ -400,7 +400,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.gen(mpi); + trans.gen_(mpi); }, ); }); @@ -572,7 +572,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { self.move_data(), enum_place, variant, - |mpi| trans.gen(mpi), + |mpi| trans.gen_(mpi), ); }); } @@ -643,7 +643,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.gen(mpi); + trans.gen_(mpi); }, ); }); @@ -738,7 +738,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { let call_loc = self.body.terminator_loc(block); for init_index in &init_loc_map[call_loc] { - trans.gen(*init_index); + trans.gen_(*init_index); } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 334fa9976f03..48bdb1316012 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -116,7 +116,7 @@ where self.0.kill(place.local); } } - Some(DefUse::Use) => self.0.gen(place.local), + Some(DefUse::Use) => self.0.gen_(place.local), None => {} } @@ -154,7 +154,7 @@ impl DefUse { fn apply(trans: &mut impl GenKill, place: Place<'_>, context: PlaceContext) { match DefUse::for_place(place, context) { Some(DefUse::Def) => trans.kill(place.local), - Some(DefUse::Use) => trans.gen(place.local), + Some(DefUse::Use) => trans.gen_(place.local), None => {} } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index f850a7102773..682cec12f1fb 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -54,7 +54,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { _: Location, ) { match stmt.kind { - StatementKind::StorageLive(l) => trans.gen(l), + StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageDead(l) => trans.kill(l), _ => (), } @@ -127,7 +127,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { ) { match stmt.kind { StatementKind::StorageLive(l) => trans.kill(l), - StatementKind::StorageDead(l) => trans.gen(l), + StatementKind::StorageDead(l) => trans.gen_(l), _ => (), } } @@ -208,7 +208,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { StatementKind::Assign(box (place, _)) | StatementKind::SetDiscriminant { box place, .. } | StatementKind::Deinit(box place) => { - trans.gen(place.local); + trans.gen_(place.local); } // Nothing to do for these. Match exhaustively so this fails to compile when new @@ -250,7 +250,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { match &terminator.kind { TerminatorKind::Call { destination, .. } => { - trans.gen(destination.local); + trans.gen_(destination.local); } // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for @@ -265,7 +265,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { InlineAsmOperand::Out { place, .. } | InlineAsmOperand::InOut { out_place: place, .. } => { if let Some(place) = place { - trans.gen(place.local); + trans.gen_(place.local); } } InlineAsmOperand::In { .. } @@ -341,7 +341,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { - return_places.for_each(|place| trans.gen(place.local)); + return_places.for_each(|place| trans.gen_(place.local)); } } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index aeb347436080..398a5f73d7b7 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1998,6 +1998,9 @@ impl<'a> Builder<'a> { if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); + // FIXME(edition_2024): Change this to `-Wrust_2018_idioms` when all + // of the individual lints are satisfied. + rustflags.arg("-Wkeyword_idents_2024"); } if self.config.rust_frame_pointers { From f08c43afc7b801f2ab0109764df9cc959ebc8b79 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 14:22:11 -0400 Subject: [PATCH 313/361] Suppress some fallout from gen in synstructure --- compiler/rustc_macros/src/diagnostics/diagnostic.rs | 4 ++++ compiler/rustc_macros/src/diagnostics/subdiagnostic.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index a3abbdcf18ca..2743660ab891 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -71,6 +71,8 @@ impl<'a> DiagnosticDerive<'a> { }); // A lifetime of `'a` causes conflicts, but `_sess` is fine. + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let mut imp = structure.gen_impl(quote! { gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self where G: rustc_errors::EmissionGuarantee @@ -148,6 +150,8 @@ impl<'a> LintDiagnosticDerive<'a> { } }); + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let mut imp = structure.gen_impl(quote! { gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self { #[track_caller] diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 69014f39925a..7f090f5ebc16 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -86,6 +86,9 @@ impl SubdiagnosticDerive { let diag = &self.diag; let f = &self.f; + + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let ret = structure.gen_impl(quote! { gen impl rustc_errors::Subdiagnostic for @Self { fn add_to_diag_with<__G, __F>( @@ -100,6 +103,7 @@ impl SubdiagnosticDerive { } } }); + ret } } From bbf303ed146d9f5bb08caabf153019ab1909c83e Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 14 Jul 2024 21:43:20 +0300 Subject: [PATCH 314/361] sys::init is not unsafe on teeos --- library/std/src/rt.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index c0a1c5f5594a..d030017cfb4e 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -90,13 +90,14 @@ macro_rules! rtunwrap { // `compiler/rustc_session/src/config/sigpipe.rs`. #[cfg_attr(test, allow(dead_code))] unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { + #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] unsafe { - sys::init(argc, argv, sigpipe); + sys::init(argc, argv, sigpipe) + }; - // Set up the current thread to give it the right name. - let thread = Thread::new_main(); - thread::set_current(thread); - } + // Set up the current thread to give it the right name. + let thread = Thread::new_main(); + thread::set_current(thread); } // One-time runtime cleanup. From 80393ea7a8a789d26643b3038410d85a9315c117 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 14:52:36 -0400 Subject: [PATCH 315/361] Fix trivial gen ident usage in tools --- src/bootstrap/src/core/builder.rs | 2 +- src/librustdoc/clean/mod.rs | 4 ++-- src/librustdoc/html/render/search_index.rs | 6 +++--- .../clippy/clippy_lints/src/misc_early/mod.rs | 4 ++-- .../clippy/clippy_lints/src/trait_bounds.rs | 20 +++++++++---------- .../clippy_lints/src/types/type_complexity.rs | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 398a5f73d7b7..f033905e9f62 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1998,7 +1998,7 @@ impl<'a> Builder<'a> { if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); - // FIXME(edition_2024): Change this to `-Wrust_2018_idioms` when all + // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // of the individual lints are satisfied. rustflags.arg("-Wkeyword_idents_2024"); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 98ce268a7746..a0e28d2f55c7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1052,12 +1052,12 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { match literal.kind { ast::LitKind::Int(a, _) => { - let gen = func.generics.params.remove(0); + let param = func.generics.params.remove(0); if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. }, .. - } = gen + } = param { func.decl .inputs diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index bc8bdffc3314..66d3f0fd8ce8 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1051,7 +1051,7 @@ fn simplify_fn_type<'tcx, 'a>( let mut ty_generics = Vec::new(); let mut ty_constraints = Vec::new(); if let Some(arg_generics) = arg.generic_args() { - for ty in arg_generics.into_iter().filter_map(|gen| match gen { + for ty in arg_generics.into_iter().filter_map(|param| match param { clean::GenericArg::Type(ty) => Some(ty), _ => None, }) { @@ -1172,8 +1172,8 @@ fn simplify_fn_constraint<'tcx, 'a>( ) { let mut ty_constraints = Vec::new(); let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name); - for gen in &constraint.assoc.args { - match gen { + for param in &constraint.assoc.args { + match param { clean::GenericArg::Type(arg) => simplify_fn_type( self_, generics, diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index fedcfd11fdcc..4cba13a05c24 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -364,8 +364,8 @@ declare_lint_pass!(MiscEarlyLints => [ ]); impl EarlyLintPass for MiscEarlyLints { - fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { - for param in &gen.params { + fn check_generics(&mut self, cx: &EarlyContext<'_>, generics: &Generics) { + for param in &generics.params { builtin_type_shadow::check(cx, param); } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index c05cd9ed5934..07390d6f4302 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -102,9 +102,9 @@ impl TraitBounds { impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { - fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { - self.check_type_repetition(cx, gen); - check_trait_bound_duplication(cx, gen); + fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { + self.check_type_repetition(cx, generics); + check_trait_bound_duplication(cx, generics); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { @@ -238,7 +238,7 @@ impl TraitBounds { } #[allow(clippy::mutable_key_type)] - fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { + fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, cx: &'cx LateContext<'tcx>, @@ -258,12 +258,12 @@ impl TraitBounds { } impl Eq for SpanlessTy<'_, '_> {} - if gen.span.from_expansion() { + if generics.span.from_expansion() { return; } let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; - for bound in gen.predicates { + for bound in generics.predicates { if let WherePredicate::BoundPredicate(ref p) = bound && p.origin != PredicateOrigin::ImplTrait && p.bounds.len() as u64 <= self.max_trait_bounds @@ -301,8 +301,8 @@ impl TraitBounds { } } -fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() { +fn check_trait_bound_duplication(cx: &LateContext<'_>, generics: &'_ Generics<'_>) { + if generics.span.from_expansion() { return; } @@ -313,7 +313,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // collects each of these where clauses into a set keyed by generic name and comparable trait // eg. (T, Clone) - let where_predicates = gen + let where_predicates = generics .predicates .iter() .filter_map(|pred| { @@ -342,7 +342,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // compare trait bounds keyed by generic name and comparable trait to collected where // predicates eg. (T, Clone) - for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) { + for predicate in generics.predicates.iter().filter(|pred| !pred.in_where_clause()) { if let WherePredicate::BoundPredicate(bound_predicate) = predicate && bound_predicate.origin != PredicateOrigin::ImplTrait && !bound_predicate.span.from_expansion() diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index 0aa50c99c169..b6e765d7c393 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { bound .bound_generic_params .iter() - .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) + .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) }); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> From f18d4a86a71603f0a01a56ca22e9fca67b8edff6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 14 Jul 2024 17:53:39 -0400 Subject: [PATCH 316/361] Add myself to the review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 9c0026ced2e1..d47d54d45c0b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -941,6 +941,7 @@ libs = [ "@workingjubilee", "@joboet", "@jhpratt", + "@tgross35", ] bootstrap = [ "@Mark-Simulacrum", From d939351c311676baa887b27aabac490c360d0e14 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 14 Jul 2024 15:07:43 +0000 Subject: [PATCH 317/361] std: removes logarithms family function edge cases handling for solaris. Issue had been fixed over time with solaris, 11.x behaves correctly (and we support it as minimum), illumos works correctly too. --- library/std/src/f64.rs | 6 +++--- library/std/src/sys/pal/mod.rs | 31 ------------------------------- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index f8c66a3e7175..1ca2b32e241c 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -520,7 +520,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f64 { - crate::sys::log_wrapper(self, |n| unsafe { intrinsics::logf64(n) }) + unsafe { intrinsics::logf64(self) } } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -574,7 +574,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - crate::sys::log_wrapper(self, crate::sys::log2f64) + crate::sys::log2f64(self) } /// Returns the base 10 logarithm of the number. @@ -599,7 +599,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f64 { - crate::sys::log_wrapper(self, |n| unsafe { intrinsics::log10f64(n) }) + unsafe { intrinsics::log10f64(self) } } /// The positive difference of two numbers. diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 8c75ac652998..df0176244489 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -94,36 +94,5 @@ cfg_if::cfg_if! { } } -// Solaris/Illumos requires a wrapper around log, log2, and log10 functions -// because of their non-standard behavior (e.g., log(-n) returns -Inf instead -// of expected NaN). -#[cfg(not(test))] -#[cfg(any(target_os = "solaris", target_os = "illumos"))] -#[inline] -pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { - if n.is_finite() { - if n > 0.0 { - log_fn(n) - } else if n == 0.0 { - f64::NEG_INFINITY // log(0) = -Inf - } else { - f64::NAN // log(-n) = NaN - } - } else if n.is_nan() { - n // log(NaN) = NaN - } else if n > 0.0 { - n // log(Inf) = Inf - } else { - f64::NAN // log(-Inf) = NaN - } -} - -#[cfg(not(test))] -#[cfg(not(any(target_os = "solaris", target_os = "illumos")))] -#[inline] -pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { - log_fn(n) -} - #[cfg(not(target_os = "uefi"))] pub type RawOsError = i32; From 3a2c0aedf1bd1371e5e58cbf0f2cf51fca02494e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 27 Jun 2024 03:21:25 -0400 Subject: [PATCH 318/361] Add `classify` and related methods for `f16` and `f128` --- library/core/src/num/f128.rs | 120 +++++++++++++++++++++++++ library/core/src/num/f16.rs | 162 +++++++++++++++++++++++++++++++++- library/std/src/f128/tests.rs | 66 ++++++++++---- library/std/src/f16/tests.rs | 66 ++++++++++---- 4 files changed, 375 insertions(+), 39 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 58ed98c888cc..ad5a5ee9905a 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -13,6 +13,7 @@ use crate::convert::FloatToInt; use crate::mem; +use crate::num::FpCategory; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] @@ -251,6 +252,12 @@ impl f128 { #[cfg(not(bootstrap))] pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + /// Exponent mask + pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000; + + /// Mantissa mask + pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff; + /// Minimum representable positive value (min subnormal) #[cfg(not(bootstrap))] const TINY_BITS: u128 = 0x1; @@ -354,6 +361,119 @@ impl f128 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128 + /// let max = f128::MAX; + /// let lower_than_min = 1.0e-4960_f128; + /// let zero = 0.0_f128; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f128::NAN.is_subnormal()); + /// assert!(!f128::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// # } + /// ``` + /// + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + + /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128 + /// let max = f128::MAX; + /// let lower_than_min = 1.0e-4960_f128; + /// let zero = 0.0_f128; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f128::NAN.is_normal()); + /// assert!(!f128::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// # } + /// ``` + /// + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) + } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// use std::num::FpCategory; + /// + /// let num = 12.4_f128; + /// let inf = f128::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// # } + /// ``` + #[inline] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { + // Other float types cannot use a bitwise classify because they may suffer a variety + // of errors if the backend chooses to cast to different float types (x87). `f128` cannot + // fit into any other float types so this is not a concern, and we rely on bit patterns. + + // SAFETY: POD bitcast, same as in `to_bits`. + let bits = unsafe { mem::transmute::(self) }; + Self::classify_bits(bits) + } + + /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs. + /// FIXME(jubilee): In a just world, this would be the entire impl for classify, + /// plus a transmute. We do not live in a just world, but we can make it more so. + #[inline] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn classify_bits(b: u128) -> FpCategory { + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3c58b0af9c27..198a506f2b85 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -13,6 +13,7 @@ use crate::convert::FloatToInt; use crate::mem; +use crate::num::FpCategory; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] @@ -244,7 +245,13 @@ impl f16 { /// Sign bit #[cfg(not(bootstrap))] - const SIGN_MASK: u16 = 0x8000; + pub(crate) const SIGN_MASK: u16 = 0x8000; + + /// Exponent mask + pub(crate) const EXP_MASK: u16 = 0x7c00; + + /// Mantissa mask + pub(crate) const MAN_MASK: u16 = 0x03ff; /// Minimum representable positive value (min subnormal) #[cfg(not(bootstrap))] @@ -344,6 +351,159 @@ impl f16 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let min = f16::MIN_POSITIVE; // 6.1035e-5 + /// let max = f16::MAX; + /// let lower_than_min = 1.0e-7_f16; + /// let zero = 0.0_f16; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f16::NAN.is_subnormal()); + /// assert!(!f16::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// # } + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + + /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let min = f16::MIN_POSITIVE; // 6.1035e-5 + /// let max = f16::MAX; + /// let lower_than_min = 1.0e-7_f16; + /// let zero = 0.0_f16; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f16::NAN.is_normal()); + /// assert!(!f16::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// # } + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) + } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// use std::num::FpCategory; + /// + /// let num = 12.4_f16; + /// let inf = f16::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// # } + /// ``` + #[inline] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { + // A previous implementation for f32/f64 tried to only use bitmask-based checks, + // using `to_bits` to transmute the float to its bit repr and match on that. + // Unfortunately, floating point numbers can be much worse than that. + // This also needs to not result in recursive evaluations of `to_bits`. + // + + // Platforms without native support generally convert to `f32` to perform operations, + // and most of these platforms correctly round back to `f16` after each operation. + // However, some platforms have bugs where they keep the excess `f32` precision (e.g. + // WASM, see llvm/llvm-project#96437). This implementation makes a best-effort attempt + // to account for that excess precision. + if self.is_infinite() { + // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask. + FpCategory::Infinite + } else if self.is_nan() { + // And it may not be NaN, as it can simply be an "overextended" finite value. + FpCategory::Nan + } else { + // However, std can't simply compare to zero to check for zero, either, + // as correctness requires avoiding equality tests that may be Subnormal == -0.0 + // because it may be wrong under "denormals are zero" and "flush to zero" modes. + // Most of std's targets don't use those, but they are used for thumbv7neon. + // So, this does use bitpattern matching for the rest. + + // SAFETY: f16 to u16 is fine. Usually. + // If classify has gotten this far, the value is definitely in one of these categories. + unsafe { f16::partial_classify(self) } + } + } + + /// This doesn't actually return a right answer for NaN on purpose, + /// seeing as how it cannot correctly discern between a floating point NaN, + /// and some normal floating point numbers truncated from an x87 FPU. + /// + /// # Safety + /// + /// This requires making sure you call this function for values it answers correctly on, + /// otherwise it returns a wrong answer. This is not important for memory safety per se, + /// but getting floats correct is important for not accidentally leaking const eval + /// runtime-deviating logic which may or may not be acceptable. + #[inline] + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const unsafe fn partial_classify(self) -> FpCategory { + // SAFETY: The caller is not asking questions for which this will tell lies. + let b = unsafe { mem::transmute::(self) }; + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + + /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs. + /// FIXME(jubilee): In a just world, this would be the entire impl for classify, + /// plus a transmute. We do not live in a just world, but we can make it more so. + #[inline] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn classify_bits(b: u16) -> FpCategory { + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index bd7a921c502a..0b3e485b0e73 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -3,6 +3,7 @@ #![cfg(reliable_f128)] use crate::f128::consts; +use crate::num::FpCategory as Fp; use crate::num::*; /// Smallest number @@ -52,9 +53,8 @@ fn test_nan() { assert!(!nan.is_finite()); assert!(nan.is_sign_positive()); assert!(!nan.is_sign_negative()); - // FIXME(f16_f128): classify - // assert!(!nan.is_normal()); - // assert_eq!(Fp::Nan, nan.classify()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); } #[test] @@ -65,9 +65,8 @@ fn test_infinity() { assert!(inf.is_sign_positive()); assert!(!inf.is_sign_negative()); assert!(!inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!inf.is_normal()); - // assert_eq!(Fp::Infinite, inf.classify()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); } #[test] @@ -78,9 +77,8 @@ fn test_neg_infinity() { assert!(!neg_inf.is_sign_positive()); assert!(neg_inf.is_sign_negative()); assert!(!neg_inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_inf.is_normal()); - // assert_eq!(Fp::Infinite, neg_inf.classify()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); } #[test] @@ -92,9 +90,8 @@ fn test_zero() { assert!(zero.is_sign_positive()); assert!(!zero.is_sign_negative()); assert!(!zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!zero.is_normal()); - // assert_eq!(Fp::Zero, zero.classify()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); } #[test] @@ -106,9 +103,8 @@ fn test_neg_zero() { assert!(!neg_zero.is_sign_positive()); assert!(neg_zero.is_sign_negative()); assert!(!neg_zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_zero.is_normal()); - // assert_eq!(Fp::Zero, neg_zero.classify()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); } #[test] @@ -120,9 +116,8 @@ fn test_one() { assert!(one.is_sign_positive()); assert!(!one.is_sign_negative()); assert!(!one.is_nan()); - // FIXME(f16_f128): classify - // assert!(one.is_normal()); - // assert_eq!(Fp::Normal, one.classify()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); } #[test] @@ -164,7 +159,40 @@ fn test_is_finite() { assert!((-109.2f128).is_finite()); } -// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working +#[test] +fn test_is_normal() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f128.is_normal()); + assert!(1e-4931f128.is_normal()); + assert!(!1e-4932f128.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f128.classify(), Fp::Normal); + assert_eq!(1e-4931f128.classify(), Fp::Normal); + assert_eq!(1e-4932f128.classify(), Fp::Subnormal); +} + // FIXME(f16_f128): add missing math functions when available #[test] diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs index bb6a811529e1..26658a0be87b 100644 --- a/library/std/src/f16/tests.rs +++ b/library/std/src/f16/tests.rs @@ -3,6 +3,7 @@ #![cfg(reliable_f16)] use crate::f16::consts; +use crate::num::FpCategory as Fp; use crate::num::*; // We run out of precision pretty quickly with f16 @@ -58,9 +59,8 @@ fn test_nan() { assert!(!nan.is_finite()); assert!(nan.is_sign_positive()); assert!(!nan.is_sign_negative()); - // FIXME(f16_f128): classify - // assert!(!nan.is_normal()); - // assert_eq!(Fp::Nan, nan.classify()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); } #[test] @@ -71,9 +71,8 @@ fn test_infinity() { assert!(inf.is_sign_positive()); assert!(!inf.is_sign_negative()); assert!(!inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!inf.is_normal()); - // assert_eq!(Fp::Infinite, inf.classify()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); } #[test] @@ -84,9 +83,8 @@ fn test_neg_infinity() { assert!(!neg_inf.is_sign_positive()); assert!(neg_inf.is_sign_negative()); assert!(!neg_inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_inf.is_normal()); - // assert_eq!(Fp::Infinite, neg_inf.classify()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); } #[test] @@ -98,9 +96,8 @@ fn test_zero() { assert!(zero.is_sign_positive()); assert!(!zero.is_sign_negative()); assert!(!zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!zero.is_normal()); - // assert_eq!(Fp::Zero, zero.classify()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); } #[test] @@ -112,9 +109,8 @@ fn test_neg_zero() { assert!(!neg_zero.is_sign_positive()); assert!(neg_zero.is_sign_negative()); assert!(!neg_zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_zero.is_normal()); - // assert_eq!(Fp::Zero, neg_zero.classify()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); } #[test] @@ -126,9 +122,8 @@ fn test_one() { assert!(one.is_sign_positive()); assert!(!one.is_sign_negative()); assert!(!one.is_nan()); - // FIXME(f16_f128): classify - // assert!(one.is_normal()); - // assert_eq!(Fp::Normal, one.classify()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); } #[test] @@ -170,7 +165,40 @@ fn test_is_finite() { assert!((-109.2f16).is_finite()); } -// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working +#[test] +fn test_is_normal() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f16.is_normal()); + assert!(1e-4f16.is_normal()); + assert!(!1e-5f16.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f16.classify(), Fp::Normal); + assert_eq!(1e-4f16.classify(), Fp::Normal); + assert_eq!(1e-5f16.classify(), Fp::Subnormal); +} + // FIXME(f16_f128): add missing math functions when available #[test] From 4572ed63899d5f692cf4f34ce374d634aa104c73 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 16:43:50 -0700 Subject: [PATCH 319/361] std: deny(unsafe_op_in_unsafe_fn) but allow sites This provides a list of locations to hunt down issues in. --- library/std/src/collections/hash/map.rs | 2 ++ library/std/src/env.rs | 1 + library/std/src/ffi/mod.rs | 1 + library/std/src/io/mod.rs | 1 + library/std/src/lib.rs | 3 ++- library/std/src/os/mod.rs | 1 + library/std/src/sync/mod.rs | 1 + library/std/src/sys/mod.rs | 2 ++ library/std/src/sys_common/mod.rs | 1 + 9 files changed, 12 insertions(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index fcd1c307b5af..955f4013ab65 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,3 +1,5 @@ +#![allow(unsafe_op_in_unsafe_fn)] + #[cfg(test)] mod tests; diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 2f35e721610e..b47b6531d538 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -9,6 +9,7 @@ //! and those without will return a [`String`]. #![stable(feature = "env", since = "1.0.0")] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index f45fd77e8b16..bb64f07844b1 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -160,6 +160,7 @@ //! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" #![stable(feature = "rust1", since = "1.0.0")] +#![allow(unsafe_op_in_unsafe_fn)] #[unstable(feature = "c_str_module", issue = "112134")] pub mod c_str; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b464461277a0..d69c98ce79e6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -293,6 +293,7 @@ //! [`Arc`]: crate::sync::Arc #![stable(feature = "rust1", since = "1.0.0")] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 66aeb35aceec..d4d68c2068d8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -252,6 +252,7 @@ #![allow(internal_features)] #![deny(rustc::existing_doc_keyword)] #![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] @@ -664,7 +665,7 @@ pub mod alloc; mod panicking; #[path = "../../backtrace/src/lib.rs"] -#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)] +#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)] mod backtrace_rs; // Re-export macros defined in core. diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 455fdd3c34d7..020a8b324f41 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -2,6 +2,7 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, nonstandard_style, missing_debug_implementations)] +#![allow(unsafe_op_in_unsafe_fn)] pub mod raw; diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 9a38c42f43a0..5cabdc3a9c7e 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -157,6 +157,7 @@ //! [`RwLock`]: crate::sync::RwLock #![stable(feature = "rust1", since = "1.0.0")] +#![allow(unsafe_op_in_unsafe_fn)] #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 4092e6080d54..e50758ce00d8 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,3 +1,5 @@ +#![allow(unsafe_op_in_unsafe_fn)] + /// The PAL (platform abstraction layer) contains platform-specific abstractions /// for implementing the features in the other submodules, e.g. UNIX file /// descriptors. diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 60ee405ecaaa..fc4d5592981f 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -16,6 +16,7 @@ #![allow(missing_docs)] #![allow(missing_debug_implementations)] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; From 87d850dff053fb622e56ec0c865a8462d379e649 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 16:49:02 -0700 Subject: [PATCH 320/361] std: Unsafe-wrap HashMap::get_many_unchecked_mut --- library/std/src/collections/hash/map.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 955f4013ab65..1f6a3e904795 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,5 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] - #[cfg(test)] mod tests; @@ -1020,7 +1018,7 @@ where K: Borrow, Q: Hash + Eq, { - self.base.get_many_unchecked_mut(ks) + unsafe { self.base.get_many_unchecked_mut(ks) } } /// Returns `true` if the map contains a value for the specified key. From ce35265105929ead4a4e8d8c556ee3c00d35bc72 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 16:59:12 -0700 Subject: [PATCH 321/361] std: Unsafe-wrap OSStr{,ing}::from_encoded_bytes_unchecked --- library/std/src/ffi/mod.rs | 1 - library/std/src/ffi/os_str.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index bb64f07844b1..f45fd77e8b16 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -160,7 +160,6 @@ //! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" #![stable(feature = "rust1", since = "1.0.0")] -#![allow(unsafe_op_in_unsafe_fn)] #[unstable(feature = "c_str_module", issue = "112134")] pub mod c_str; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 4a417c84a30a..f9dba08da4c3 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -184,7 +184,7 @@ impl OsString { #[inline] #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self { - OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) } + OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } } } /// Converts to an [`OsStr`] slice. @@ -813,7 +813,7 @@ impl OsStr { #[inline] #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { - Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes)) + Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) }) } #[inline] From 83a0fe53967ef12411cb7f954a7ad52bee20dc56 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 17:07:19 -0700 Subject: [PATCH 322/361] std: Directly call unsafe {un,}setenv in env --- library/std/src/env.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index b47b6531d538..36add02d68c5 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -9,7 +9,6 @@ //! and those without will return a [`String`]. #![stable(feature = "env", since = "1.0.0")] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -367,11 +366,8 @@ impl Error for VarError { #[rustc_deprecated_safe_2024] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { - _set_var(key.as_ref(), value.as_ref()) -} - -unsafe fn _set_var(key: &OsStr, value: &OsStr) { - os_imp::setenv(key, value).unwrap_or_else(|e| { + let (key, value) = (key.as_ref(), value.as_ref()); + unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| { panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") }) } @@ -434,11 +430,8 @@ unsafe fn _set_var(key: &OsStr, value: &OsStr) { #[rustc_deprecated_safe_2024] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { - _remove_var(key.as_ref()) -} - -unsafe fn _remove_var(key: &OsStr) { - os_imp::unsetenv(key) + let key = key.as_ref(); + unsafe { os_imp::unsetenv(key) } .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) } From df353a0cc3eaf66c496e07232ceb06a91fc10e67 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 17:14:55 -0700 Subject: [PATCH 323/361] std: Unsafe-wrap std::io --- library/std/src/io/buffered/bufwriter.rs | 8 +++++--- library/std/src/io/cursor.rs | 2 +- library/std/src/io/error/repr_bitpacked.rs | 7 +++++-- library/std/src/io/mod.rs | 5 ++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 1768bb05ddbc..a8680e9b6ead 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -433,9 +433,11 @@ impl BufWriter { let old_len = self.buf.len(); let buf_len = buf.len(); let src = buf.as_ptr(); - let dst = self.buf.as_mut_ptr().add(old_len); - ptr::copy_nonoverlapping(src, dst, buf_len); - self.buf.set_len(old_len + buf_len); + unsafe { + let dst = self.buf.as_mut_ptr().add(old_len); + ptr::copy_nonoverlapping(src, dst, buf_len); + self.buf.set_len(old_len + buf_len); + } } #[inline] diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index a1a8b2a3505c..2ed64a40495e 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -482,7 +482,7 @@ where A: Allocator, { debug_assert!(vec.capacity() >= pos + buf.len()); - vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()); + unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) }; pos + buf.len() } diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index a5cefe2292be..fbb74967df3f 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -267,11 +267,14 @@ where // Using this rather than unwrap meaningfully improves the code // for callers which only care about one variant (usually // `Custom`) - core::hint::unreachable_unchecked(); + unsafe { core::hint::unreachable_unchecked() }; }); ErrorData::Simple(kind) } - TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()), + TAG_SIMPLE_MESSAGE => { + // SAFETY: per tag + unsafe { ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()) } + } TAG_CUSTOM => { // It would be correct for us to use `ptr::byte_sub` here (see the // comment above the `wrapping_add` call in `new_custom` for why), diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d69c98ce79e6..1345a30361e2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -293,7 +293,6 @@ //! [`Arc`]: crate::sync::Arc #![stable(feature = "rust1", since = "1.0.0")] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -383,11 +382,11 @@ pub(crate) unsafe fn append_to_string(buf: &mut String, f: F) -> Result) -> Result, { - let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; + let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } }; let ret = f(g.buf); // SAFETY: the caller promises to only append data to `buf` - let appended = g.buf.get_unchecked(g.len..); + let appended = unsafe { g.buf.get_unchecked(g.len..) }; if str::from_utf8(appended).is_err() { ret.and_then(|_| Err(Error::INVALID_UTF8)) } else { From 64fb2366dacfcd187ce437e637e237ce39d9073c Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 17:39:40 -0700 Subject: [PATCH 324/361] std: Unsafe-wrap in Wtf8 impl --- library/std/src/sys_common/mod.rs | 1 - library/std/src/sys_common/wtf8.rs | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index fc4d5592981f..60ee405ecaaa 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -16,7 +16,6 @@ #![allow(missing_docs)] #![allow(missing_debug_implementations)] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 117a3e23044e..6aeeb6259285 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -602,7 +602,8 @@ impl Wtf8 { /// marked unsafe. #[inline] pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - mem::transmute(value) + // SAFETY: start with &[u8], end with fancy &[u8] + unsafe { &*(value as *const [u8] as *const Wtf8) } } /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. @@ -611,7 +612,8 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - mem::transmute(value) + // SAFETY: start with &mut [u8], end with fancy &mut [u8] + unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } } /// Returns the length, in WTF-8 bytes. @@ -942,8 +944,12 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { /// Copied from core::str::raw::slice_unchecked #[inline] pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // memory layout of a &[u8] and &Wtf8 are the same - Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin)) + // SAFETY: memory layout of a &[u8] and &Wtf8 are the same + unsafe { + let len = end - begin; + let start = s.as_bytes().as_ptr().add(begin); + Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) + } } /// Copied from core::str::raw::slice_error_fail From e32460276cb146b665c0c18b50bf6ea7764c693b Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 14 Jul 2024 17:59:37 -0700 Subject: [PATCH 325/361] std: Unsafe-wrap std::sync --- library/std/src/sync/mod.rs | 1 - library/std/src/sync/mpmc/array.rs | 22 +++++++++------- library/std/src/sync/mpmc/counter.rs | 4 +-- library/std/src/sync/mpmc/list.rs | 36 ++++++++++++++------------ library/std/src/sync/mpmc/zero.rs | 20 ++++++++------ library/std/src/sync/once_lock.rs | 4 +-- library/std/src/sync/reentrant_lock.rs | 4 ++- library/std/src/sync/rwlock.rs | 2 +- 8 files changed, 53 insertions(+), 40 deletions(-) diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 5cabdc3a9c7e..9a38c42f43a0 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -157,7 +157,6 @@ //! [`RwLock`]: crate::sync::RwLock #![stable(feature = "rust1", since = "1.0.0")] -#![allow(unsafe_op_in_unsafe_fn)] #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 492e21d9bdb6..185319add745 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -200,11 +200,12 @@ impl Channel { return Err(msg); } - let slot: &Slot = &*(token.array.slot as *const Slot); - // Write the message into the slot and update the stamp. - slot.msg.get().write(MaybeUninit::new(msg)); - slot.stamp.store(token.array.stamp, Ordering::Release); + unsafe { + let slot: &Slot = &*(token.array.slot as *const Slot); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.stamp.store(token.array.stamp, Ordering::Release); + } // Wake a sleeping receiver. self.receivers.notify(); @@ -291,11 +292,14 @@ impl Channel { return Err(()); } - let slot: &Slot = &*(token.array.slot as *const Slot); - // Read the message from the slot and update the stamp. - let msg = slot.msg.get().read().assume_init(); - slot.stamp.store(token.array.stamp, Ordering::Release); + let msg = unsafe { + let slot: &Slot = &*(token.array.slot as *const Slot); + + let msg = slot.msg.get().read().assume_init(); + slot.stamp.store(token.array.stamp, Ordering::Release); + msg + }; // Wake a sleeping sender. self.senders.notify(); @@ -471,7 +475,7 @@ impl Channel { false }; - self.discard_all_messages(tail); + unsafe { self.discard_all_messages(tail) }; disconnected } diff --git a/library/std/src/sync/mpmc/counter.rs b/library/std/src/sync/mpmc/counter.rs index a5a6bdc67f13..3478cf41dc9d 100644 --- a/library/std/src/sync/mpmc/counter.rs +++ b/library/std/src/sync/mpmc/counter.rs @@ -63,7 +63,7 @@ impl Sender { disconnect(&self.counter().chan); if self.counter().destroy.swap(true, Ordering::AcqRel) { - drop(Box::from_raw(self.counter)); + drop(unsafe { Box::from_raw(self.counter) }); } } } @@ -116,7 +116,7 @@ impl Receiver { disconnect(&self.counter().chan); if self.counter().destroy.swap(true, Ordering::AcqRel) { - drop(Box::from_raw(self.counter)); + drop(unsafe { Box::from_raw(self.counter) }); } } } diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 9e7148c716cd..edac7a0cb183 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -91,7 +91,7 @@ impl Block { // It is not necessary to set the `DESTROY` bit in the last slot because that slot has // begun destruction of the block. for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); + let slot = unsafe { (*this).slots.get_unchecked(i) }; // Mark the `DESTROY` bit if a thread is still using the slot. if slot.state.load(Ordering::Acquire) & READ == 0 @@ -103,7 +103,7 @@ impl Block { } // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); + drop(unsafe { Box::from_raw(this) }); } } @@ -265,9 +265,11 @@ impl Channel { // Write the message into the slot. let block = token.list.block as *mut Block; let offset = token.list.offset; - let slot = (*block).slots.get_unchecked(offset); - slot.msg.get().write(MaybeUninit::new(msg)); - slot.state.fetch_or(WRITE, Ordering::Release); + unsafe { + let slot = (*block).slots.get_unchecked(offset); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.state.fetch_or(WRITE, Ordering::Release); + } // Wake a sleeping receiver. self.receivers.notify(); @@ -369,19 +371,21 @@ impl Channel { // Read the message. let block = token.list.block as *mut Block; let offset = token.list.offset; - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let msg = slot.msg.get().read().assume_init(); + unsafe { + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let msg = slot.msg.get().read().assume_init(); - // Destroy the block if we've reached the end, or if another thread wanted to destroy but - // couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); + // Destroy the block if we've reached the end, or if another thread wanted to destroy but + // couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + Ok(msg) } - - Ok(msg) } /// Attempts to send a message into the channel. diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 1b82713edc74..6d1c9d64e7a7 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -103,9 +103,11 @@ impl Channel { return Err(msg); } - let packet = &*(token.zero.0 as *const Packet); - packet.msg.get().write(Some(msg)); - packet.ready.store(true, Ordering::Release); + unsafe { + let packet = &*(token.zero.0 as *const Packet); + packet.msg.get().write(Some(msg)); + packet.ready.store(true, Ordering::Release); + } Ok(()) } @@ -116,22 +118,24 @@ impl Channel { return Err(()); } - let packet = &*(token.zero.0 as *const Packet); + let packet = unsafe { &*(token.zero.0 as *const Packet) }; if packet.on_stack { // The message has been in the packet from the beginning, so there is no need to wait // for it. However, after reading the message, we need to set `ready` to `true` in // order to signal that the packet can be destroyed. - let msg = packet.msg.get().replace(None).unwrap(); + let msg = unsafe { packet.msg.get().replace(None) }.unwrap(); packet.ready.store(true, Ordering::Release); Ok(msg) } else { // Wait until the message becomes available, then read it and destroy the // heap-allocated packet. packet.wait_ready(); - let msg = packet.msg.get().replace(None).unwrap(); - drop(Box::from_raw(token.zero.0 as *mut Packet)); - Ok(msg) + unsafe { + let msg = packet.msg.get().replace(None).unwrap(); + drop(Box::from_raw(token.zero.0 as *mut Packet)); + Ok(msg) + } } } diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index fe243550606f..94955beaf37b 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -502,7 +502,7 @@ impl OnceLock { #[inline] unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); - (&*self.value.get()).assume_init_ref() + unsafe { (&*self.value.get()).assume_init_ref() } } /// # Safety @@ -511,7 +511,7 @@ impl OnceLock { #[inline] unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); - (&mut *self.value.get()).assume_init_mut() + unsafe { (&mut *self.value.get()).assume_init_mut() } } } diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index f7fe8eb1c7fd..042c439394e0 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -244,7 +244,9 @@ impl ReentrantLock { } unsafe fn increment_lock_count(&self) -> Option<()> { - *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; + unsafe { + *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; + } Some(()) } } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index e0a8a7603d71..a4ec52a4abe6 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -578,7 +578,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { // successfully called from the same thread before instantiating this object. unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { - data: NonNull::new_unchecked(lock.data.get()), + data: unsafe { NonNull::new_unchecked(lock.data.get()) }, inner_lock: &lock.inner, }) } From 1d1cae1ba5f5ba41084c717fd38fdd25f3b06b64 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:28:27 +0000 Subject: [PATCH 326/361] Remove NonZeroDWORD --- library/std/src/sys/pal/windows/c.rs | 2 -- library/std/src/sys/pal/windows/process.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 7dfda4f714c7..1c27f6246468 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -7,7 +7,6 @@ use crate::ffi::CStr; use crate::mem; -use crate::num::NonZero; pub use crate::os::raw::c_int; use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; @@ -19,7 +18,6 @@ mod windows_sys; pub use windows_sys::*; pub type DWORD = c_ulong; -pub type NonZeroDWORD = NonZero; pub type LARGE_INTEGER = c_longlong; #[cfg_attr(target_vendor = "uwp", allow(unused))] pub type LONG = c_long; diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index c62764696b86..4b4856d870d2 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -19,7 +19,7 @@ use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Mutex; use crate::sys::args::{self, Arg}; -use crate::sys::c::{self, NonZeroDWORD, EXIT_FAILURE, EXIT_SUCCESS}; +use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::cvt; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; @@ -717,7 +717,7 @@ pub struct ExitStatus(c::DWORD); impl ExitStatus { pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - match NonZeroDWORD::try_from(self.0) { + match NonZero::::try_from(self.0) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), } @@ -750,7 +750,7 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatusError(c::NonZeroDWORD); +pub struct ExitStatusError(NonZero); impl Into for ExitStatusError { fn into(self) -> ExitStatus { From 91ba4ebcfdaf6e12bbb04649cadb3e3e83604e0f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:32:22 +0000 Subject: [PATCH 327/361] Remove LARGE_INTEGER --- library/std/src/sys/pal/windows/c.rs | 11 +++++------ library/std/src/sys/pal/windows/fs.rs | 10 +++++----- library/std/src/sys/pal/windows/time.rs | 10 +++++----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 1c27f6246468..c85cc62fde76 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -8,7 +8,7 @@ use crate::ffi::CStr; use crate::mem; pub use crate::os::raw::c_int; -use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_char, c_long, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; @@ -18,7 +18,6 @@ mod windows_sys; pub use windows_sys::*; pub type DWORD = c_ulong; -pub type LARGE_INTEGER = c_longlong; #[cfg_attr(target_vendor = "uwp", allow(unused))] pub type LONG = c_long; pub type UINT = c_uint; @@ -270,7 +269,7 @@ pub unsafe fn NtReadFile( iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, + byteoffset: Option<&i64>, key: Option<&ULONG>, ) -> NTSTATUS { windows_sys::NtReadFile( @@ -293,7 +292,7 @@ pub unsafe fn NtWriteFile( iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, + byteoffset: Option<&i64>, key: Option<&ULONG>, ) -> NTSTATUS { windows_sys::NtWriteFile( @@ -452,7 +451,7 @@ compat_fn_with_fallback! { iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, + byteoffset: Option<&i64>, key: Option<&ULONG> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED @@ -466,7 +465,7 @@ compat_fn_with_fallback! { iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, + byteoffset: Option<&i64>, key: Option<&ULONG> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index cc68f5ef5f08..086768773150 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -495,7 +495,7 @@ impl File { SeekFrom::End(n) => (c::FILE_END, n), SeekFrom::Current(n) => (c::FILE_CURRENT, n), }; - let pos = pos as c::LARGE_INTEGER; + let pos = pos as i64; let mut newpos = 0; cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?; Ok(newpos as u64) @@ -1417,10 +1417,10 @@ pub fn canonicalize(p: &Path) -> io::Result { pub fn copy(from: &Path, to: &Path) -> io::Result { unsafe extern "system" fn callback( - _TotalFileSize: c::LARGE_INTEGER, - _TotalBytesTransferred: c::LARGE_INTEGER, - _StreamSize: c::LARGE_INTEGER, - StreamBytesTransferred: c::LARGE_INTEGER, + _TotalFileSize: i64, + _TotalBytesTransferred: i64, + _StreamSize: i64, + StreamBytesTransferred: i64, dwStreamNumber: c::DWORD, _dwCallbackReason: c::DWORD, _hSourceFile: c::HANDLE, diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 09e78a29304f..bf299a9b7d2e 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -172,7 +172,7 @@ mod perf_counter { use crate::time::Duration; pub struct PerformanceCounterInstant { - ts: c::LARGE_INTEGER, + ts: i64, } impl PerformanceCounterInstant { pub fn now() -> Self { @@ -196,7 +196,7 @@ mod perf_counter { } } - fn frequency() -> c::LARGE_INTEGER { + fn frequency() -> i64 { // Either the cached result of `QueryPerformanceFrequency` or `0` for // uninitialized. Storing this as a single `AtomicU64` allows us to use // `Relaxed` operations, as we are only interested in the effects on a @@ -206,7 +206,7 @@ mod perf_counter { let cached = FREQUENCY.load(Ordering::Relaxed); // If a previous thread has filled in this global state, use that. if cached != 0 { - return cached as c::LARGE_INTEGER; + return cached as i64; } // ... otherwise learn for ourselves ... let mut frequency = 0; @@ -218,8 +218,8 @@ mod perf_counter { frequency } - fn query() -> c::LARGE_INTEGER { - let mut qpc_value: c::LARGE_INTEGER = 0; + fn query() -> i64 { + let mut qpc_value: i64 = 0; cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap(); qpc_value } From 65da4af0be038d9f73d36515d1ce5d83c0fb96e2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:43:43 +0000 Subject: [PATCH 328/361] Remove LONG --- library/std/src/sys/pal/windows/c.rs | 4 +--- library/std/src/sys/pal/windows/stack_overflow.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index c85cc62fde76..315bffa220e5 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -8,7 +8,7 @@ use crate::ffi::CStr; use crate::mem; pub use crate::os::raw::c_int; -use crate::os::raw::{c_char, c_long, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_char, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; @@ -18,8 +18,6 @@ mod windows_sys; pub use windows_sys::*; pub type DWORD = c_ulong; -#[cfg_attr(target_vendor = "uwp", allow(unused))] -pub type LONG = c_long; pub type UINT = c_uint; pub type WCHAR = u16; pub type USHORT = c_ushort; diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index f93f31026f81..59feb0c601ac 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -11,7 +11,7 @@ pub unsafe fn reserve_stack() { debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); } -unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG { +unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 { unsafe { let rec = &(*(*ExceptionInfo).ExceptionRecord); let code = rec.ExceptionCode; From b107cfa73cf70d391a14ca5de696b679ef8c2081 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:44:48 +0000 Subject: [PATCH 329/361] Remove UINT --- library/std/src/sys/pal/windows/c.rs | 1 - library/std/src/sys/pal/windows/os.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 315bffa220e5..da96858d6869 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -18,7 +18,6 @@ mod windows_sys; pub use windows_sys::*; pub type DWORD = c_ulong; -pub type UINT = c_uint; pub type WCHAR = u16; pub type USHORT = c_ushort; pub type SIZE_T = usize; diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 62199c16bfed..542fabcb6655 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -383,7 +383,7 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { - unsafe { c::ExitProcess(code as c::UINT) } + unsafe { c::ExitProcess(code as u32) } } pub fn getpid() -> u32 { From e70cc288311e907f721e5dff9201be18c4e42640 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:45:15 +0000 Subject: [PATCH 330/361] Remove LPWSTR --- library/std/src/sys/pal/windows/c.rs | 2 -- library/std/src/sys/pal/windows/os.rs | 4 ++-- library/std/src/sys/pal/windows/stdio.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index da96858d6869..97fec6e59f0b 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -28,8 +28,6 @@ pub type LPCVOID = *const c_void; pub type LPOVERLAPPED = *mut OVERLAPPED; pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPVOID = *mut c_void; -pub type LPWCH = *mut WCHAR; -pub type LPWSTR = *mut WCHAR; #[cfg(target_vendor = "win7")] pub type PSRWLOCK = *mut SRWLOCK; diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 542fabcb6655..ed7911b99cbd 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -81,7 +81,7 @@ pub fn error_string(mut errnum: i32) -> String { } pub struct Env { - base: c::LPWCH, + base: *mut c::WCHAR, iter: EnvIterator, } @@ -126,7 +126,7 @@ impl Iterator for Env { } #[derive(Clone)] -struct EnvIterator(c::LPWCH); +struct EnvIterator(*mut c::WCHAR); impl Iterator for EnvIterator { type Item = (OsString, OsString); diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 10aeeac07ea2..995be689b467 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -182,12 +182,12 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result Date: Sun, 14 Jul 2024 06:53:28 +0000 Subject: [PATCH 331/361] Remove USHORT We stick to C types in for socket and address as these are at least nominally BSD-ish and they're used outside of pal/windows in general *nix code --- library/std/src/sys/pal/windows/c.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 97fec6e59f0b..20f1ff84b7b5 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -19,7 +19,6 @@ pub use windows_sys::*; pub type DWORD = c_ulong; pub type WCHAR = u16; -pub type USHORT = c_ushort; pub type SIZE_T = usize; pub type CHAR = c_char; pub type ULONG = c_ulong; @@ -33,7 +32,7 @@ pub type LPVOID = *mut c_void; pub type PSRWLOCK = *mut SRWLOCK; pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = USHORT; +pub type ADDRESS_FAMILY = c_ushort; pub use FD_SET as fd_set; pub use LINGER as linger; pub use TIMEVAL as timeval; @@ -152,7 +151,7 @@ pub struct SOCKADDR_STORAGE_LH { #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_family: ADDRESS_FAMILY, - pub sin_port: USHORT, + pub sin_port: c_ushort, pub sin_addr: in_addr, pub sin_zero: [CHAR; 8], } @@ -161,7 +160,7 @@ pub struct sockaddr_in { #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: USHORT, + pub sin6_port: c_ushort, pub sin6_flowinfo: c_ulong, pub sin6_addr: in6_addr, pub sin6_scope_id: c_ulong, From 5b700a76cf1c1d815f0082f7ea12c5f8c5a45114 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:59:05 +0000 Subject: [PATCH 332/361] Remove CHAR As with USHORT, keep using C types for BSD socket APIs. --- library/std/src/sys/pal/windows/c.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 20f1ff84b7b5..f38cf0e2ac77 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -20,7 +20,6 @@ pub use windows_sys::*; pub type DWORD = c_ulong; pub type WCHAR = u16; pub type SIZE_T = usize; -pub type CHAR = c_char; pub type ULONG = c_ulong; pub type LPCVOID = *const c_void; @@ -142,9 +141,9 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [CHAR; 6], + pub __ss_pad1: [c_char; 6], pub __ss_align: i64, - pub __ss_pad2: [CHAR; 112], + pub __ss_pad2: [c_char; 112], } #[repr(C)] @@ -153,7 +152,7 @@ pub struct sockaddr_in { pub sin_family: ADDRESS_FAMILY, pub sin_port: c_ushort, pub sin_addr: in_addr, - pub sin_zero: [CHAR; 8], + pub sin_zero: [c_char; 8], } #[repr(C)] From 286c3270b472c9ffed5d019f5d2b4073025701be Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 06:59:28 +0000 Subject: [PATCH 333/361] Remove SIZE_T --- library/std/src/sys/pal/windows/alloc.rs | 4 ++-- library/std/src/sys/pal/windows/c.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index e6cbdb6ef7d6..c2fb0c2b8764 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -114,7 +114,7 @@ fn init_or_get_process_heap() -> c::HANDLE { extern "C" fn process_heap_init_and_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` flags: c::DWORD, - dwBytes: c::SIZE_T, + dwBytes: usize, ) -> c::LPVOID { let heap = init_or_get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { @@ -128,7 +128,7 @@ extern "C" fn process_heap_init_and_alloc( fn process_heap_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, flags: c::DWORD, - dwBytes: c::SIZE_T, + dwBytes: usize, ) -> c::LPVOID { let heap = HEAP.load(Ordering::Relaxed); if core::intrinsics::likely(!heap.is_null()) { diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index f38cf0e2ac77..a771a77d077c 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -19,7 +19,6 @@ pub use windows_sys::*; pub type DWORD = c_ulong; pub type WCHAR = u16; -pub type SIZE_T = usize; pub type ULONG = c_ulong; pub type LPCVOID = *const c_void; From 8052fb8f3c38eda84a239022d391a0a943261ed3 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:05:45 +0000 Subject: [PATCH 334/361] Remove LPCVOID --- library/std/src/sys/pal/windows/c.rs | 1 - library/std/src/sys/pal/windows/fs.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index a771a77d077c..801970f93fff 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -21,7 +21,6 @@ pub type DWORD = c_ulong; pub type WCHAR = u16; pub type ULONG = c_ulong; -pub type LPCVOID = *const c_void; pub type LPOVERLAPPED = *mut OVERLAPPED; pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPVOID = *mut c_void; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 086768773150..e7648fb2e5a5 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1425,7 +1425,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { _dwCallbackReason: c::DWORD, _hSourceFile: c::HANDLE, _hDestinationFile: c::HANDLE, - lpData: c::LPCVOID, + lpData: *const c_void, ) -> c::DWORD { if dwStreamNumber == 1 { *(lpData as *mut i64) = StreamBytesTransferred; From 1b7cf3a3f2c99722972747b1f6003a8c151c81c9 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:10:00 +0000 Subject: [PATCH 335/361] Remove LPOVERLAPPED --- library/std/src/sys/pal/windows/c.rs | 1 - library/std/src/sys/pal/windows/pipe.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 801970f93fff..d118e430ab29 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -21,7 +21,6 @@ pub type DWORD = c_ulong; pub type WCHAR = u16; pub type ULONG = c_ulong; -pub type LPOVERLAPPED = *mut OVERLAPPED; pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPVOID = *mut c_void; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 67ef3ca82da0..408653f538f6 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -227,7 +227,7 @@ type AlertableIoFn = unsafe extern "system" fn( BorrowedHandle<'_>, c::LPVOID, c::DWORD, - c::LPOVERLAPPED, + *mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE, ) -> c::BOOL; From 351f1f36f696b14b84ac784ee5a6b3a7879699cc Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:12:32 +0000 Subject: [PATCH 336/361] Remove LPSECURITY_ATTRIBUTES --- library/std/src/sys/pal/windows/c.rs | 1 - library/std/src/sys/pal/windows/fs.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index d118e430ab29..48d46296d98f 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -21,7 +21,6 @@ pub type DWORD = c_ulong; pub type WCHAR = u16; pub type ULONG = c_ulong; -pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPVOID = *mut c_void; #[cfg(target_vendor = "win7")] diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index e7648fb2e5a5..2c4380e1446f 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -79,7 +79,7 @@ pub struct OpenOptions { attributes: c::DWORD, share_mode: c::DWORD, security_qos_flags: c::DWORD, - security_attributes: c::LPSECURITY_ATTRIBUTES, + security_attributes: *mut c::SECURITY_ATTRIBUTES, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -241,7 +241,7 @@ impl OpenOptions { // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on. self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT; } - pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) { + pub fn security_attributes(&mut self, attrs: *mut c::SECURITY_ATTRIBUTES) { self.security_attributes = attrs; } From 84dd7e4959bd1cadb67989f7a3234a46bcda2faf Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:19:57 +0000 Subject: [PATCH 337/361] Remove LPVOID --- library/std/src/sys/pal/windows/alloc.rs | 8 ++++---- library/std/src/sys/pal/windows/c.rs | 8 +++----- library/std/src/sys/pal/windows/pipe.rs | 4 ++-- library/std/src/sys/pal/windows/stdio.rs | 2 +- library/std/src/sys/sync/thread_parking/windows.rs | 9 +++++---- library/std/src/sys/thread_local/guard/windows.rs | 5 +++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index c2fb0c2b8764..f85d29c00a9a 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -115,7 +115,7 @@ extern "C" fn process_heap_init_and_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` flags: c::DWORD, dwBytes: usize, -) -> c::LPVOID { +) -> *mut c_void { let heap = init_or_get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { return ptr::null_mut(); @@ -129,7 +129,7 @@ fn process_heap_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, flags: c::DWORD, dwBytes: usize, -) -> c::LPVOID { +) -> *mut c_void { let heap = HEAP.load(Ordering::Relaxed); if core::intrinsics::likely(!heap.is_null()) { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. @@ -240,7 +240,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `block` is a pointer to the start of an allocated block. - unsafe { HeapFree(heap, 0, block as c::LPVOID) }; + unsafe { HeapFree(heap, 0, block.cast::()) }; } #[inline] @@ -253,7 +253,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `ptr` is a pointer to the start of an allocated block. // The returned pointer points to the start of an allocated block. - unsafe { HeapReAlloc(heap, 0, ptr as c::LPVOID, new_size) as *mut u8 } + unsafe { HeapReAlloc(heap, 0, ptr.cast::(), new_size).cast::() } } else { // SAFETY: `realloc_fallback` is implemented using `dealloc` and `alloc`, which will // correctly handle `ptr` and return a pointer satisfying the guarantees of `System` diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 48d46296d98f..e284804c2c8d 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -21,8 +21,6 @@ pub type DWORD = c_ulong; pub type WCHAR = u16; pub type ULONG = c_ulong; -pub type LPVOID = *mut c_void; - #[cfg(target_vendor = "win7")] pub type PSRWLOCK = *mut SRWLOCK; @@ -390,7 +388,7 @@ compat_fn_with_fallback! { pub fn NtCreateKeyedEvent( KeyedEventHandle: *mut HANDLE, DesiredAccess: DWORD, - ObjectAttributes: LPVOID, + ObjectAttributes: *mut c_void, Flags: ULONG ) -> NTSTATUS { panic!("keyed events not available") @@ -398,7 +396,7 @@ compat_fn_with_fallback! { #[cfg(target_vendor = "win7")] pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, - Key: LPVOID, + Key: *mut c_void, Alertable: BOOLEAN, Timeout: *mut c_longlong ) -> NTSTATUS { @@ -407,7 +405,7 @@ compat_fn_with_fallback! { #[cfg(target_vendor = "win7")] pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, - Key: LPVOID, + Key: *mut c_void, Alertable: BOOLEAN, Timeout: *mut c_longlong ) -> NTSTATUS { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 408653f538f6..031660335483 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -225,7 +225,7 @@ fn random_number() -> usize { // Abstracts over `ReadFileEx` and `WriteFileEx` type AlertableIoFn = unsafe extern "system" fn( BorrowedHandle<'_>, - c::LPVOID, + *mut core::ffi::c_void, c::DWORD, *mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE, @@ -327,7 +327,7 @@ impl AnonPipe { unsafe fn alertable_io_internal( &self, io: AlertableIoFn, - buf: c::LPVOID, + buf: *mut core::ffi::c_void, len: c::DWORD, ) -> io::Result { // Use "alertable I/O" to synchronize the pipe I/O. diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 995be689b467..07686ab29333 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -355,7 +355,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::ResultEMPTY but leave PARKED alone. if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { // Actually woken up by unpark(). @@ -144,7 +145,7 @@ impl Parker { } // Wait for something to happen, assuming it's still set to PARKED. - c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as *const c_void, 1, dur2timeout(timeout)); // Set the state back to EMPTY (from either PARKED or NOTIFIED). // Note that we don't just write EMPTY, but use swap() to also // include an acquire-ordered read to synchronize with unpark()'s @@ -177,8 +178,8 @@ impl Parker { } } - fn ptr(&self) -> c::LPVOID { - core::ptr::addr_of!(self.state) as c::LPVOID + fn ptr(&self) -> *const c_void { + core::ptr::addr_of!(self.state).cast::() } } diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index 81797f55170d..c35b717fe75d 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -65,6 +65,7 @@ use crate::ptr; use crate::sys::c; +use core::ffi::c_void; pub fn enable() { // When destructors are used, we don't want LLVM eliminating CALLBACK for any @@ -74,9 +75,9 @@ pub fn enable() { #[link_section = ".CRT$XLB"] #[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section` -pub static CALLBACK: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = tls_callback; +pub static CALLBACK: unsafe extern "system" fn(*mut c_void, c::DWORD, *mut c_void) = tls_callback; -unsafe extern "system" fn tls_callback(_h: c::LPVOID, dw_reason: c::DWORD, _pv: c::LPVOID) { +unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: c::DWORD, _pv: *mut c_void) { // See comments above for what this is doing. Note that we don't need this // trickery on GNU windows, just on MSVC. #[cfg(all(target_env = "msvc", not(target_thread_local)))] From 21f69b5b8236a3297c8000253dbe995b04b6c966 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:26:18 +0000 Subject: [PATCH 338/361] Remove PSRWLOCK --- library/std/src/sys/pal/windows/c.rs | 3 --- library/std/src/sys/sync/mutex/windows7.rs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index e284804c2c8d..83b87f47a8be 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -21,9 +21,6 @@ pub type DWORD = c_ulong; pub type WCHAR = u16; pub type ULONG = c_ulong; -#[cfg(target_vendor = "win7")] -pub type PSRWLOCK = *mut SRWLOCK; - pub type socklen_t = c_int; pub type ADDRESS_FAMILY = c_ushort; pub use FD_SET as fd_set; diff --git a/library/std/src/sys/sync/mutex/windows7.rs b/library/std/src/sys/sync/mutex/windows7.rs index ef2f84082cd5..689dba10f01e 100644 --- a/library/std/src/sys/sync/mutex/windows7.rs +++ b/library/std/src/sys/sync/mutex/windows7.rs @@ -25,7 +25,7 @@ unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} #[inline] -pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { +pub unsafe fn raw(m: &Mutex) -> *mut c::SRWLOCK { m.srwlock.get() } From d8d7c5c3b96b386403c094946fa5d0a8cef3b666 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:40:57 +0000 Subject: [PATCH 339/361] Remove ULONG --- library/std/src/sys/pal/windows/c.rs | 9 ++++----- library/std/src/sys/pal/windows/io.rs | 12 ++++++------ library/std/src/sys/pal/windows/rand.rs | 2 +- library/std/src/sys/pal/windows/stdio.rs | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 83b87f47a8be..9f189452ecc8 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -19,7 +19,6 @@ pub use windows_sys::*; pub type DWORD = c_ulong; pub type WCHAR = u16; -pub type ULONG = c_ulong; pub type socklen_t = c_int; pub type ADDRESS_FAMILY = c_ushort; @@ -252,9 +251,9 @@ pub unsafe fn NtReadFile( apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, - length: ULONG, + length: u32, byteoffset: Option<&i64>, - key: Option<&ULONG>, + key: Option<&u32>, ) -> NTSTATUS { windows_sys::NtReadFile( filehandle.as_raw_handle(), @@ -275,9 +274,9 @@ pub unsafe fn NtWriteFile( apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, - length: ULONG, + length: u32, byteoffset: Option<&i64>, - key: Option<&ULONG>, + key: Option<&u32>, ) -> NTSTATUS { windows_sys::NtWriteFile( filehandle.as_raw_handle(), diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 77b8f3c410eb..1d0707926c92 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -15,9 +15,9 @@ pub struct IoSlice<'a> { impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); + assert!(buf.len() <= u32::MAX as usize); IoSlice { - vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_ptr() as *mut u8 }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, _p: PhantomData, } } @@ -29,7 +29,7 @@ impl<'a> IoSlice<'a> { } unsafe { - self.vec.len -= n as c::ULONG; + self.vec.len -= n as u32; self.vec.buf = self.vec.buf.add(n); } } @@ -49,9 +49,9 @@ pub struct IoSliceMut<'a> { impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); + assert!(buf.len() <= u32::MAX as usize); IoSliceMut { - vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, _p: PhantomData, } } @@ -63,7 +63,7 @@ impl<'a> IoSliceMut<'a> { } unsafe { - self.vec.len -= n as c::ULONG; + self.vec.len -= n as u32; self.vec.buf = self.vec.buf.add(n); } } diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs index 09f527a09bf1..e366bb995626 100644 --- a/library/std/src/sys/pal/windows/rand.rs +++ b/library/std/src/sys/pal/windows/rand.rs @@ -20,7 +20,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { - c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as c::ULONG) + c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as u32) }; if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) } diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 07686ab29333..831efb252c47 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -341,9 +341,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result() as c::ULONG, + nLength: crate::mem::size_of::() as u32, nInitialChars: 0, dwCtrlWakeupMask: CTRL_Z_MASK, dwControlKeyState: 0, From e2b062c9b5ffbb2a57688cfa6efd9843ad70c454 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 07:41:14 +0000 Subject: [PATCH 340/361] Remove DWORD --- library/std/src/process/tests.rs | 22 +++---- library/std/src/sys/pal/windows/alloc.rs | 6 +- library/std/src/sys/pal/windows/c.rs | 17 +++--- library/std/src/sys/pal/windows/fs.rs | 57 +++++++++---------- library/std/src/sys/pal/windows/handle.rs | 13 ++--- library/std/src/sys/pal/windows/mod.rs | 14 ++--- library/std/src/sys/pal/windows/net.rs | 6 +- library/std/src/sys/pal/windows/os.rs | 4 +- library/std/src/sys/pal/windows/pipe.rs | 12 ++-- library/std/src/sys/pal/windows/process.rs | 22 +++---- library/std/src/sys/pal/windows/stdio.rs | 8 +-- library/std/src/sys/pal/windows/thread.rs | 2 +- library/std/src/sys/pal/windows/time.rs | 4 +- .../std/src/sys/thread_local/guard/windows.rs | 4 +- .../std/src/sys/thread_local/key/windows.rs | 4 +- 15 files changed, 90 insertions(+), 105 deletions(-) diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index b4f6bb71c79c..055601d03079 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -385,29 +385,25 @@ fn test_interior_nul_in_env_value_is_error() { #[cfg(windows)] fn test_creation_flags() { use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, DWORD, INFINITE}; + use crate::sys::c::{BOOL, INFINITE}; #[repr(C)] struct DEBUG_EVENT { - pub event_code: DWORD, - pub process_id: DWORD, - pub thread_id: DWORD, + pub event_code: u32, + pub process_id: u32, + pub thread_id: u32, // This is a union in the real struct, but we don't // need this data for the purposes of this test. pub _junk: [u8; 164], } extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent( - dwProcessId: DWORD, - dwThreadId: DWORD, - dwContinueStatus: DWORD, - ) -> BOOL; + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL; + fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL; } - const DEBUG_PROCESS: DWORD = 1; - const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; - const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + const DEBUG_PROCESS: u32 = 1; + const EXIT_PROCESS_DEBUG_EVENT: u32 = 5; + const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; let mut child = Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap(); diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index f85d29c00a9a..9f0194492b0a 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -15,7 +15,7 @@ mod tests; // See https://docs.microsoft.com/windows/win32/api/heapapi/ // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed. -const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008; +const HEAP_ZERO_MEMORY: u32 = 0x00000008; // Get a handle to the default heap of the current process, or null if the operation fails. // @@ -113,7 +113,7 @@ fn init_or_get_process_heap() -> c::HANDLE { #[cold] extern "C" fn process_heap_init_and_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` - flags: c::DWORD, + flags: u32, dwBytes: usize, ) -> *mut c_void { let heap = init_or_get_process_heap(); @@ -127,7 +127,7 @@ extern "C" fn process_heap_init_and_alloc( #[inline(never)] fn process_heap_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, - flags: c::DWORD, + flags: u32, dwBytes: usize, ) -> *mut c_void { let heap = HEAP.load(Ordering::Relaxed); diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 9f189452ecc8..0197be5be3af 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -17,7 +17,6 @@ pub(super) mod windows_targets; mod windows_sys; pub use windows_sys::*; -pub type DWORD = c_ulong; pub type WCHAR = u16; pub type socklen_t = c_int; @@ -316,13 +315,13 @@ compat_fn_with_fallback! { // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } // >= Win8 / Server 2012 @@ -383,9 +382,9 @@ compat_fn_with_fallback! { #[cfg(target_vendor = "win7")] pub fn NtCreateKeyedEvent( KeyedEventHandle: *mut HANDLE, - DesiredAccess: DWORD, + DesiredAccess: u32, ObjectAttributes: *mut c_void, - Flags: ULONG + Flags: u32 ) -> NTSTATUS { panic!("keyed events not available") } @@ -433,9 +432,9 @@ compat_fn_with_fallback! { apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, - length: ULONG, + length: u32, byteoffset: Option<&i64>, - key: Option<&ULONG> + key: Option<&u32> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } @@ -447,9 +446,9 @@ compat_fn_with_fallback! { apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, - length: ULONG, + length: u32, byteoffset: Option<&i64>, - key: Option<&ULONG> + key: Option<&u32> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 2c4380e1446f..f47e0a173349 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -28,12 +28,12 @@ pub struct File { #[derive(Clone)] pub struct FileAttr { - attributes: c::DWORD, + attributes: u32, creation_time: c::FILETIME, last_access_time: c::FILETIME, last_write_time: c::FILETIME, file_size: u64, - reparse_tag: c::DWORD, + reparse_tag: u32, volume_serial_number: Option, number_of_links: Option, file_index: Option, @@ -41,8 +41,8 @@ pub struct FileAttr { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType { - attributes: c::DWORD, - reparse_tag: c::DWORD, + attributes: u32, + reparse_tag: u32, } pub struct ReadDir { @@ -75,16 +75,16 @@ pub struct OpenOptions { create_new: bool, // system-specific custom_flags: u32, - access_mode: Option, - attributes: c::DWORD, - share_mode: c::DWORD, - security_qos_flags: c::DWORD, + access_mode: Option, + attributes: u32, + share_mode: u32, + security_qos_flags: u32, security_attributes: *mut c::SECURITY_ATTRIBUTES, } #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { - attrs: c::DWORD, + attrs: u32, } #[derive(Copy, Clone, Debug, Default)] @@ -245,7 +245,7 @@ impl OpenOptions { self.security_attributes = attrs; } - fn get_access_mode(&self) -> io::Result { + fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append, self.access_mode) { (.., Some(mode)) => Ok(mode), (true, false, false, None) => Ok(c::GENERIC_READ), @@ -261,7 +261,7 @@ impl OpenOptions { } } - fn get_creation_mode(&self) -> io::Result { + fn get_creation_mode(&self) -> io::Result { match (self.write, self.append) { (true, false) => {} (false, false) => { @@ -287,7 +287,7 @@ impl OpenOptions { }) } - fn get_flags_and_attributes(&self) -> c::DWORD { + fn get_flags_and_attributes(&self) -> u32 { self.custom_flags | self.attributes | self.security_qos_flags @@ -397,21 +397,21 @@ impl File { self.handle.as_raw_handle(), c::FileBasicInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; let mut attr = FileAttr { attributes: info.FileAttributes, creation_time: c::FILETIME { - dwLowDateTime: info.CreationTime as c::DWORD, - dwHighDateTime: (info.CreationTime >> 32) as c::DWORD, + dwLowDateTime: info.CreationTime as u32, + dwHighDateTime: (info.CreationTime >> 32) as u32, }, last_access_time: c::FILETIME { - dwLowDateTime: info.LastAccessTime as c::DWORD, - dwHighDateTime: (info.LastAccessTime >> 32) as c::DWORD, + dwLowDateTime: info.LastAccessTime as u32, + dwHighDateTime: (info.LastAccessTime >> 32) as u32, }, last_write_time: c::FILETIME { - dwLowDateTime: info.LastWriteTime as c::DWORD, - dwHighDateTime: (info.LastWriteTime >> 32) as c::DWORD, + dwLowDateTime: info.LastWriteTime as u32, + dwHighDateTime: (info.LastWriteTime >> 32) as u32, }, file_size: 0, reparse_tag: 0, @@ -425,7 +425,7 @@ impl File { self.handle.as_raw_handle(), c::FileStandardInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); @@ -511,7 +511,7 @@ impl File { fn reparse_point( &self, space: &mut Align8<[MaybeUninit]>, - ) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> { + ) -> io::Result<(u32, *mut c::REPARSE_DATA_BUFFER)> { unsafe { let mut bytes = 0; cvt({ @@ -524,7 +524,7 @@ impl File { ptr::null_mut(), 0, space.0.as_mut_ptr().cast(), - len as c::DWORD, + len as u32, &mut bytes, ptr::null_mut(), ) @@ -609,8 +609,7 @@ impl File { "Cannot set file timestamp to 0", )); } - let is_max = - |t: c::FILETIME| t.dwLowDateTime == c::DWORD::MAX && t.dwHighDateTime == c::DWORD::MAX; + let is_max = |t: c::FILETIME| t.dwLowDateTime == u32::MAX && t.dwHighDateTime == u32::MAX; if times.accessed.map_or(false, is_max) || times.modified.map_or(false, is_max) || times.created.map_or(false, is_max) @@ -641,7 +640,7 @@ impl File { self.handle.as_raw_handle(), c::FileBasicInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; Ok(info) } @@ -1020,7 +1019,7 @@ impl FileTimes { } impl FileType { - fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { + fn new(attrs: u32, reparse_tag: u32) -> FileType { FileType { attributes: attrs, reparse_tag } } pub fn is_dir(&self) -> bool { @@ -1421,12 +1420,12 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { _TotalBytesTransferred: i64, _StreamSize: i64, StreamBytesTransferred: i64, - dwStreamNumber: c::DWORD, - _dwCallbackReason: c::DWORD, + dwStreamNumber: u32, + _dwCallbackReason: u32, _hSourceFile: c::HANDLE, _hDestinationFile: c::HANDLE, lpData: *const c_void, - ) -> c::DWORD { + ) -> u32 { if dwStreamNumber == 1 { *(lpData as *mut i64) = StreamBytesTransferred; } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 3f85bb0a099a..575178c3826c 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -141,7 +141,7 @@ impl Handle { buf: &mut [u8], overlapped: *mut c::OVERLAPPED, ) -> io::Result> { - let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; let mut amt = 0; let res = cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped)); @@ -209,12 +209,7 @@ impl Handle { Ok(Self(self.0.try_clone()?)) } - pub fn duplicate( - &self, - access: c::DWORD, - inherit: bool, - options: c::DWORD, - ) -> io::Result { + pub fn duplicate(&self, access: u32, inherit: bool, options: u32) -> io::Result { Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?)) } @@ -233,7 +228,7 @@ impl Handle { let mut io_status = c::IO_STATUS_BLOCK::PENDING; // The length is clamped at u32::MAX. - let len = cmp::min(len, c::DWORD::MAX as usize) as c::DWORD; + let len = cmp::min(len, u32::MAX as usize) as u32; let status = c::NtReadFile( self.as_handle(), ptr::null_mut(), @@ -281,7 +276,7 @@ impl Handle { let mut io_status = c::IO_STATUS_BLOCK::PENDING; // The length is clamped at u32::MAX. - let len = cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; let status = unsafe { c::NtWriteFile( self.as_handle(), diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 6406cec9c27d..59dcbbc752fd 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -75,7 +75,7 @@ pub fn is_interrupted(_errno: i32) -> bool { pub fn decode_error_kind(errno: i32) -> ErrorKind { use ErrorKind::*; - match errno as c::DWORD { + match errno as u32 { c::ERROR_ACCESS_DENIED => return PermissionDenied, c::ERROR_ALREADY_EXISTS => return AlreadyExists, c::ERROR_FILE_EXISTS => return AlreadyExists, @@ -216,7 +216,7 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { // from this closure is then the return value of the function. pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result where - F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, + F1: FnMut(*mut u16, u32) -> u32, F2: FnOnce(&[u16]) -> T, { // Start off with a stack buf but then spill over to the heap if we end up @@ -238,7 +238,7 @@ where // We used `reserve` and not `reserve_exact`, so in theory we // may have gotten more than requested. If so, we'd like to use // it... so long as we won't cause overflow. - n = heap_buf.capacity().min(c::DWORD::MAX as usize); + n = heap_buf.capacity().min(u32::MAX as usize); // Safety: MaybeUninit does not need initialization heap_buf.set_len(n); &mut heap_buf[..] @@ -254,13 +254,13 @@ where // error" is still 0 then we interpret it as a 0 length buffer and // not an actual error. c::SetLastError(0); - let k = match f1(buf.as_mut_ptr().cast::(), n as c::DWORD) { + let k = match f1(buf.as_mut_ptr().cast::(), n as u32) { 0 if api::get_last_error().code == 0 => 0, 0 => return Err(crate::io::Error::last_os_error()), n => n, } as usize; if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER { - n = n.saturating_mul(2).min(c::DWORD::MAX as usize); + n = n.saturating_mul(2).min(u32::MAX as usize); } else if k > n { n = k; } else if k == n { @@ -308,7 +308,7 @@ pub fn cvt(i: I) -> crate::io::Result { if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) } } -pub fn dur2timeout(dur: Duration) -> c::DWORD { +pub fn dur2timeout(dur: Duration) -> u32 { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the // timeouts in windows APIs are typically u32 milliseconds. To translate, we // have two pieces to take care of: @@ -320,7 +320,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 })) - .map(|ms| if ms > ::MAX as u64 { c::INFINITE } else { ms as c::DWORD }) + .map(|ms| if ms > ::MAX as u64 { c::INFINITE } else { ms as u32 }) .unwrap_or(c::INFINITE) } diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 9e15b15a3513..bff789a8030e 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -250,7 +250,7 @@ impl Socket { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nread = 0; let mut flags = 0; let result = unsafe { @@ -335,7 +335,7 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nwritten = 0; let result = unsafe { c::WSASend( @@ -371,7 +371,7 @@ impl Socket { } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = net::getsockopt(self, c::SOL_SOCKET, kind)?; if raw == 0 { Ok(None) } else { diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index ed7911b99cbd..88a4a46726ce 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -52,10 +52,10 @@ pub fn error_string(mut errnum: i32) -> String { let res = c::FormatMessageW( flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, module, - errnum as c::DWORD, + errnum as u32, 0, buf.as_mut_ptr(), - buf.len() as c::DWORD, + buf.len() as u32, ptr::null(), ) as usize; if res == 0 { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 031660335483..da76e0c52756 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -156,7 +156,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res opts.share_mode(0); let size = mem::size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, + nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), bInheritHandle: their_handle_inheritable as i32, }; @@ -226,7 +226,7 @@ fn random_number() -> usize { type AlertableIoFn = unsafe extern "system" fn( BorrowedHandle<'_>, *mut core::ffi::c_void, - c::DWORD, + u32, *mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE, ) -> c::BOOL; @@ -244,7 +244,7 @@ impl AnonPipe { pub fn read(&self, buf: &mut [u8]) -> io::Result { let result = unsafe { - let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len) }; @@ -260,7 +260,7 @@ impl AnonPipe { pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { let result = unsafe { - let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32; self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) }; @@ -295,7 +295,7 @@ impl AnonPipe { pub fn write(&self, buf: &[u8]) -> io::Result { unsafe { - let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len) } } @@ -328,7 +328,7 @@ impl AnonPipe { &self, io: AlertableIoFn, buf: *mut core::ffi::c_void, - len: c::DWORD, + len: u32, ) -> io::Result { // Use "alertable I/O" to synchronize the pipe I/O. // This has four steps. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 4b4856d870d2..76d2cb77d474 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -174,7 +174,7 @@ pub struct Command { pub enum Stdio { Inherit, - InheritSpecific { from_stdio_id: c::DWORD }, + InheritSpecific { from_stdio_id: u32 }, Null, MakePipe, Pipe(AnonPipe), @@ -364,7 +364,7 @@ impl Command { }; si_ptr = core::ptr::addr_of_mut!(si_ex) as _; } else { - si.cb = mem::size_of::() as c::DWORD; + si.cb = mem::size_of::() as u32; si_ptr = core::ptr::addr_of_mut!(si) as _; } @@ -566,7 +566,7 @@ fn program_exists(path: &Path) -> Option> { } impl Stdio { - fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option) -> io::Result { + fn to_handle(&self, stdio_id: u32, pipe: &mut Option) -> io::Result { let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) { Ok(io) => unsafe { let io = Handle::from_raw_handle(io); @@ -601,7 +601,7 @@ impl Stdio { Stdio::Null => { let size = mem::size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, + nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), bInheritHandle: 1, }; @@ -713,7 +713,7 @@ impl Process { } #[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] -pub struct ExitStatus(c::DWORD); +pub struct ExitStatus(u32); impl ExitStatus { pub fn exit_ok(&self) -> Result<(), ExitStatusError> { @@ -727,9 +727,9 @@ impl ExitStatus { } } -/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying. -impl From for ExitStatus { - fn from(u: c::DWORD) -> ExitStatus { +/// Converts a raw `u32` to a type-safe `ExitStatus` by wrapping it without copying. +impl From for ExitStatus { + fn from(u: u32) -> ExitStatus { ExitStatus(u) } } @@ -765,7 +765,7 @@ impl ExitStatusError { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(c::DWORD); +pub struct ExitCode(u32); impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); @@ -779,13 +779,13 @@ impl ExitCode { impl From for ExitCode { fn from(code: u8) -> Self { - ExitCode(c::DWORD::from(code)) + ExitCode(u32::from(code)) } } impl From for ExitCode { fn from(code: u32) -> Self { - ExitCode(c::DWORD::from(code)) + ExitCode(u32::from(code)) } } diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 831efb252c47..44385fecf6e3 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -68,7 +68,7 @@ const MAX_BUFFER_SIZE: usize = 8192; // UTF-16 to UTF-8. pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3; -pub fn get_handle(handle_id: c::DWORD) -> io::Result { +pub fn get_handle(handle_id: u32) -> io::Result { let handle = unsafe { c::GetStdHandle(handle_id) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) @@ -87,11 +87,7 @@ fn is_console(handle: c::HANDLE) -> bool { unsafe { c::GetConsoleMode(handle, &mut mode) != 0 } } -fn write( - handle_id: c::DWORD, - data: &[u8], - incomplete_utf8: &mut IncompleteUtf8, -) -> io::Result { +fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result { if data.is_empty() { return Ok(0); } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 70099e0a3b56..84f6f28dbe2c 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -45,7 +45,7 @@ impl Thread { Err(io::Error::last_os_error()) }; - unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { + unsafe extern "system" fn thread_start(main: *mut c_void) -> u32 { // Next, reserve some stack space for if we otherwise run out of stack. stack_overflow::reserve_stack(); // Finally, let's run some code. diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index bf299a9b7d2e..b853daeffebd 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -76,8 +76,8 @@ impl SystemTime { fn from_intervals(intervals: i64) -> SystemTime { SystemTime { t: c::FILETIME { - dwLowDateTime: intervals as c::DWORD, - dwHighDateTime: (intervals >> 32) as c::DWORD, + dwLowDateTime: intervals as u32, + dwHighDateTime: (intervals >> 32) as u32, }, } } diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index c35b717fe75d..f6cd457046ff 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -75,9 +75,9 @@ pub fn enable() { #[link_section = ".CRT$XLB"] #[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section` -pub static CALLBACK: unsafe extern "system" fn(*mut c_void, c::DWORD, *mut c_void) = tls_callback; +pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback; -unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: c::DWORD, _pv: *mut c_void) { +unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) { // See comments above for what this is doing. Note that we don't need this // trickery on GNU windows, just on MSVC. #[cfg(all(target_env = "msvc", not(target_thread_local)))] diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index baf23979c7c6..8b43e558d5d9 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -33,11 +33,11 @@ use crate::sync::atomic::{ use crate::sys::c; use crate::sys::thread_local::guard; -pub type Key = c::DWORD; +pub type Key = u32; type Dtor = unsafe extern "C" fn(*mut u8); pub struct LazyKey { - /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX + /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == u32::MAX /// is not a valid key value, this allows us to use zero as sentinel value /// without risking overflow. key: AtomicU32, From 8a1ce3dfcce533b9009d703f3bbf275a98b48ba4 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 08:40:13 +0000 Subject: [PATCH 341/361] Make normalization regex less exact --- src/tools/miri/tests/fail/alloc/global_system_mixup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs index 2e88e5644e44..19c62913b4c6 100644 --- a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs +++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs @@ -4,7 +4,7 @@ //@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" +//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^}]*\};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] From ffe8fc276ea593d0e1b9c8aee6edb71a53190a43 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 21:32:13 +0000 Subject: [PATCH 342/361] Don't re-export `c_int` from `c` --- library/std/src/sys/pal/windows/c.rs | 3 +-- library/std/src/sys/pal/windows/stdio.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 0197be5be3af..9982293fbb83 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -7,8 +7,7 @@ use crate::ffi::CStr; use crate::mem; -pub use crate::os::raw::c_int; -use crate::os::raw::{c_char, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 44385fecf6e3..c6a21665157d 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -181,9 +181,9 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result]) -> io::Result io::Result { - debug_assert!(utf16.len() <= c::c_int::MAX as usize); - debug_assert!(utf8.len() <= c::c_int::MAX as usize); + debug_assert!(utf16.len() <= i32::MAX as usize); + debug_assert!(utf8.len() <= i32::MAX as usize); if utf16.is_empty() { return Ok(0); @@ -386,9 +386,9 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { c::CP_UTF8, // CodePage c::WC_ERR_INVALID_CHARS, // dwFlags utf16.as_ptr(), // lpWideCharStr - utf16.len() as c::c_int, // cchWideChar + utf16.len() as i32, // cchWideChar utf8.as_mut_ptr(), // lpMultiByteStr - utf8.len() as c::c_int, // cbMultiByte + utf8.len() as i32, // cbMultiByte ptr::null(), // lpDefaultChar ptr::null_mut(), // lpUsedDefaultChar ) From 816d90ae5f87e9819f5693fa38e56ed7d76697ca Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 06:14:53 +0000 Subject: [PATCH 343/361] Fix Windows 7 --- library/std/src/sys/pal/windows/c.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 9982293fbb83..e171a78d3acf 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -390,18 +390,18 @@ compat_fn_with_fallback! { #[cfg(target_vendor = "win7")] pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, - Key: *mut c_void, + Key: *const c_void, Alertable: BOOLEAN, - Timeout: *mut c_longlong + Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") } #[cfg(target_vendor = "win7")] pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, - Key: *mut c_void, + Key: *const c_void, Alertable: BOOLEAN, - Timeout: *mut c_longlong + Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") } From 2402e84e78c2e2503a088e7d6d1b7501a8f00983 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 06:45:17 +0000 Subject: [PATCH 344/361] Make pal/windows default to deny unsafe in unsafe --- library/std/src/sys/pal/windows/api.rs | 6 ++++-- library/std/src/sys/pal/windows/c.rs | 1 + library/std/src/sys/pal/windows/compat.rs | 8 +++++--- library/std/src/sys/pal/windows/fs.rs | 1 + library/std/src/sys/pal/windows/handle.rs | 1 + library/std/src/sys/pal/windows/io.rs | 1 + library/std/src/sys/pal/windows/mod.rs | 11 +++++++---- library/std/src/sys/pal/windows/net.rs | 4 ++-- library/std/src/sys/pal/windows/os.rs | 1 + library/std/src/sys/pal/windows/pipe.rs | 1 + library/std/src/sys/pal/windows/stack_overflow.rs | 1 + library/std/src/sys/pal/windows/thread.rs | 1 + 12 files changed, 26 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 17a0e47ad595..00c816a6c09b 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -227,8 +227,10 @@ pub fn set_file_information_by_handle( info: *const c_void, size: u32, ) -> Result<(), WinError> { - let result = c::SetFileInformationByHandle(handle, class, info, size); - (result != 0).then_some(()).ok_or_else(get_last_error) + unsafe { + let result = c::SetFileInformationByHandle(handle, class, info, size); + (result != 0).then_some(()).ok_or_else(get_last_error) + } } // SAFETY: The `SetFileInformation` trait ensures that this is safe. unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 7dfda4f714c7..710dc97d150c 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -4,6 +4,7 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] +#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::mem; diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index f5d57a28db69..190e6ba0cf24 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -111,9 +111,11 @@ impl Module { /// This should only be use for modules that exist for the lifetime of std /// (e.g. kernel32 and ntdll). pub unsafe fn new(name: &CStr) -> Option { - // SAFETY: A CStr is always null terminated. - let module = c::GetModuleHandleA(name.as_ptr().cast::()); - NonNull::new(module).map(Self) + unsafe { + // SAFETY: A CStr is always null terminated. + let module = c::GetModuleHandleA(name.as_ptr().cast::()); + NonNull::new(module).map(Self) + } } // Try to get the address of a function. diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index cc68f5ef5f08..37a4587dccf0 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use core::ptr::addr_of; use crate::os::windows::prelude::*; diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 3f85bb0a099a..21b9f6b816b5 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -1,4 +1,5 @@ #![unstable(issue = "none", feature = "windows_handle")] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 77b8f3c410eb..6b05791a4ec2 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::marker::PhantomData; use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 6406cec9c27d..e070251fbdba 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -1,4 +1,5 @@ #![allow(missing_docs, nonstandard_style)] +#![deny(unsafe_op_in_unsafe_fn)] use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; @@ -54,11 +55,13 @@ impl IoResult for Result { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { - stack_overflow::init(); + unsafe { + stack_overflow::init(); - // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already - // exists, we have to call it ourselves. - thread::Thread::set_name_wide(wide_str!("main")); + // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already + // exists, we have to call it ourselves. + thread::Thread::set_name_wide(wide_str!("main")); + } } // SAFETY: must be called only once during runtime cleanup. diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 9e15b15a3513..37a38e2940fd 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -436,7 +436,7 @@ impl Socket { pub unsafe fn from_raw(raw: c::SOCKET) -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert_eq!(mem::align_of::(), mem::align_of::()); - Self::from_raw_socket(raw as RawSocket) + unsafe { Self::from_raw_socket(raw as RawSocket) } } } @@ -486,6 +486,6 @@ impl IntoRawSocket for Socket { impl FromRawSocket for Socket { unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self { - Self(FromRawSocket::from_raw_socket(raw_socket)) + unsafe { Self(FromRawSocket::from_raw_socket(raw_socket)) } } } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 62199c16bfed..d406e4e797a0 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,6 +1,7 @@ //! Implementation of `std::os` functionality for Windows. #![allow(nonstandard_style)] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 67ef3ca82da0..ebf6435e8354 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::os::windows::prelude::*; use crate::ffi::OsStr; diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index f93f31026f81..9f83c4a1760c 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -1,4 +1,5 @@ #![cfg_attr(test, allow(dead_code))] +#![allow(unsafe_op_in_unsafe_fn)] use crate::sys::c; use crate::thread; diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 70099e0a3b56..7d79439d056f 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::io; use crate::num::NonZero; From 3411a025d5716967ba9bc8b259acd687998bcc40 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 07:10:41 +0000 Subject: [PATCH 345/361] Make os/windows default to deny unsafe in unsafe --- library/std/src/os/windows/io/raw.rs | 28 ++++++++++++++++--------- library/std/src/os/windows/io/socket.rs | 8 ++++--- library/std/src/os/windows/mod.rs | 1 + library/std/src/os/windows/process.rs | 4 ++-- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 770583a9ce3e..343cc6e4a8a5 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -159,10 +159,12 @@ fn stdio_handle(raw: RawHandle) -> RawHandle { impl FromRawHandle for fs::File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - let handle = handle as sys::c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( - OwnedHandle::from_raw_handle(handle), - ))) + unsafe { + let handle = handle as sys::c::HANDLE; + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } } } @@ -260,24 +262,30 @@ impl AsRawSocket for net::UdpSocket { impl FromRawSocket for net::TcpStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::UdpSocket { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + } } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 6ffdf907c8ed..4334d041439d 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -76,7 +76,7 @@ impl BorrowedSocket<'_> { #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(socket: RawSocket) -> Self { assert!(socket != sys::c::INVALID_SOCKET as RawSocket); - Self { socket, _phantom: PhantomData } + unsafe { Self { socket, _phantom: PhantomData } } } } @@ -201,8 +201,10 @@ impl IntoRawSocket for OwnedSocket { impl FromRawSocket for OwnedSocket { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { - debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); - Self { socket } + unsafe { + debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); + Self { socket } + } } } diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 52eb3b7c0676..f452403ee842 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -24,6 +24,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] +#![deny(unsafe_op_in_unsafe_fn)] pub mod ffi; pub mod fs; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 05ffb8925a1f..3927b2ed9bb5 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -16,7 +16,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = sys::handle::Handle::from_raw_handle(handle as *mut _); + let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; let io = sys::process::Stdio::Handle(handle); process::Stdio::from_inner(io) } @@ -407,7 +407,7 @@ impl CommandExt for process::Command { attribute: usize, value: T, ) -> &mut process::Command { - self.as_inner_mut().raw_attribute(attribute, value); + unsafe { self.as_inner_mut().raw_attribute(attribute, value) }; self } } From 7e16d5fb6111fc974c5b9a2aff951f2eb07b3deb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 07:30:11 +0000 Subject: [PATCH 346/361] Move safety comment outside unsafe block --- library/std/src/sys/pal/windows/compat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index 190e6ba0cf24..49fa1603f3e1 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -111,8 +111,8 @@ impl Module { /// This should only be use for modules that exist for the lifetime of std /// (e.g. kernel32 and ntdll). pub unsafe fn new(name: &CStr) -> Option { + // SAFETY: A CStr is always null terminated. unsafe { - // SAFETY: A CStr is always null terminated. let module = c::GetModuleHandleA(name.as_ptr().cast::()); NonNull::new(module).map(Self) } From 2393093bb552d45a3e8675272308732b23ea826c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 27 Jun 2024 03:21:54 -0400 Subject: [PATCH 347/361] Mark some `f16` and `f128` functions unstably const These constifications were blocked on classification functions being added. Now that those methods are available, constify them. This brings things more in line with `f32` and `f64`. --- library/core/src/num/f128.rs | 121 ++++++++++++++++++++++++++++++----- library/core/src/num/f16.rs | 121 ++++++++++++++++++++++++++++++----- 2 files changed, 210 insertions(+), 32 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index ad5a5ee9905a..002a41b56695 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -12,6 +12,8 @@ #![unstable(feature = "f128", issue = "116909")] use crate::convert::FloatToInt; +#[cfg(not(test))] +use crate::intrinsics; use crate::mem; use crate::num::FpCategory; @@ -758,12 +760,52 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_bits(self) -> u128 { - // SAFETY: `u128` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(self) } + pub const fn to_bits(self) -> u128 { + // SAFETY: `u128` is a plain old datatype so we can always transmute to it. + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to a floating point mode that alters nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // we reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_f128_to_u128(ct: f128) -> u128 { + // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that + // is not available on all platforms (needs `netf2` and `unordtf2`). So classify + // the bits instead. + + // SAFETY: this is a POD transmutation + let bits = unsafe { mem::transmute::(ct) }; + match f128::classify_bits(bits) { + FpCategory::Nan => { + panic!("const-eval error: cannot use f128::to_bits on a NaN") + } + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f128::to_bits on a subnormal number") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits, + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f128_to_u128(x: f128) -> u128 { + // SAFETY: `u128` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128) } /// Raw transmutation from `u128`. @@ -808,11 +850,52 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_bits(v: u128) -> Self { - // SAFETY: `u128 is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(v) } + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_bits(v: u128) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + // SAFETY: `u128` is a plain old datatype so we can always transmute from it + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to floating point modes that alter nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // This is not a problem usually, but at least one tier2 platform for Rust + // actually exhibits this behavior by default: thumbv7neon + // aka "the Neon FPU in AArch32 state" + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_u128_to_f128(ct: u128) -> f128 { + match f128::classify_bits(ct) { + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f128::from_bits on a subnormal number") + } + FpCategory::Nan => { + panic!("const-eval error: cannot use f128::from_bits on NaN") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => { + // SAFETY: It's not a frumious number + unsafe { mem::transmute::(ct) } + } + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u128_to_f128(x: u128) -> f128 { + // SAFETY: `u128` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128) } /// Return the memory representation of this floating point number as a byte array in @@ -835,8 +918,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_be_bytes(self) -> [u8; 16] { + pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() } @@ -860,8 +944,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_le_bytes(self) -> [u8; 16] { + pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() } @@ -896,8 +981,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_ne_bytes(self) -> [u8; 16] { + pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() } @@ -923,7 +1009,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_be_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -949,7 +1036,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_le_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -985,7 +1073,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_ne_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 198a506f2b85..72d324aac242 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -12,6 +12,8 @@ #![unstable(feature = "f16", issue = "116909")] use crate::convert::FloatToInt; +#[cfg(not(test))] +use crate::intrinsics; use crate::mem; use crate::num::FpCategory; @@ -788,12 +790,52 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_bits(self) -> u16 { - // SAFETY: `u16` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(self) } + pub const fn to_bits(self) -> u16 { + // SAFETY: `u16` is a plain old datatype so we can always transmute to it. + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to a floating point mode that alters nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // we reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_f16_to_u16(ct: f16) -> u16 { + // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but we don't yet + // want to rely on that on all platforms because it is nondeterministic (e.g. x86 has + // convention discrepancies calling intrinsics). So just classify the bits instead. + + // SAFETY: this is a POD transmutation + let bits = unsafe { mem::transmute::(ct) }; + match f16::classify_bits(bits) { + FpCategory::Nan => { + panic!("const-eval error: cannot use f16::to_bits on a NaN") + } + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f16::to_bits on a subnormal number") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits, + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f16_to_u16(x: f16) -> u16 { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((self,), ct_f16_to_u16, rt_f16_to_u16) } /// Raw transmutation from `u16`. @@ -837,11 +879,52 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_bits(v: u16) -> Self { - // SAFETY: `u16` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(v) } + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_bits(v: u16) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + // SAFETY: `u16` is a plain old datatype so we can always transmute from it + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to floating point modes that alter nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // This is not a problem usually, but at least one tier2 platform for Rust + // actually exhibits this behavior by default: thumbv7neon + // aka "the Neon FPU in AArch32 state" + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_u16_to_f16(ct: u16) -> f16 { + match f16::classify_bits(ct) { + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f16::from_bits on a subnormal number") + } + FpCategory::Nan => { + panic!("const-eval error: cannot use f16::from_bits on NaN") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => { + // SAFETY: It's not a frumious number + unsafe { mem::transmute::(ct) } + } + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u16_to_f16(x: u16) -> f16 { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16) } /// Return the memory representation of this floating point number as a byte array in @@ -860,8 +943,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_be_bytes(self) -> [u8; 2] { + pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() } @@ -881,8 +965,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_le_bytes(self) -> [u8; 2] { + pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() } @@ -915,8 +1000,9 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_ne_bytes(self) -> [u8; 2] { + pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() } @@ -938,7 +1024,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_be_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -960,7 +1047,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_le_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -993,7 +1081,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_ne_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } From 741ed0164649290718d7a226d7d043aefa16e9e0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 15 Jul 2024 20:37:14 +1000 Subject: [PATCH 348/361] coverage: Store a copy of `num_bcbs` in `ExtractedMappings` This makes it possible to allocate per-BCB data structures without needing access to the whole graph. --- .../rustc_mir_transform/src/coverage/mappings.rs | 13 ++++++++----- compiler/rustc_mir_transform/src/coverage/mod.rs | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 25297245172a..578e1ae0b8aa 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -56,6 +56,10 @@ pub(super) struct MCDCDecision { #[derive(Default)] pub(super) struct ExtractedMappings { + /// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't + /// need access to the whole graph when allocating per-BCB data. This is + /// only public so that other code can still use exhaustive destructuring. + pub(super) num_bcbs: usize, pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, pub(super) mcdc_bitmap_bytes: u32, @@ -106,6 +110,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ); ExtractedMappings { + num_bcbs: basic_coverage_blocks.num_nodes(), code_mappings, branch_pairs, mcdc_bitmap_bytes, @@ -115,12 +120,10 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( } impl ExtractedMappings { - pub(super) fn all_bcbs_with_counter_mappings( - &self, - basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set - ) -> BitSet { + pub(super) fn all_bcbs_with_counter_mappings(&self) -> BitSet { // Fully destructure self to make sure we don't miss any fields that have mappings. let Self { + num_bcbs, code_mappings, branch_pairs, mcdc_bitmap_bytes: _, @@ -129,7 +132,7 @@ impl ExtractedMappings { } = self; // Identify which BCBs have one or more mappings. - let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut bcbs_with_counter_mappings = BitSet::new_empty(*num_bcbs); let mut insert = |bcb| { bcbs_with_counter_mappings.insert(bcb); }; diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 2efca40d1804..4e6692a55e5b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -88,8 +88,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. - let bcbs_with_counter_mappings = - extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks); + let bcbs_with_counter_mappings = extracted_mappings.all_bcbs_with_counter_mappings(); if bcbs_with_counter_mappings.is_empty() { // No relevant spans were found in MIR, so skip instrumenting this function. return; @@ -163,6 +162,7 @@ fn create_mappings<'tcx>( // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { + num_bcbs: _, code_mappings, branch_pairs, mcdc_bitmap_bytes: _, From d4f1f9242624f007c48d358ae3f62d046dee8925 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 15 Jul 2024 20:32:14 +1000 Subject: [PATCH 349/361] coverage: Restrict `ExpressionUsed` simplification to `Code` mappings In the future, branch and MC/DC mappings might have expressions that don't correspond to any single point in the control-flow graph. That makes it trickier to keep track of which expressions should expect an `ExpressionUsed` node. We therefore sidestep that complexity by only performing `ExpressionUsed` simplification for expressions associated directly with ordinary `Code` mappings. --- .../rustc_codegen_llvm/src/coverageinfo/map_data.rs | 11 +++++++++-- compiler/rustc_middle/src/mir/coverage.rs | 13 ------------- .../rustc_mir_transform/src/coverage/mappings.rs | 9 +++++++++ compiler/rustc_mir_transform/src/coverage/mod.rs | 13 +++++++++---- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index b969fe27a99b..14a944685870 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -66,8 +66,15 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { // For each expression ID that is directly used by one or more mappings, // mark it as not-yet-seen. This indicates that we expect to see a // corresponding `ExpressionUsed` statement during MIR traversal. - for term in function_coverage_info.mappings.iter().flat_map(|m| m.kind.terms()) { - if let CovTerm::Expression(id) = term { + for mapping in function_coverage_info.mappings.iter() { + // Currently we only worry about ordinary code mappings. + // For branch and MC/DC mappings, expressions might not correspond + // to any particular point in the control-flow graph. + // (Keep this in sync with the injection of `ExpressionUsed` + // statements in the `InstrumentCoverage` MIR pass.) + if let MappingKind::Code(term) = mapping.kind + && let CovTerm::Expression(id) = term + { expressions_seen.remove(id); } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index beaaadd497d3..2a593340849e 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -220,19 +220,6 @@ pub enum MappingKind { } impl MappingKind { - /// Iterator over all coverage terms in this mapping kind. - pub fn terms(&self) -> impl Iterator { - let zero = || None.into_iter().chain(None); - let one = |a| Some(a).into_iter().chain(None); - let two = |a, b| Some(a).into_iter().chain(Some(b)); - match *self { - Self::Code(term) => one(term), - Self::Branch { true_term, false_term } => two(true_term, false_term), - Self::MCDCBranch { true_term, false_term, .. } => two(true_term, false_term), - Self::MCDCDecision(_) => zero(), - } - } - /// Returns a copy of this mapping kind, in which all coverage terms have /// been replaced with ones returned by the given function. pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self { diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 578e1ae0b8aa..2ac08ea85d25 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -159,6 +159,15 @@ impl ExtractedMappings { bcbs_with_counter_mappings } + + /// Returns the set of BCBs that have one or more `Code` mappings. + pub(super) fn bcbs_with_ordinary_code_mappings(&self) -> BitSet { + let mut bcbs = BitSet::new_empty(self.num_bcbs); + for &CodeMapping { span: _, bcb } in &self.code_mappings { + bcbs.insert(bcb); + } + bcbs + } } fn resolve_block_markers( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 4e6692a55e5b..3772a8f51181 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -25,7 +25,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; use crate::MirPass; @@ -108,7 +108,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_coverage_statements( mir_body, &basic_coverage_blocks, - bcb_has_counter_mappings, + &extracted_mappings, &coverage_counters, ); @@ -219,7 +219,7 @@ fn create_mappings<'tcx>( fn inject_coverage_statements<'tcx>( mir_body: &mut mir::Body<'tcx>, basic_coverage_blocks: &CoverageGraph, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + extracted_mappings: &ExtractedMappings, coverage_counters: &CoverageCounters, ) { // Inject counter-increment statements into MIR. @@ -252,11 +252,16 @@ fn inject_coverage_statements<'tcx>( // can check whether the injected statement survived MIR optimization. // (BCB edges can't have spans, so we only need to process BCB nodes here.) // + // We only do this for ordinary `Code` mappings, because branch and MC/DC + // mappings might have expressions that don't correspond to any single + // point in the control-flow graph. + // // See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals // with "expressions seen" and "zero terms". + let eligible_bcbs = extracted_mappings.bcbs_with_ordinary_code_mappings(); for (bcb, expression_id) in coverage_counters .bcb_nodes_with_coverage_expressions() - .filter(|&(bcb, _)| bcb_has_coverage_spans(bcb)) + .filter(|&(bcb, _)| eligible_bcbs.contains(bcb)) { inject_statement( mir_body, From 9c3c278b545d9e03939e3bfcbebb256758b9a8b9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 01:06:40 +0000 Subject: [PATCH 350/361] Add support for `Result<&T, _>' --- .../src/fn_ctxt/suggestions.rs | 19 +++++++++---------- ...ransforming-option-ref-issue-127545.stderr | 4 ++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 15a1a18daa70..faa6d06ccaf2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1451,9 +1451,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else { return; }; - if !self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + "Option" + } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) { + "Result" + } else { return; - } + }; if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { return; @@ -1484,14 +1488,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(snip) => (snip, Applicability::MachineApplicable), Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), }; - let sugg = &format!("map_or({provided_snip}, |v| v)"); - err.span_suggestion_verbose( - error_span, - "use `Option::map_or` to deref inner value of `Option`", - sugg, - applicability, - ); - return; + let sugg = format!("map_or({provided_snip}, |v| v)"); + let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); + err.span_suggestion_verbose(error_span, msg, sugg, applicability); } /// Suggest wrapping the block in square brackets instead of curly braces diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 0a6d47339d8e..1790fc1249ab 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -80,6 +80,10 @@ LL | arg.unwrap_or(&[]) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/result.rs:LL:COL +help: use `Result::map_or` to deref inner value of `Result` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors From bdc9df247841e259c24e95fd81754fb61e332c65 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 01:18:21 +0000 Subject: [PATCH 351/361] Use multipart_suggestion to avoid place holder in span_to_snippet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CO-AUTHORED-BY: Esteban Küber --- .../src/fn_ctxt/suggestions.rs | 20 +++++++++++-------- ...ransforming-option-ref-issue-127545.stderr | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index faa6d06ccaf2..b3b4c5a56fbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1459,7 +1459,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { + let Some(call_ident) = call_ident else { + return; + }; + if call_ident.name != sym::unwrap_or { return; } @@ -1483,14 +1486,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.can_coerce(expected_ty, dummy_ty) { return; } - let (provided_snip, applicability) = - match self.tcx.sess.source_map().span_to_snippet(provided_expr.span) { - Ok(snip) => (snip, Applicability::MachineApplicable), - Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), - }; - let sugg = format!("map_or({provided_snip}, |v| v)"); let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); - err.span_suggestion_verbose(error_span, msg, sugg, applicability); + err.multipart_suggestion_verbose( + msg, + vec![ + (call_ident.span, "map_or".to_owned()), + (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()), + ], + Applicability::MachineApplicable, + ); } /// Suggest wrapping the block in square brackets instead of curly braces diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 1790fc1249ab..ad423f86ef9e 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -35,7 +35,7 @@ note: method defined here help: use `Option::map_or` to deref inner value of `Option` | LL | arg.map_or(&[], |v| v) - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 @@ -59,7 +59,7 @@ note: method defined here help: use `Option::map_or` to deref inner value of `Option` | LL | arg.map_or(v, |v| v) - | ~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:17:19 @@ -83,7 +83,7 @@ note: method defined here help: use `Result::map_or` to deref inner value of `Result` | LL | arg.map_or(&[], |v| v) - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error: aborting due to 4 previous errors From ee86e2d624a61b634c14dd931b7ae2532a6634ff Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:00:42 -0400 Subject: [PATCH 352/361] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/book b/src/doc/book index f1e49bf7a8ea..67fa53676801 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64 +Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 941db8b3df45..5454de3d12b9 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c +Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac diff --git a/src/doc/embedded-book b/src/doc/embedded-book index b10c6acaf0f4..019f3928d8b9 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit b10c6acaf0f43481f6600e95d4b5013446e29f7a +Subproject commit 019f3928d8b939ec71b63722dcc2e46330156441 diff --git a/src/doc/reference b/src/doc/reference index 1ae3deebc3ac..2a7931476643 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08 +Subproject commit 2a7931476643e2a07bf9796e14bbeee3c9e589b8 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 658c6c27cb97..89aecb6951b7 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 658c6c27cb975b92227936024816986c2d3716fb +Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d6e3a32a557d..0c4d55cb59fe 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7 +Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f From 3051436a3c5e7717c840bf04f6f147223739566b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 15 Jul 2024 10:58:58 -0700 Subject: [PATCH 353/361] Update reference to fix toolstate --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 2a7931476643..e2f0bdc40318 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 2a7931476643e2a07bf9796e14bbeee3c9e589b8 +Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf From ff9c4883449ff895942398be656e260891755e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 7 Jul 2024 17:16:44 +0200 Subject: [PATCH 354/361] Move `force_coloring_in_ci` from `builder_helper` to `bootstrap` It was only used in bootstrap. This move allows us to modify the function to work with `BootstrapCommand`, rather than `Command`. --- src/bootstrap/src/core/build_steps/test.rs | 4 +--- src/bootstrap/src/core/builder.rs | 2 +- src/bootstrap/src/utils/exec.rs | 13 +++++++++++++ src/tools/build_helper/src/ci.rs | 14 -------------- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 118b6b876ed1..3f0cbde64e39 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2095,9 +2095,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let git_config = builder.config.git_config(); cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); - - // FIXME: Move CiEnv back to bootstrap, it is only used here anyway - builder.ci_env.force_coloring_in_ci(cmd.as_command_mut()); + cmd.force_coloring_in_ci(builder.ci_env); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index aeb347436080..08308dbbf73f 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2105,7 +2105,7 @@ impl<'a> Builder<'a> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - self.ci_env.force_coloring_in_ci(cargo.as_command_mut()); + cargo.force_coloring_in_ci(self.ci_env); // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index b05301649973..a60c0084f3d7 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,5 @@ use crate::Build; +use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; use std::ffi::OsStr; use std::fmt::{Debug, Formatter}; @@ -171,6 +172,18 @@ impl BootstrapCommand { pub fn get_created_location(&self) -> std::panic::Location<'static> { self.drop_bomb.get_created_location() } + + /// If in a CI environment, forces the command to run with colors. + pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) { + if ci_env != CiEnv::None { + // Due to use of stamp/docker, the output stream of bootstrap is not + // a TTY in CI, so coloring is by-default turned off. + // The explicit `TERM=xterm` environment is needed for + // `--color always` to actually work. This env var was lost when + // compiling through the Makefile. Very strange. + self.env("TERM", "xterm").args(["--color", "always"]); + } + } } impl Debug for BootstrapCommand { diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 233fed4151c1..6d79c7c83ad8 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -1,5 +1,3 @@ -use std::process::Command; - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum CiEnv { /// Not a CI environment. @@ -21,18 +19,6 @@ impl CiEnv { pub fn is_ci() -> bool { Self::current() != CiEnv::None } - - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(self, cmd: &mut Command) { - if self != CiEnv::None { - // Due to use of stamp/docker, the output stream of bootstrap is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - cmd.env("TERM", "xterm").args(&["--color", "always"]); - } - } } pub mod gha { From 7a5411757124b3cdc4aff5ea86cbe91f5e58a618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 14 Jul 2024 10:58:57 +0200 Subject: [PATCH 355/361] Make sure to run git submodule checkout in dry run mode --- src/bootstrap/src/lib.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 52e28fbd0598..c2367375708a 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -490,7 +490,17 @@ impl Build { return; } - let submodule_git = || helpers::git(Some(&absolute_path)).capture_stdout(); + // Submodule updating actually happens during in the dry run mode. We need to make sure that + // all the git commands below are actually executed, because some follow-up code + // in bootstrap might depend on the submodules being checked out. Furthermore, not all + // the command executions below work with an empty output (produced during dry run). + // Therefore, all commands below are marked with `run_always()`, so that they also run in + // dry run mode. + let submodule_git = || { + let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout(); + cmd.run_always(); + cmd + }; // Determine commit checked out in submodule. let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout(); @@ -498,6 +508,7 @@ impl Build { // Determine commit that the submodule *should* have. let recorded = helpers::git(Some(&self.src)) .capture_stdout() + .run_always() .args(["ls-tree", "HEAD"]) .arg(relative_path) .run(self) @@ -514,6 +525,7 @@ impl Build { println!("Updating submodule {}", relative_path.display()); helpers::git(Some(&self.src)) + .run_always() .args(["submodule", "-q", "sync"]) .arg(relative_path) .run(self); @@ -524,12 +536,14 @@ impl Build { // even though that has no relation to the upstream for the submodule. let current_branch = helpers::git(Some(&self.src)) .capture_stdout() + .run_always() .args(["symbolic-ref", "--short", "HEAD"]) .run(self) .stdout_if_ok() .map(|s| s.trim().to_owned()); let mut git = helpers::git(Some(&self.src)).allow_failure(); + git.run_always(); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. From 317952677ad6a80b3751a075f42ffd2a8d142a84 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 13 Feb 2024 05:24:32 +0800 Subject: [PATCH 356/361] Suggest a borrow when using dbg --- .../src/diagnostics/conflict_errors.rs | 65 +++++++++- tests/ui/borrowck/dbg-issue-120327.rs | 68 ++++++++++ tests/ui/borrowck/dbg-issue-120327.stderr | 117 ++++++++++++++++++ .../dbg-macro-move-semantics.stderr | 4 + 4 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 tests/ui/borrowck/dbg-issue-120327.rs create mode 100644 tests/ui/borrowck/dbg-issue-120327.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1cb74849017a..c7f6840e401c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4,7 +4,7 @@ #![allow(rustc::untranslatable_diagnostic)] use either::Either; -use hir::ClosureKind; +use hir::{ClosureKind, Path}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; @@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::VarDebugInfoContents; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, @@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } } - if let Some(pat) = finder.pat { + + self.suggest_ref_for_dbg_args(expr, place, move_span, err); + + // it's useless to suggest inserting `ref` when the span don't comes from local code + if let Some(pat) = finder.pat + && !move_span.is_dummy() + && !self.infcx.tcx.sess.source_map().is_imported(move_span) + { *in_pattern = true; let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; if let Some(pat) = finder.parent_pat { @@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } + // for dbg!(x) which may take ownership, suggest dbg!(&x) instead + // but here we actually do not check whether the macro name is `dbg!` + // so that we may extend the scope a bit larger to cover more cases + fn suggest_ref_for_dbg_args( + &self, + body: &hir::Expr<'_>, + place: &Place<'tcx>, + move_span: Span, + err: &mut Diag<'infcx>, + ) { + let var_info = self.body.var_debug_info.iter().find(|info| match info.value { + VarDebugInfoContents::Place(ref p) => p == place, + _ => false, + }); + let arg_name = if let Some(var_info) = var_info { + var_info.name + } else { + return; + }; + struct MatchArgFinder { + expr_span: Span, + match_arg_span: Option, + arg_name: Symbol, + } + impl Visitor<'_> for MatchArgFinder { + fn visit_expr(&mut self, e: &hir::Expr<'_>) { + // dbg! is expanded into a match pattern, we need to find the right argument span + if let hir::ExprKind::Match(expr, ..) = &e.kind + && let hir::ExprKind::Path(hir::QPath::Resolved( + _, + path @ Path { segments: [seg], .. }, + )) = &expr.kind + && seg.ident.name == self.arg_name + && self.expr_span.source_callsite().contains(expr.span) + { + self.match_arg_span = Some(path.span); + } + hir::intravisit::walk_expr(self, e); + } + } + + let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name }; + finder.visit_expr(body); + if let Some(macro_arg_span) = finder.match_arg_span { + err.span_suggestion_verbose( + macro_arg_span.shrink_to_lo(), + "consider borrowing instead of transferring ownership", + "&", + Applicability::MachineApplicable, + ); + } + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs new file mode 100644 index 000000000000..2de43f634877 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.rs @@ -0,0 +1,68 @@ +fn s() -> String { + let a = String::new(); + dbg!(a); + return a; //~ ERROR use of moved value: +} + +fn m() -> String { + let a = String::new(); + dbg!(1, 2, a, 1, 2); + return a; //~ ERROR use of moved value: +} + +fn t(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return b; //~ ERROR use of moved value: +} + +fn x(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return a; //~ ERROR use of moved value: +} + +macro_rules! my_dbg { + () => { + eprintln!("[{}:{}:{}]", file!(), line!(), column!()) + }; + ($val:expr $(,)?) => { + match $val { + tmp => { + eprintln!("[{}:{}:{}] {} = {:#?}", + file!(), line!(), column!(), stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($(my_dbg!($val)),+,) + }; +} + +fn test_my_dbg() -> String { + let b: String = "".to_string(); + my_dbg!(b, 1); + return b; //~ ERROR use of moved value: +} + +fn test_not_macro() -> String { + let a = String::new(); + let _b = match a { + tmp => { + eprintln!("dbg: {}", tmp); + tmp + } + }; + return a; //~ ERROR use of moved value: +} + +fn get_expr(_s: String) {} + +fn test() { + let a: String = "".to_string(); + let _res = get_expr(dbg!(a)); + let _l = a.len(); //~ ERROR borrow of moved value +} + +fn main() {} diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr new file mode 100644 index 000000000000..efacc0c3f134 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.stderr @@ -0,0 +1,117 @@ +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:4:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a); + | ------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:10:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(1, 2, a, 1, 2); + | ------------------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(1, 2, &a, 1, 2); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:16:12 + | +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, b); + | ---------- value moved here +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(a, &b); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:22:12 + | +LL | fn x(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let b: String = "".to_string(); +LL | dbg!(a, b); + | ---------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a, b); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:46:12 + | +LL | tmp => { + | --- value moved here +... +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | my_dbg!(b, 1); +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | my_dbg!(&b, 1); + | + +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:57:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _b = match a { +LL | tmp => { + | --- value moved here +... +LL | return a; + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: borrow of moved value: `a` + --> $DIR/dbg-issue-120327.rs:65:14 + | +LL | let a: String = "".to_string(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _res = get_expr(dbg!(a)); + | ------- value moved here +LL | let _l = a.len(); + | ^ value borrowed here after move + | +help: consider borrowing instead of transferring ownership + | +LL | let _res = get_expr(dbg!(&a)); + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index c2b9899e20db..f515cb62c7cd 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -9,6 +9,10 @@ LL | let _ = dbg!(a); | ^^^^^^^ value used here after move | = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing instead of transferring ownership + | +LL | let _ = dbg!(&a); + | + error: aborting due to 1 previous error From 841b30f63ea1592f40a906ed1400c1999b89b4ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 16:43:18 -0400 Subject: [PATCH 357/361] Make sure trait def ids match before zipping args in note_function_argument_obligation --- .../src/error_reporting/traits/suggestions.rs | 1 + tests/crashes/126416.rs | 20 ----- tests/ui/methods/filter-relevant-fn-bounds.rs | 23 ++++++ .../methods/filter-relevant-fn-bounds.stderr | 74 +++++++++++++++++++ 4 files changed, 98 insertions(+), 20 deletions(-) delete mode 100644 tests/crashes/126416.rs create mode 100644 tests/ui/methods/filter-relevant-fn-bounds.rs create mode 100644 tests/ui/methods/filter-relevant-fn-bounds.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2cf808f962f0..f8843b892db3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(where_pred) = where_pred.as_trait_clause() && let Some(failed_pred) = failed_pred.as_trait_clause() + && where_pred.def_id() == failed_pred.def_id() { self.enter_forall(where_pred, |where_pred| { let failed_pred = self.instantiate_binder_with_fresh_vars( diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs deleted file mode 100644 index 9b6c5169d444..000000000000 --- a/tests/crashes/126416.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126416 - -trait Output<'a, T: 'a> { - type Type; -} - -struct Wrapper; - -impl Wrapper { - fn do_something_wrapper(&mut self, _: F) - where - F: for<'a> FnOnce(>::Type), - { - } -} - -fn main() { - let mut wrapper = Wrapper; - wrapper.do_something_wrapper(|value| ()); -} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs new file mode 100644 index 000000000000..76ececf7baa7 --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -0,0 +1,23 @@ +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(self, _: F) + //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + where + F: for<'a> FnOnce(>::Type), + //~^ ERROR the trait bound `F: Output<'_>` is not satisfied + //~| ERROR the trait bound `F: Output<'_>` is not satisfied + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); + //~^ ERROR expected a `FnOnce +} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr new file mode 100644 index 000000000000..b737c0ab11fd --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -0,0 +1,74 @@ +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:5 + | +LL | / fn do_something_wrapper(self, _: F) +LL | | +LL | | +LL | | where +LL | | F: for<'a> FnOnce(>::Type), + | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:8 + | +LL | fn do_something_wrapper(self, _: F) + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:20 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + --> $DIR/filter-relevant-fn-bounds.rs:21:34 + | +LL | wrapper.do_something_wrapper(|value| ()); + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` +help: this trait has no implementations, consider adding one + --> $DIR/filter-relevant-fn-bounds.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | fn do_something_wrapper(self, _: F) + | -------------------- required by a bound in this associated function +... +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. From 47d8d3d1dd4404c6626cb97f9da38a6df7403976 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 15 Jul 2024 22:23:20 -0700 Subject: [PATCH 358/361] Fix typos in RELEASES.md as requested in https://github.com/rust-lang/blog.rust-lang.org/pull/1358#discussion_r1678691772 --- RELEASES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 9e658568dc9a..0ecd472efb6e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -67,7 +67,7 @@ Stabilized APIs - [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add) - [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub) - [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub) -- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) +- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) - [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from) - [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read) - [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile) @@ -91,9 +91,9 @@ Stabilized APIs - [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii) - [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start) - [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end) -- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) -- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) -- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) +- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) +- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) +- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) - [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS) - [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits) - [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits) From 3e73272ac7bf16dce952cdc57f94600726c0cc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 16 Jul 2024 10:41:13 +0300 Subject: [PATCH 359/361] Use re-exported Idx and IndexVec in pat_analysis --- .../hir-ty/src/diagnostics/match_check/pat_analysis.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 01e43a67e434..bf2ff1a917c5 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 @@ -4,11 +4,10 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use once_cell::unsync::Lazy; -use rustc_index::IndexVec; use rustc_pattern_analysis::{ constructor::{Constructor, ConstructorSet, VariantVisibility}, usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport}, - Captures, PatCx, PrivateUninhabitedField, + Captures, IndexVec, PatCx, PrivateUninhabitedField, }; use smallvec::{smallvec, SmallVec}; use stdx::never; @@ -53,7 +52,7 @@ impl EnumVariantContiguousIndex { } } -impl rustc_index::Idx for EnumVariantContiguousIndex { +impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex { fn new(idx: usize) -> Self { EnumVariantContiguousIndex(idx) } From 2e37675cc91052ea5a3fe56019e2d66e5822f1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 16 Jul 2024 16:23:33 +0300 Subject: [PATCH 360/361] 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 424c93a75218..18e32e5c65b0 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -bcf1f6db4594ae6132378b179a30cdb3599a863d +a91f7d72f12efcc00ecf71591f066c534d45ddf7 From 72e22554caa473df6af10f0ab6c3c7c7c5ef8841 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 17 Jul 2024 10:07:17 -0400 Subject: [PATCH 361/361] cleanup: remove support for 3DNow! cpu features In llvm/llvm-project@f0eb5587ceeb641445b64cb264c822b4751de04a all support for 3DNow! intrinsics and instructions were removed. Per the commit message there, only AMD chips between 1998 and 2011 or so actually supported these instructions, and they were effectively replaced by SSE which was available on many more chips. I'd be very surprised if anyone had ever used these from Rust. --- compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 4c67fa0f7aa6..549706998d46 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -18,9 +18,7 @@ pub fn target() -> Target { relro_level: RelroLevel::Full, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - features: - "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" - .into(), + features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(), supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, disable_redzone: true, panic_strategy: PanicStrategy::Abort,