From 28b6d2c28259769c31649f6b8c8497576adc6a76 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Mar 2022 11:24:52 +0100 Subject: [PATCH 1/7] Fix incorrect auto trait displayed in rustdoc --- compiler/rustc_trait_selection/src/traits/select/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a1a8497859d45..c3c5ae92039ff 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1270,7 +1270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the master cache. Since coherence executes pretty quickly, // it's not worth going to more trouble to increase the // hit-rate, I don't think. - if self.intercrate { + if self.intercrate || self.allow_negative_impls { return false; } @@ -1287,7 +1287,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // mode, so don't do any caching. In particular, we might // re-use the same `InferCtxt` with both an intercrate // and non-intercrate `SelectionContext` - if self.intercrate { + if self.intercrate || self.allow_negative_impls { return None; } let tcx = self.tcx(); From 7c53ae09a85b79b3e20a85771a68e8e63aec265c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Mar 2022 11:27:18 +0100 Subject: [PATCH 2/7] Add test to ensure auto-traits are respecting constraints --- src/test/rustdoc/auto-trait-not-send.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/test/rustdoc/auto-trait-not-send.rs diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs new file mode 100644 index 0000000000000..7bd4f6dbd8ce3 --- /dev/null +++ b/src/test/rustdoc/auto-trait-not-send.rs @@ -0,0 +1,8 @@ +#![crate_name = "foo"] + +// @has 'foo/struct.Foo.html' +// @has - '//*[@id="impl-Send"]' 'impl !Send for Foo' +// @has - '//*[@id="impl-Sync"]' 'impl !Sync for Foo' +pub struct Foo(*const i8); +pub trait Whatever: Send {} +impl Whatever for T {} From f93a146433a1b724065672dbad54e557c1e70a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 18:58:54 -0400 Subject: [PATCH 3/7] interpret/memory: simplify check_and_deref_ptr --- .../rustc_const_eval/src/interpret/memory.rs | 20 +++++-------------- src/test/ui/consts/const-deref-ptr.stderr | 2 +- .../const-eval/const_raw_ptr_ops2.stderr | 4 ++-- .../const-eval/ub-wide-ptr.64bit.stderr | 2 +- .../mut_ref_in_final_dynamic_check.stderr | 2 +- src/test/ui/consts/offset_ub.stderr | 4 ++-- src/test/ui/error-codes/E0396-fixed.stderr | 2 +- 7 files changed, 13 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6397fcaaf8d10..871b7578abdc3 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -427,22 +427,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } - // Extract from the pointer an `Option` and an offset, which is relative to the - // allocation or (if that is `None`) an absolute address. - let ptr_or_addr = if size.bytes() == 0 { - // Let's see what we can do, but don't throw errors if there's nothing there. - self.ptr_try_get_alloc(ptr) - } else { - // A "real" access, we insist on getting an `AllocId`. - Ok(self.ptr_get_alloc(ptr)?) - }; - Ok(match ptr_or_addr { + Ok(match self.ptr_try_get_alloc(ptr) { Err(addr) => { - // No memory is actually being accessed. - debug_assert!(size.bytes() == 0); - // Must be non-null. - if addr == 0 { - throw_ub!(DanglingIntPointer(0, msg)) + // We couldn't get a proper allocation. This is only okay if the access size is 0, + // and the address is not null. + if size.bytes() > 0 || addr == 0 { + throw_ub!(DanglingIntPointer(addr, msg)); } // Must be aligned. if let Some(align) = align { diff --git a/src/test/ui/consts/const-deref-ptr.stderr b/src/test/ui/consts/const-deref-ptr.stderr index 316843889c683..7606afdc4ff6c 100644 --- a/src/test/ui/consts/const-deref-ptr.stderr +++ b/src/test/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0xdeadbeef is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef is not a valid pointer error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr index 44fa437806b15..df8a80be72cb5 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ 0x2a is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a is not a valid pointer error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ 0x2c is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c is not a valid pointer error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index ff850d2dbe9a0..ded007ce28139 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:135:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:139:5 diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 7d6716787aad5..9c1733e827d19 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed LL | Some(&mut *(42 as *mut i32)) | ^^^^^^^^^^^^^^^^^^^^^^ | | - | 0x2a is not a valid pointer + | dereferencing pointer failed: 0x2a is not a valid pointer | inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10 ... LL | const A: Option<&mut i32> = helper(); diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 237950a30e841..e774e38931377 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -130,7 +130,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) as *mut T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | 0x1 is not a valid pointer + | pointer arithmetic failed: 0x1 is not a valid pointer | inside `ptr::mut_ptr::::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:19:42 @@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | 0x7f..f is not a valid pointer + | pointer arithmetic failed: 0x7f..f is not a valid pointer | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:25:47 diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr index 91997fcf0f901..3eb291f0f7014 100644 --- a/src/test/ui/error-codes/E0396-fixed.stderr +++ b/src/test/ui/error-codes/E0396-fixed.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0396-fixed.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ 0x5f3759df is not a valid pointer + | ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df is not a valid pointer error: aborting due to previous error From c8cbd3d03c92ec903a964b67dd90aa2cc6d78f2c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 21 Feb 2022 21:26:37 -0800 Subject: [PATCH 4/7] better errors when a Copy impl is not coherent --- .../rustc_trait_selection/src/traits/misc.rs | 4 +- .../rustc_typeck/src/coherence/builtin.rs | 36 ++++++++++++++++- src/test/ui/coherence/deep-bad-copy-reason.rs | 40 +++++++++++++++++++ .../ui/coherence/deep-bad-copy-reason.stderr | 18 +++++++++ src/test/ui/union/union-copy.stderr | 6 +++ 5 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/coherence/deep-bad-copy-reason.rs create mode 100644 src/test/ui/coherence/deep-bad-copy-reason.stderr diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 08308253ced5f..b83b0bf1ca52e 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -11,7 +11,7 @@ use crate::traits::error_reporting::InferCtxtExt; #[derive(Clone)] pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<&'tcx ty::FieldDef>), + InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>), NotAnAdt, HasDestructor, } @@ -67,7 +67,7 @@ pub fn can_type_implement_copy<'tcx>( match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { - infringing.push(field); + infringing.push((field, ty)); } } Err(errors) => { diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index ef59df0dc88f3..3135e9996ab8b 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -91,8 +91,40 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { E0204, "the trait `Copy` may not be implemented for this type" ); - for span in fields.iter().map(|f| tcx.def_span(f.did)) { - err.span_label(span, "this field does not implement `Copy`"); + for (field, ty) in fields { + let field_span = tcx.def_span(field.did); + err.span_label(field_span, "this field does not implement `Copy`"); + // Spin up a new FulfillmentContext, so we can get the _precise_ reason + // why this field does not implement Copy. This is useful because sometimes + // it is not immediately clear why Copy is not implemented for a field, since + // all we point at is the field itself. + tcx.infer_ctxt().enter(|infcx| { + let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions(); + fulfill_cx.register_bound( + &infcx, + param_env, + ty, + tcx.lang_items().copy_trait().unwrap(), + traits::ObligationCause::dummy_with_span(field_span), + ); + for error in fulfill_cx.select_all_or_error(&infcx) { + let error_predicate = error.obligation.predicate; + // Only note if it's not the root obligation, otherwise it's trivial and + // should be self-explanatory (i.e. a field literally doesn't implement Copy). + + // FIXME: This error could be more descriptive, especially if the error_predicate + // contains a foreign type or if it's a deeply nested type... + if error_predicate != error.root_obligation.predicate { + err.span_note( + error.obligation.cause.span, + &format!( + "the `Copy` impl for `{}` requires that `{}`", + ty, error_predicate + ), + ); + } + } + }); } err.emit(); } diff --git a/src/test/ui/coherence/deep-bad-copy-reason.rs b/src/test/ui/coherence/deep-bad-copy-reason.rs new file mode 100644 index 0000000000000..80bbe387ac719 --- /dev/null +++ b/src/test/ui/coherence/deep-bad-copy-reason.rs @@ -0,0 +1,40 @@ +#![feature(extern_types)] + +extern "Rust" { + type OpaqueListContents; +} + +pub struct ListS { + len: usize, + data: [T; 0], + opaque: OpaqueListContents, +} + +pub struct Interned<'a, T>(&'a T); + +impl<'a, T> Clone for Interned<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for Interned<'a, T> {} + +pub struct List<'tcx, T>(Interned<'tcx, ListS>); +//~^ NOTE this field does not implement `Copy` +//~| NOTE the `Copy` impl for `Interned<'tcx, ListS>` requires that `OpaqueListContents: Sized` + +impl<'tcx, T> Clone for List<'tcx, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'tcx, T> Copy for List<'tcx, T> {} +//~^ ERROR the trait `Copy` may not be implemented for this type + +fn assert_is_copy() {} + +fn main() { + assert_is_copy::>(); +} diff --git a/src/test/ui/coherence/deep-bad-copy-reason.stderr b/src/test/ui/coherence/deep-bad-copy-reason.stderr new file mode 100644 index 0000000000000..295538cee6096 --- /dev/null +++ b/src/test/ui/coherence/deep-bad-copy-reason.stderr @@ -0,0 +1,18 @@ +error[E0204]: the trait `Copy` may not be implemented for this type + --> $DIR/deep-bad-copy-reason.rs:33:15 + | +LL | pub struct List<'tcx, T>(Interned<'tcx, ListS>); + | ------------------------ this field does not implement `Copy` +... +LL | impl<'tcx, T> Copy for List<'tcx, T> {} + | ^^^^ + | +note: the `Copy` impl for `Interned<'tcx, ListS>` requires that `OpaqueListContents: Sized` + --> $DIR/deep-bad-copy-reason.rs:23:26 + | +LL | pub struct List<'tcx, T>(Interned<'tcx, ListS>); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index 0f47bae7f0fed..279808dd55bb4 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -6,6 +6,12 @@ LL | a: std::mem::ManuallyDrop ... LL | impl Copy for W {} | ^^^^ + | +note: the `Copy` impl for `ManuallyDrop` requires that `String: Copy` + --> $DIR/union-copy.rs:8:5 + | +LL | a: std::mem::ManuallyDrop + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From a76e5b1882f78c250a3f7338d12c559029949d73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 22:19:50 -0400 Subject: [PATCH 5/7] bless 32bit --- src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index 2a489e8b69c8f..f8c9dca566b93 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:135:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:139:5 From bdb4b1e923d7219690135490af5f63859a7086bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 22 Mar 2022 19:25:43 -0700 Subject: [PATCH 6/7] remove [async output] from impl Future --- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 36 ++++++++++--------- ...ync-block-control-flow-static-semantics.rs | 2 +- ...block-control-flow-static-semantics.stderr | 4 +-- src/test/ui/async-await/generator-desc.stderr | 4 +-- .../issue-67252-unnamed-future.stderr | 2 +- src/test/ui/async-await/issue-68112.stderr | 4 +-- .../issue-65436-raw-ptr-not-send.stderr | 2 +- .../partial-drop-partial-reinit.stderr | 2 +- src/test/ui/chalkify/bugs/async.stderr | 2 +- .../bugs/issue-89008.stderr | 2 +- src/test/ui/impl-trait/issue-55872-2.rs | 2 +- src/test/ui/impl-trait/issue-55872-2.stderr | 4 +-- .../ui/impl-trait/issues/issue-78722.stderr | 2 +- .../pattern/non-structural-match-types.stderr | 2 +- .../expected-boxed-future-isnt-pinned.stderr | 2 +- 16 files changed, 39 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a575f27ad3860..fa2dad5ce25f0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -41,6 +41,7 @@ #![feature(new_uninit)] #![feature(nll)] #![feature(once_cell)] +#![feature(let_chains)] #![feature(let_else)] #![feature(min_specialization)] #![feature(trusted_len)] diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 00cb9907d95a5..5cfd9a5edfb19 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -896,44 +896,48 @@ pub trait PrettyPrinter<'tcx>: ); if !generics.is_empty() || !assoc_items.is_empty() { - p!("<"); let mut first = true; for ty in generics { - if !first { + if first { + p!("<"); + first = false; + } else { p!(", "); } p!(print(trait_ref.rebind(*ty))); - first = false; } for (assoc_item_def_id, term) in assoc_items { - if !first { + // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks + if let Some(ty) = term.skip_binder().ty() && + let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = ty.kind() && + Some(*item_def_id) == self.tcx().lang_items().generator_return() { + continue; + } + + if first { + p!("<"); + first = false; + } else { p!(", "); } + p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name)); match term.skip_binder() { Term::Ty(ty) => { - // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks - if matches!( - ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. }) - if Some(*item_def_id) == self.tcx().lang_items().generator_return() - ) { - p!("[async output]") - } else { - p!(print(ty)) - } + p!(print(ty)) } Term::Const(c) => { p!(print(c)); } }; - - first = false; } - p!(">"); + if !first { + p!(">"); + } } first = false; diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index e3832767203bb..f6c6f90a39378 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving ` as Future>::Output == ()` + //~^ ERROR type mismatch resolving `::Output == ()` } fn no_break_in_async_block() { diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index fe864c65b7cf2..919904ce3b6a2 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -31,7 +31,7 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: type mismatch resolving ` as Future>::Output == ()` +error[E0271]: type mismatch resolving `::Output == ()` --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future = █ @@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving ` as Future>::Output == ()` +error[E0271]: type mismatch resolving `::Output == ()` --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr index 4a45d8d2a9423..79834ed7ec1a8 100644 --- a/src/test/ui/async-await/generator-desc.stderr +++ b/src/test/ui/async-await/generator-desc.stderr @@ -46,8 +46,8 @@ LL | pub const fn from_generator(gen: T) -> impl Future | the expected opaque type | the found opaque type | - = note: expected opaque type `impl Future` (`async` closure body) - found opaque type `impl Future` (`async` closure body) + = note: expected opaque type `impl Future` (`async` closure body) + found opaque type `impl Future` (`async` closure body) error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index f32e074d75d62..19b90f1d878c7 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | spawn(async { | ^^^^^ future created by async block is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()` + = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:16 | diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index a8c2ebe12fa18..9682a7055e93c 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -44,13 +44,13 @@ LL | require_send(send_fut); = note: required because of the requirements on the impl of `Send` for `Arc>` = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]` = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>` - = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future>>` = note: required because it appears within the type `impl Future>>` = note: required because it appears within the type `{ResumeTy, impl Future>>, (), i32, Ready}` = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]` = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>` - = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` note: required by a bound in `require_send` --> $DIR/issue-68112.rs:11:25 | diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index b4d2006480390..cf023bd0f9705 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(async { | ^^^^^^^^^^^ future created by async block is not `Send` | - = help: within `impl Future`, the trait `Send` is not implemented for `*const u8` + = help: within `impl Future`, the trait `Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await --> $DIR/issue-65436-raw-ptr-not-send.rs:14:35 | diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr index 2097642eb24ab..a83b1d660c34c 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr @@ -14,7 +14,7 @@ LL | async fn foo() { = note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future, ()}` = note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]` = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>` - = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future` note: required by a bound in `gimme_send` --> $DIR/partial-drop-partial-reinit.rs:10:18 diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr index 7a86561bcb9ce..3d62f059f37cd 100644 --- a/src/test/ui/chalkify/bugs/async.stderr +++ b/src/test/ui/chalkify/bugs/async.stderr @@ -28,7 +28,7 @@ note: required by a bound in `from_generator` LL | T: Generator, | ^^^^^^^^^^ required by this bound in `from_generator` -error[E0280]: the requirement ` as Future>::Output == u32` is not satisfied +error[E0280]: the requirement `::Output == u32` is not satisfied --> $DIR/async.rs:7:25 | LL | async fn foo(x: u32) -> u32 { diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr index c2687ca540153..3e607d4004e85 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Future>::Output == impl Stream` +error[E0271]: type mismatch resolving `::Output == impl Stream` --> $DIR/issue-89008.rs:39:43 | LL | type LineStream<'a, Repr> = impl Stream; diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs index 17a6a85787442..1841d7b3d372d 100644 --- a/src/test/ui/impl-trait/issue-55872-2.rs +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -12,7 +12,7 @@ impl Bar for S { type E = impl std::marker::Copy; fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - //~| ERROR the trait bound `impl Future: Copy` is not satisfied + //~| ERROR the trait bound `impl Future: Copy` is not satisfied async {} } } diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index b76b564dfb139..76122e60c4cb6 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `impl Future: Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/issue-55872-2.rs:13:20 | LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `impl Future` + | ^^^^^^^ the trait `Copy` is not implemented for `impl Future` error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias --> $DIR/issue-55872-2.rs:13:28 diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index 130678de2370c..86bde9a0cddab 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -15,7 +15,7 @@ LL | pub const fn from_generator(gen: T) -> impl Future | ------------------------------- the found opaque type | = note: expected opaque type `impl Future` - found opaque type `impl Future` + found opaque type `impl Future` = note: distinct uses of `impl Trait` result in different opaque types error: aborting due to previous error diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr index 31168e29eb82f..91fed81eaeff6 100644 --- a/src/test/ui/pattern/non-structural-match-types.stderr +++ b/src/test/ui/pattern/non-structural-match-types.stderr @@ -4,7 +4,7 @@ error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used LL | const { || {} } => {}, | ^^^^^^^^^^^^^^^ -error: `impl Future` cannot be used in patterns +error: `impl Future` cannot be used in patterns --> $DIR/non-structural-match-types.rs:12:9 | LL | const { async {} } => {}, diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 550ed4b03b039..7ef4895249cec 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -81,7 +81,7 @@ LL | pub const fn from_generator(gen: T) -> impl Future | ------------------------------- the found opaque type | = note: expected struct `Pin + Send + 'static)>>` - found opaque type `impl Future` + found opaque type `impl Future` help: you need to pin and box this expression | LL ~ Box::pin(async { From 925857d8dcd88e243125bf8a7467c9f055ae958e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 23 Mar 2022 22:54:02 +0900 Subject: [PATCH 7/7] stop emitting E0026 for struct enums with underscores --- compiler/rustc_typeck/src/check/pat.rs | 6 +++-- ...uct-enum-ignoring-field-with-underscore.rs | 12 ++++++++++ ...enum-ignoring-field-with-underscore.stderr | 24 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs create mode 100644 src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index c16be38d5fc3d..1c4fbbbb9bfaf 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -17,7 +17,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, MultiSpan, DUMMY_SP}; use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::{ObligationCause, Pattern}; @@ -1275,7 +1275,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|(_, ident)| !used_fields.contains_key(ident)) .collect::>(); - let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { + let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) + && !inexistent_fields.iter().any(|field| field.name == kw::Underscore) + { Some(self.error_inexistent_fields( adt.variant_descr(), &inexistent_fields, diff --git a/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs new file mode 100644 index 0000000000000..c30b8a1e1f1a7 --- /dev/null +++ b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs @@ -0,0 +1,12 @@ +enum Foo { + Bar { bar: bool }, + Other, +} + +fn main() { + let foo = Some(Foo::Other); + + if let Some(Foo::Bar {_}) = foo {} + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR pattern does not mention field `bar` [E0027] +} diff --git a/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr new file mode 100644 index 0000000000000..16f751444a558 --- /dev/null +++ b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:27 + | +LL | if let Some(Foo::Bar {_}) = foo {} + | ^ expected identifier, found reserved identifier + +error[E0027]: pattern does not mention field `bar` + --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:17 + | +LL | if let Some(Foo::Bar {_}) = foo {} + | ^^^^^^^^^^^^ missing field `bar` + | +help: include the missing field in the pattern + | +LL | if let Some(Foo::Bar {_, bar }) = foo {} + | ~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | if let Some(Foo::Bar {_, .. }) = foo {} + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0027`.