From c957b809e9bc9907c4de2386935888cf3cf585ef Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 6 Apr 2022 14:16:17 -0700 Subject: [PATCH 1/8] Update binary_search example to instead redirect to partition_point --- library/alloc/src/collections/vec_deque/mod.rs | 18 ++++++++++++++++-- library/core/src/slice/mod.rs | 16 ++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index dcae58ae590f1..2133f3725c876 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2593,14 +2593,15 @@ impl VecDeque { /// ``` /// /// If you want to insert an item to a sorted deque, while maintaining - /// sort order: + /// sort order, consider using [`partition_point`]: /// /// ``` /// use std::collections::VecDeque; /// /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// let num = 42; - /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x); + /// let idx = deque.partition_point(&num); + /// // The above is equivalent to `let idx = deque.binary_search(&num).unwrap_or_else(|x| x);` /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` @@ -2744,6 +2745,19 @@ impl VecDeque { /// assert!(deque.iter().take(i).all(|&x| x < 5)); /// assert!(deque.iter().skip(i).all(|&x| !(x < 5))); /// ``` + /// + /// If you want to insert an item to a sorted deque, while maintaining + /// sort order: + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let num = 42; + /// let idx = deque.partition_point(&num); + /// deque.insert(idx, num); + /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] pub fn partition_point

(&self, mut pred: P) -> usize where diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 17f6373ecbf86..dee089d4e97b6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2332,12 +2332,13 @@ impl [T] { /// ``` /// /// If you want to insert an item to a sorted vector, while maintaining - /// sort order: + /// sort order, consider using [`partition_point`]: /// /// ``` /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// let num = 42; - /// let idx = s.binary_search(&num).unwrap_or_else(|x| x); + /// let idx = s.partition_point(&num); + /// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);` /// s.insert(idx, num); /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` @@ -3744,6 +3745,17 @@ impl [T] { /// assert!(v[..i].iter().all(|&x| x < 5)); /// assert!(v[i..].iter().all(|&x| !(x < 5))); /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(&num); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` #[stable(feature = "partition_point", since = "1.52.0")] #[must_use] pub fn partition_point

(&self, mut pred: P) -> usize From 0eb0d891ad2558f523527db8595c1daf03c5ca83 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 6 Apr 2022 18:14:21 -0700 Subject: [PATCH 2/8] add necessary closure for partition_point --- library/alloc/src/collections/vec_deque/mod.rs | 4 ++-- library/core/src/slice/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 2133f3725c876..488671d8d8d19 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2600,7 +2600,7 @@ impl VecDeque { /// /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// let num = 42; - /// let idx = deque.partition_point(&num); + /// let idx = deque.partition_point(|&x| x < num); /// // The above is equivalent to `let idx = deque.binary_search(&num).unwrap_or_else(|x| x);` /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); @@ -2754,7 +2754,7 @@ impl VecDeque { /// /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// let num = 42; - /// let idx = deque.partition_point(&num); + /// let idx = deque.partition_point(|&x| x < num); /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dee089d4e97b6..ccb32bf16e3b8 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2337,7 +2337,7 @@ impl [T] { /// ``` /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// let num = 42; - /// let idx = s.partition_point(&num); + /// let idx = s.partition_point(|&x| x < num); /// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);` /// s.insert(idx, num); /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); @@ -3752,7 +3752,7 @@ impl [T] { /// ``` /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// let num = 42; - /// let idx = s.partition_point(&num); + /// let idx = s.partition_point(|&x| x < num); /// s.insert(idx, num); /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` From 77f610e4b4a930c8552d9f642a9b8ec802dfdd59 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 9 Apr 2022 18:55:23 +0100 Subject: [PATCH 3/8] Note that CI tests Windows 10 --- src/doc/rustc/src/platform-support.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 32def67ed65e3..b3c4a52c414b2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -31,18 +31,20 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes] -`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) +`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support] +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) `x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+) -`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) -`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) +`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support] +`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support] `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) [^missing-stack-probes]: Stack probes support is missing on `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near future. The implementation is tracked on [issue #77071][77071]. +[^windows-support]: Only Windows 10 currently undergoes automated testing. Earlier versions of Windows rely on testing and support from the community. + [77071]: https://github.com/rust-lang/rust/issues/77071 ## Tier 1 From bf3ef0da0c630ab239e4f26e86602eabe585e74f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:25:46 -0400 Subject: [PATCH 4/8] Switch to the 'normal' basic block for writing asm outputs if needed. We may sometimes emit an `invoke` instead of a `call` for inline assembly during the MIR -> LLVM IR lowering. But we failed to update the IR builder's current basic block before writing the results to the outputs. This would result in invalid IR because the basic block would end in a `store` instruction, which isn't a valid terminator. --- compiler/rustc_codegen_llvm/src/asm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 03c390b4bd427..91d132eb34350 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -290,6 +290,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); + // Switch to the 'normal' basic block if we did an `invoke` instead of a `call` + if let Some((dest, _, _)) = dest_catch_funclet { + self.switch_to_block(dest); + } + // Write results to outputs for (idx, op) in operands.iter().enumerate() { if let InlineAsmOperandRef::Out { reg, place: Some(place), .. } From 0b2f3604fd733db5ad9498eaf129655879c242b3 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:16:38 -0700 Subject: [PATCH 5/8] Update asm-may_unwind test to handle use of asm with outputs. --- src/test/codegen/asm-may_unwind.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs index 3b34d79c3a946..bf4202764a7ec 100644 --- a/src/test/codegen/asm-may_unwind.rs +++ b/src/test/codegen/asm-may_unwind.rs @@ -18,10 +18,23 @@ impl Drop for Foo { } } -// CHECK-LABEL: @may_unwind +// CHECK-LABEL: @asm_may_unwind #[no_mangle] -pub unsafe fn may_unwind() { +pub unsafe fn asm_may_unwind() { let _m = Foo; // CHECK: invoke void asm sideeffect alignstack inteldialect unwind "" asm!("", options(may_unwind)); } + +// CHECK-LABEL: @asm_with_result_may_unwind +#[no_mangle] +pub unsafe fn asm_with_result_may_unwind() -> u64 { + let _m = Foo; + let res: u64; + // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind + // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]] + asm!("mov {}, 1", out(reg) res, options(may_unwind)); + // CHECK: [[NORMALBB]]: + // CHECK: ret i64 [[RES:%[0-9]+]] + res +} From 137c207d2055c5703320c71ea6cdd02932492f06 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Apr 2022 11:11:25 -0700 Subject: [PATCH 6/8] FIXME for diagnostic variable name --- compiler/rustc_middle/src/ty/error.rs | 124 +++++++++--------- .../rustc_resolve/src/late/diagnostics.rs | 13 +- 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index d93c9a79c6556..07878defa8ccd 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -347,8 +347,7 @@ impl<'tcx> Ty<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub fn note_and_explain_type_err( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, err: &TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, @@ -360,12 +359,12 @@ impl<'tcx> TyCtxt<'tcx> { ArgumentSorts(values, _) | Sorts(values) => { match (values.expected.kind(), values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { - db.note("no two closures, even if identical, have the same type"); - db.help("consider boxing your closure and/or using it as a trait object"); + diag.note("no two closures, even if identical, have the same type"); + diag.help("consider boxing your closure and/or using it as a trait object"); } (ty::Opaque(..), ty::Opaque(..)) => { // Issue #63167 - db.note("distinct uses of `impl Trait` result in different opaque types"); + diag.note("distinct uses of `impl Trait` result in different opaque types"); } (ty::Float(_), ty::Infer(ty::IntVar(_))) if let Ok( @@ -374,7 +373,7 @@ impl<'tcx> TyCtxt<'tcx> { ) = self.sess.source_map().span_to_snippet(sp) => { if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - db.span_suggestion( + diag.span_suggestion( sp, "use a float literal", format!("{}.0", snippet), @@ -386,30 +385,30 @@ impl<'tcx> TyCtxt<'tcx> { let generics = self.generics_of(body_owner_def_id); let e_span = self.def_span(generics.type_param(expected, self).def_id); if !sp.contains(e_span) { - db.span_label(e_span, "expected type parameter"); + diag.span_label(e_span, "expected type parameter"); } let f_span = self.def_span(generics.type_param(found, self).def_id); if !sp.contains(f_span) { - db.span_label(f_span, "found type parameter"); + diag.span_label(f_span, "found type parameter"); } - db.note( + diag.note( "a type parameter was expected, but a different one was found; \ you might be missing a type parameter or trait bound", ); - db.note( + diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch10-02-traits.html\ #traits-as-parameters", ); } (ty::Projection(_), ty::Projection(_)) => { - db.note("an associated type was expected, but a different one was found"); + diag.note("an associated type was expected, but a different one was found"); } (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); if !sp.contains(p_span) { - db.span_label(p_span, "this type parameter"); + diag.span_label(p_span, "this type parameter"); } let hir = self.hir(); let mut note = true; @@ -444,14 +443,14 @@ impl<'tcx> TyCtxt<'tcx> { note = !suggest_constraining_type_param( self, generics, - db, + diag, &format!("{}", proj.self_ty()), &path, None, ); } if note { - db.note("you might be missing a type parameter or trait bound"); + diag.note("you might be missing a type parameter or trait bound"); } } (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..)) @@ -459,11 +458,11 @@ impl<'tcx> TyCtxt<'tcx> { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); if !sp.contains(p_span) { - db.span_label(p_span, "this type parameter"); + diag.span_label(p_span, "this type parameter"); } - db.help("type parameters must be constrained to match other types"); - if self.sess.teach(&db.get_code().unwrap()) { - db.help( + diag.help("type parameters must be constrained to match other types"); + if self.sess.teach(&diag.get_code().unwrap()) { + diag.help( "given a type parameter `T` and a method `foo`: ``` trait Trait { fn foo(&self) -> T; } @@ -489,7 +488,7 @@ impl Trait for X { ```", ); } - db.note( + diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch10-02-traits.html\ #traits-as-parameters", @@ -499,9 +498,9 @@ impl Trait for X { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); if !sp.contains(p_span) { - db.span_label(p_span, "this type parameter"); + diag.span_label(p_span, "this type parameter"); } - db.help(&format!( + diag.help(&format!( "every closure has a distinct type and so could not always match the \ caller-chosen type of parameter `{}`", p @@ -511,12 +510,12 @@ impl Trait for X { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); if !sp.contains(p_span) { - db.span_label(p_span, "this type parameter"); + diag.span_label(p_span, "this type parameter"); } } (ty::Projection(proj_ty), _) => { self.expected_projection( - db, + diag, proj_ty, values, body_owner_def_id, @@ -529,19 +528,19 @@ impl Trait for X { values.found, values.expected, ); if !(self.suggest_constraining_opaque_associated_type( - db, + diag, &msg, proj_ty, values.expected, ) || self.suggest_constraint( - db, + diag, &msg, body_owner_def_id, proj_ty, values.expected, )) { - db.help(&msg); - db.note( + diag.help(&msg); + diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); @@ -560,7 +559,7 @@ impl Trait for X { CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. if ty.is_closure() || ty.is_generator() { - db.note( + diag.note( "closures cannot capture themselves or take themselves as argument;\n\ this error may be the result of a recent compiler bug-fix,\n\ see issue #46062 \n\ @@ -574,10 +573,10 @@ impl Trait for X { .iter() .filter(|attr| attr.has_name(sym::target_feature)) .map(|attr| attr.span); - db.note( + diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); - db.span_labels(target_spans, "`#[target_feature]` added here"); + diag.span_labels(target_spans, "`#[target_feature]` added here"); } _ => {} } @@ -585,8 +584,7 @@ impl Trait for X { fn suggest_constraint( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, msg: &str, body_owner_def_id: DefId, proj_ty: &ty::ProjectionTy<'tcx>, @@ -623,7 +621,7 @@ impl Trait for X { } if self.constrain_generic_bound_associated_type_structured_suggestion( - db, + diag, &trait_ref, pred.bounds, &assoc, @@ -642,7 +640,7 @@ impl Trait for X { { // This is type param `A` in `::Foo`. return self.constrain_generic_bound_associated_type_structured_suggestion( - db, + diag, &trait_ref, param.bounds, &assoc, @@ -673,8 +671,7 @@ impl Trait for X { /// fn that returns the type. fn expected_projection( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, body_owner_def_id: DefId, @@ -712,7 +709,7 @@ impl Trait for X { // want the more general suggestion later in this method about "consider constraining // the associated type or calling a method that returns the associated type". let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( - db, + diag, assoc.container.id(), current_method_ident, proj_ty.item_def_id, @@ -720,33 +717,36 @@ impl Trait for X { ); // Possibly suggest constraining the associated type to conform to the // found type. - if self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found) + if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found) || point_at_assoc_fn { return; } } - self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found); + self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found); - if self.point_at_associated_type(db, body_owner_def_id, values.found) { + if self.point_at_associated_type(diag, body_owner_def_id, values.found) { return; } if !impl_comparison { // Generic suggestion when we can't be more specific. if callable_scope { - db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected)); + diag.help(&format!( + "{} or calling a method that returns `{}`", + msg, values.expected + )); } else { - db.help(&msg); + diag.help(&msg); } - db.note( + diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } - if self.sess.teach(&db.get_code().unwrap()) { - db.help( + if self.sess.teach(&diag.get_code().unwrap()) { + diag.help( "given an associated type `T` and a method `foo`: ``` trait Trait { @@ -769,8 +769,7 @@ fn foo(&self) -> Self::T { String::new() } /// a return type. This can occur when dealing with `TryStream` (#71035). fn suggest_constraining_opaque_associated_type( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, msg: &str, proj_ty: &ty::ProjectionTy<'tcx>, ty: Ty<'tcx>, @@ -790,7 +789,7 @@ fn foo(&self) -> Self::T { String::new() } let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); self.constrain_generic_bound_associated_type_structured_suggestion( - db, + diag, &trait_ref, opaque_hir_ty.bounds, assoc, @@ -806,8 +805,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_methods_that_satisfy_associated_type( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, assoc_container_id: DefId, current_method_ident: Option, proj_ty_item_def_id: DefId, @@ -854,7 +852,7 @@ fn foo(&self) -> Self::T { String::new() } for (sp, label) in methods.into_iter() { span.push_span_label(sp, label); } - db.span_help(span, &msg); + diag.span_help(span, &msg); return true; } false @@ -862,8 +860,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_associated_type( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, body_owner_def_id: DefId, found: Ty<'tcx>, ) -> bool { @@ -887,7 +884,7 @@ fn foo(&self) -> Self::T { String::new() } if let hir::Defaultness::Default { has_value: true } = item.defaultness { if self.type_of(item.id.def_id) == found { - db.span_label( + diag.span_label( item.span, "associated type defaults can't be assumed inside the \ trait defining them", @@ -907,7 +904,7 @@ fn foo(&self) -> Self::T { String::new() } for item in &items[..] { if let hir::AssocItemKind::Type = item.kind { if self.type_of(item.id.def_id) == found { - db.span_label(item.span, "expected this associated type"); + diag.span_label(item.span, "expected this associated type"); return true; } } @@ -927,8 +924,7 @@ fn foo(&self) -> Self::T { String::new() } /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: &ty::AssocItem, @@ -958,15 +954,21 @@ fn foo(&self) -> Self::T { String::new() } _ => return false, }; - self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg) + self.constrain_associated_type_structured_suggestion( + diag, + span, + assoc, + assoc_substs, + ty, + msg, + ) } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, span: Span, assoc: &ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], @@ -984,7 +986,7 @@ fn foo(&self) -> Self::T { String::new() } let item_args = self.format_generic_args(assoc_substs); (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty)) }; - db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); + diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); return true; } false diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1e943f0e44abd..3ec63d102fab6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1875,8 +1875,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { /// Returns whether to add `'static` lifetime to the suggested lifetime list. crate fn report_elision_failure( &mut self, - // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. - db: &mut Diagnostic, + diag: &mut Diagnostic, params: &[ElisionFailureInfo], ) -> bool { let mut m = String::new(); @@ -1891,7 +1890,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = info; - db.span_label(span, ""); + diag.span_label(span, ""); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -1923,27 +1922,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } if len == 0 { - db.help( + diag.help( "this function's return type contains a borrowed value, \ but there is no value for it to be borrowed from", ); true } else if elided_len == 0 { - db.help( + diag.help( "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", ); true } else if elided_len == 1 { - db.help(&format!( + diag.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say which {} it is borrowed from", m )); false } else { - db.help(&format!( + diag.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say whether it is borrowed from {}", m From dfe13dbbcf6ccd503a82deb8f5a808713d0399c6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Apr 2022 01:21:35 -0700 Subject: [PATCH 7/8] only suggest removing semicolon when expr implements trait --- .../src/traits/error_reporting/suggestions.rs | 31 ++++++++----- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 2 +- .../consider-removing-last-semi.stderr | 6 +-- src/test/ui/block-result/issue-11714.stderr | 2 +- src/test/ui/block-result/issue-13428.stderr | 2 +- ...-closure-expression-remove-semicolon.fixed | 2 +- ...old-closure-expression-remove-semicolon.rs | 2 +- ...closure-expression-remove-semicolon.stderr | 2 +- ...coercion-missing-tail-expected-type.stderr | 4 +- src/test/ui/issues/issue-6458-4.stderr | 2 +- .../liveness-return-last-stmt-semi.stderr | 2 +- .../impl-trait-return-trailing-semicolon.rs | 21 ++++++++- ...mpl-trait-return-trailing-semicolon.stderr | 45 ++++++++++++++++--- src/test/ui/suggestions/issue-81098.stderr | 4 +- ...t-arm-types-as-stmt-instead-of-expr.stderr | 2 +- 15 files changed, 97 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c920c80d1bba1..ead1f0126c465 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1083,20 +1083,31 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node - && let body = hir.body(*body_id) - && let hir::ExprKind::Block(blk, _) = &body.value.kind + && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) && blk.expr.is_none() - && *trait_pred.self_ty().skip_binder().kind() == ty::Tuple(ty::List::empty()) - // FIXME(estebank): When encountering a method with a trait - // bound not satisfied in the return type with a body that has - // no return, suggest removal of semicolon on last statement. - // Once that is added, close #54771. + && trait_pred.self_ty().skip_binder().is_unit() && let Some(stmt) = blk.stmts.last() - && let hir::StmtKind::Semi(_) = stmt.kind + && let hir::StmtKind::Semi(expr) = stmt.kind + // Only suggest this if the expression behind the semicolon implements the predicate + && let Some(typeck_results) = self.in_progress_typeck_results + && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr) + && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty)) { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); + err.span_label( + expr.span, + &format!( + "this expression has type `{}`, which implements `{}`", + ty, + trait_pred.print_modifiers_and_trait_path() + ) + ); + err.span_suggestion( + self.tcx.sess.source_map().end_point(stmt.span), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable + ); return true; } false diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1cc1460750a23..f6a5243274cd2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_suggestion_short( span_semi, - "consider removing this semicolon", + "remove this semicolon", String::new(), Applicability::MachineApplicable, ); diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 99a367bfccdcd..2412dcd32f79a 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -7,7 +7,7 @@ LL | pub fn f() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; LL | "bla".to_string(); - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:8:15 @@ -18,7 +18,7 @@ LL | pub fn g() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); LL | "removeme".to_string(); - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:13:25 @@ -29,7 +29,7 @@ LL | pub fn macro_tests() -> u32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | mac!(); - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to 3 previous errors diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr index 61991643a4a56..5b8d96fd4ebe2 100644 --- a/src/test/ui/block-result/issue-11714.stderr +++ b/src/test/ui/block-result/issue-11714.stderr @@ -7,7 +7,7 @@ LL | fn blah() -> i32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to previous error diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 2f24679cc9591..a33448edff2bc 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -15,7 +15,7 @@ LL | fn bar() -> String { | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() LL | ; - | - help: consider removing this semicolon + | - help: remove this semicolon error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed index 5629d4b6e6e5f..623e917da07e8 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed @@ -7,6 +7,6 @@ fn foo() -> i32 { fn main() { let _x: i32 = { //~^ ERROR mismatched types - foo() //~ HELP consider removing this semicolon + foo() //~ HELP remove this semicolon }; } diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs index 33f11b50afca2..4974b08664945 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs @@ -7,6 +7,6 @@ fn foo() -> i32 { fn main() { let _x: i32 = { //~^ ERROR mismatched types - foo(); //~ HELP consider removing this semicolon + foo(); //~ HELP remove this semicolon }; } diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr index ab7983dc9e487..9b73ce4fee346 100644 --- a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr +++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr @@ -5,7 +5,7 @@ LL | let _x: i32 = { | ___________________^ LL | | LL | | foo(); - | | - help: consider removing this semicolon + | | - help: remove this semicolon LL | | }; | |_____^ expected `i32`, found `()` diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr index df1fb58e25a02..a4843bca58c99 100644 --- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr @@ -6,7 +6,7 @@ LL | fn plus_one(x: i32) -> i32 { | | | implicitly returns `()` as its body has no tail or `return` expression LL | x + 1; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:8:13 @@ -16,7 +16,7 @@ LL | fn foo() -> Result { | | | implicitly returns `()` as its body has no tail or `return` expression LL | Ok(1); - | - help: consider removing this semicolon + | - help: remove this semicolon | = note: expected enum `Result` found unit type `()` diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index 0cf82d37d5d0b..d6e74d10e03c9 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -6,7 +6,7 @@ LL | fn foo(b: bool) -> Result { | | | implicitly returns `()` as its body has no tail or `return` expression LL | Err("bar".to_string()); - | - help: consider removing this semicolon + | - help: remove this semicolon | = note: expected enum `Result` found unit type `()` diff --git a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr index 0b33d8d0a2b23..82d136bd318d8 100644 --- a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr +++ b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -14,7 +14,7 @@ LL | fn bar(x: u32) -> u32 { | | | implicitly returns `()` as its body has no tail or `return` expression LL | x * 2; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:13:19 diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs index cad7d76c6ab5f..5a17c108ccc13 100644 --- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs @@ -1,8 +1,25 @@ trait Bar {} -impl Bar for u8 {} + +impl Bar for i32 {} + +struct Qux; + +impl Bar for Qux {} + fn foo() -> impl Bar { - 5; //~^ ERROR the trait bound `(): Bar` is not satisfied + //~^ ERROR the trait bound `(): Bar` is not satisfied + //~| ERROR the trait bound `(): Bar` is not satisfied + //~| HELP the following other types implement trait `Bar`: + 5; + //~^ HELP remove this semicolon +} + +fn bar() -> impl Bar { + //~^ ERROR the trait bound `(): Bar` is not satisfied //~| ERROR the trait bound `(): Bar` is not satisfied + //~| HELP the following other types implement trait `Bar`: + //~| HELP the following other types implement trait `Bar`: + ""; } fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr index 0de765588e5b7..43f8b7c66f07a 100644 --- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -1,23 +1,58 @@ error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13 + --> $DIR/impl-trait-return-trailing-semicolon.rs:9:13 | LL | fn foo() -> impl Bar { | ^^^^^^^^ the trait `Bar` is not implemented for `()` +... LL | 5; - | - consider removing this semicolon + | -- help: remove this semicolon + | | + | this expression has type `{integer}`, which implements `Bar` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/impl-trait-return-trailing-semicolon.rs:3:22 + --> $DIR/impl-trait-return-trailing-semicolon.rs:9:22 | LL | fn foo() -> impl Bar { | ______________________^ +LL | | +LL | | +LL | | LL | | 5; LL | | LL | | } | |_^ the trait `Bar` is not implemented for `()` | - = help: the trait `Bar` is implemented for `u8` + = help: the following other types implement trait `Bar`: + Qux + i32 + +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:17:13 + | +LL | fn bar() -> impl Bar { + | ^^^^^^^^ the trait `Bar` is not implemented for `()` + | + = help: the following other types implement trait `Bar`: + Qux + i32 + +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:17:22 + | +LL | fn bar() -> impl Bar { + | ______________________^ +LL | | +LL | | +LL | | +LL | | +LL | | ""; +LL | | } + | |_^ the trait `Bar` is not implemented for `()` + | + = help: the following other types implement trait `Bar`: + Qux + i32 -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr index d62526442e9af..8665f2e70a85c 100644 --- a/src/test/ui/suggestions/issue-81098.stderr +++ b/src/test/ui/suggestions/issue-81098.stderr @@ -27,7 +27,9 @@ LL | fn ok() -> impl core::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter LL | LL | 1; - | - consider removing this semicolon + | -- help: remove this semicolon + | | + | this expression has type `{integer}`, which implements `std::fmt::Display` | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr index 7dce97468b6dd..60f423a116317 100644 --- a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr +++ b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr @@ -7,7 +7,7 @@ LL | fn not_all_paths(a: &str) -> u32 { | implicitly returns `()` as its body has no tail or `return` expression ... LL | }; - | - help: consider removing this semicolon + | - help: remove this semicolon error[E0308]: `match` arms have incompatible types --> $DIR/match-with-different-arm-types-as-stmt-instead-of-expr.rs:26:14 From 7f54d68f26783afb5b05ef1f49f655119313fcad Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 10 Apr 2022 17:36:08 +1000 Subject: [PATCH 8/8] Add a note for unsatisfied `~const Drop` bounds --- .../src/traits/error_reporting/mod.rs | 7 +++++ src/librustdoc/clean/mod.rs | 12 +------ src/test/rustdoc/rfc-2632-const-trait-impl.rs | 31 +++++++++++++++---- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9998c5bb087e1..b1d570f2ed420 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -439,6 +439,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait() + && predicate_is_const + { + err.note("`~const Drop` was renamed to `~const Destruct`"); + err.note("See for more details"); + } + let explanation = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e6ef3c26e290a..85a3e05e8b213 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -302,23 +302,13 @@ impl<'a> Clean> for ty::Predicate<'a> { impl<'a> Clean> for ty::PolyTraitPredicate<'a> { fn clean(&self, cx: &mut DocContext<'_>) -> Option { - // `T: ~const Drop` is not equivalent to `T: Drop`, and we don't currently document `~const` bounds - // because of its experimental status, so just don't show these. // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. if self.skip_binder().constness == ty::BoundConstness::ConstIfConst - && [cx.tcx.lang_items().drop_trait(), cx.tcx.lang_items().destruct_trait()] - .iter() - .any(|tr| *tr == Some(self.skip_binder().def_id())) + && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() { return None; } - #[cfg(bootstrap)] - { - // FIXME: remove `lang_items().drop_trait()` from above logic, - // as well as the comment about `~const Drop` because it was renamed to `Destruct`. - } - let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); Some(WherePredicate::BoundPredicate { ty: poly_trait_ref.skip_binder().self_ty().clean(cx), diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs index c5353c4d5b523..f9173feeeec81 100644 --- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs +++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs @@ -1,5 +1,5 @@ // Test that we do not currently display `~const` in rustdoc -// as that syntax is currently provisional; `~const Drop` has +// as that syntax is currently provisional; `~const Destruct` has // no effect on stable code so it should be hidden as well. // // To future blessers: make sure that `const_trait_impl` is @@ -8,6 +8,8 @@ #![feature(const_trait_impl)] #![crate_name = "foo"] +use std::marker::Destruct; + pub struct S(T); // @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const' @@ -20,22 +22,36 @@ pub trait Tr { // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone' #[default_method_body_is_const] - fn a() where Option: ~const Clone {} + fn a() + where + Option: ~const Clone + ~const Destruct, + { + } } // @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const' // @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone' // @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const' // @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone' -impl const Tr for T where Option: ~const Clone { - fn a() where Option: ~const Clone {} +impl const Tr for T +where + Option: ~const Clone + ~const Destruct, +{ + fn a() + where + Option: ~const Clone + ~const Destruct, + { + } } // @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const' // @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone' // @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const' // @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone' -pub const fn foo() where Option: ~const Clone { +pub const fn foo() +where + Option: ~const Clone + ~const Destruct, +{ F::a() } @@ -44,7 +60,10 @@ impl S { // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone' // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone' - pub const fn foo() where B: ~const Clone { + pub const fn foo() + where + B: ~const Clone + ~const Destruct, + { B::a() } }