From 3811ddc7b7ade2df4aa8f58ceddcad03208999de Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Mon, 9 Jun 2025 20:15:01 -0700 Subject: [PATCH 1/6] add structural_init feature --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index efd8bde71d76d..61f54f1ed316d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -241,6 +241,8 @@ declare_features! ( (unstable, sized_hierarchy, "1.89.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. (internal, staged_api, "1.0.0", None), + /// FIXME: needs description and tracking issue. + (unstable, structural_init, "CURRENT_RUSTC_VERSION", None), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), /// Helps with formatting for `group_imports = "StdExternalCrate"`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 09f01d8704e2a..bd862e7810468 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2099,6 +2099,7 @@ symbols! { struct_field_attributes, struct_inherit, struct_variant, + structural_init, structural_match, structural_peq, sub, From 984b65a5f5efecd699444cecbade24385a9acd5f Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:31:33 -0700 Subject: [PATCH 2/6] it works for structs --- compiler/rustc_borrowck/src/lib.rs | 58 +++++++++++++++++-- .../rustc_mir_dataflow/src/move_paths/mod.rs | 6 +- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 82b300dcb17d9..e374f24e630ed 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1946,6 +1946,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { debug!("check_if_full_path_is_moved place: {:?}", place_span.0); let (prefix, mpi) = self.move_path_closest_to(place_span.0); + + if prefix == place_span.0 && !self.forbid_structural_initialization(mpi) { + return; + } + if maybe_uninits.contains(mpi) { self.report_use_of_moved_or_uninitialized( location, @@ -2059,9 +2064,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0); if let Some(mpi) = self.move_path_for_place(place_span.0) { - let uninit_mpi = self - .move_data - .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)); + let uninit_mpi = self.move_data.find_in_move_path_or_its_descendants(mpi, |mpi| { + maybe_uninits.contains(mpi) && self.forbid_structural_initialization(mpi) + }); if let Some(uninit_mpi) = uninit_mpi { self.report_use_of_moved_or_uninitialized( @@ -2075,6 +2080,51 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } + fn forbid_structural_initialization(&self, mpi: MovePathIndex) -> bool { + // FIXME: cache this + + let tcx = self.infcx.tcx; + + if !tcx.features().structural_init() { + return true; + } + + let path = &self.move_data.move_paths[mpi]; + + let ty = path.place.ty(self.body(), tcx).ty; + + let ty::Adt(adt, _) = ty.kind() else { + return true; + }; + + if !adt.is_struct() { + return true; + } + + let variant = adt.non_enum_variant(); + + if variant.field_list_has_applicable_non_exhaustive() { + return true; + } + + // FIXME: destructors? + + // A structurally initialized ADT is "uninit" but all of it's fields are init. + // This means all of it's fields must have MovePaths + // because fields that are never written to will not have MovePaths. + // Without this check, we may not detect that unwritten fields are uninit. + for field in variant.fields.indices() { + // FIXME WrapUnsafeBinder? + if self.move_data.rev_lookup.project(mpi, ProjectionElem::Field(field, ())).is_none() { + return true; + } + } + + debug!("sucess!!"); + + false + } + /// Currently MoveData does not store entries for all places in /// the input MIR. For example it will currently filter out /// places that are Copy; thus we do not track places of shared @@ -2164,7 +2214,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. - ty::Adt(..) | ty::Tuple(..) => { + ty::Adt(..) | ty::Tuple(..) if !tcx.features().structural_init() => { check_parent_of_field(self, location, place_base, span, state); } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 18985ba0da259..10d54116da9f2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -324,7 +324,7 @@ impl<'tcx> MovePathLookup<'tcx> { }; for (_, elem) in self.un_derefer.iter_projections(place) { - if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + if let Some(subpath) = self.project(result, elem.lift()) { result = subpath; } else { return LookupResult::Parent(Some(result)); @@ -346,6 +346,10 @@ impl<'tcx> MovePathLookup<'tcx> { ) -> impl DoubleEndedIterator { self.locals.iter_enumerated().filter_map(|(l, &idx)| Some((l, idx?))) } + + pub fn project(&self, mpi: MovePathIndex, elem: ProjectionKind) -> Option { + self.projections.get(&(mpi, elem)).copied() + } } impl<'tcx> MoveData<'tcx> { From f6901c80d973198a5278570f3510040290722f53 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:47:15 -0700 Subject: [PATCH 3/6] and now for tuples too --- compiler/rustc_borrowck/src/lib.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e374f24e630ed..f2a5fd0ef1078 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1992,6 +1992,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { if (from..to).contains(offset) { let uninit_child = self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| { + // FIXME(structural_init) you can't partially init an array element, right? maybe_uninits.contains(mpi) }); @@ -2091,37 +2092,34 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let path = &self.move_data.move_paths[mpi]; - let ty = path.place.ty(self.body(), tcx).ty; + let field_count = match path.place.ty(self.body(), tcx).ty.kind() { + ty::Adt(adt, _) if adt.is_struct() => { + let variant = adt.non_enum_variant(); - let ty::Adt(adt, _) = ty.kind() else { - return true; - }; - - if !adt.is_struct() { - return true; - } + if variant.field_list_has_applicable_non_exhaustive() { + return true; + } - let variant = adt.non_enum_variant(); + variant.fields.len() + } + ty::Tuple(tys) => tys.len(), - if variant.field_list_has_applicable_non_exhaustive() { - return true; - } + _ => return true, + }; // FIXME: destructors? - // A structurally initialized ADT is "uninit" but all of it's fields are init. + // A structurally initialized type is "uninit" but all of it's fields are init. // This means all of it's fields must have MovePaths // because fields that are never written to will not have MovePaths. // Without this check, we may not detect that unwritten fields are uninit. - for field in variant.fields.indices() { + for field in (0..field_count).map(FieldIdx::from_usize) { // FIXME WrapUnsafeBinder? if self.move_data.rev_lookup.project(mpi, ProjectionElem::Field(field, ())).is_none() { return true; } } - debug!("sucess!!"); - false } From de936c712f5dc68ba9f398a00af23cb0867ce0ce Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 9 Jul 2025 01:13:21 -0700 Subject: [PATCH 4/6] move & rename strucural init tests changes are seperate so git will recognize as a move --- .../structural_init.rs} | 0 .../structural_init.stable.stderr} | 0 .../structural_init_invalid.feature.stderr} | 0 .../structural_init_invalid.rs} | 0 .../structural_init_invalid.stable.stderr | 64 +++++++++++++++++++ 5 files changed, 64 insertions(+) rename tests/ui/{nll/issue-21232-partial-init-and-use.rs => borrowck/structural_init.rs} (100%) rename tests/ui/{nll/issue-21232-partial-init-and-use.stderr => borrowck/structural_init.stable.stderr} (100%) rename tests/ui/{nll/issue-21232-partial-init-and-erroneous-use.stderr => borrowck/structural_init_invalid.feature.stderr} (100%) rename tests/ui/{nll/issue-21232-partial-init-and-erroneous-use.rs => borrowck/structural_init_invalid.rs} (100%) create mode 100644 tests/ui/borrowck/structural_init_invalid.stable.stderr diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.rs b/tests/ui/borrowck/structural_init.rs similarity index 100% rename from tests/ui/nll/issue-21232-partial-init-and-use.rs rename to tests/ui/borrowck/structural_init.rs diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/borrowck/structural_init.stable.stderr similarity index 100% rename from tests/ui/nll/issue-21232-partial-init-and-use.stderr rename to tests/ui/borrowck/structural_init.stable.stderr diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/tests/ui/borrowck/structural_init_invalid.feature.stderr similarity index 100% rename from tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr rename to tests/ui/borrowck/structural_init_invalid.feature.stderr diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/tests/ui/borrowck/structural_init_invalid.rs similarity index 100% rename from tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs rename to tests/ui/borrowck/structural_init_invalid.rs diff --git a/tests/ui/borrowck/structural_init_invalid.stable.stderr b/tests/ui/borrowck/structural_init_invalid.stable.stderr new file mode 100644 index 0000000000000..63f230be7d4b3 --- /dev/null +++ b/tests/ui/borrowck/structural_init_invalid.stable.stderr @@ -0,0 +1,64 @@ +error[E0381]: assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5 + | +LL | let d: D; + | - binding declared here but left uninitialized +LL | d.x = 10; + | ^^^^^^^^ `d` assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0381]: assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5 + | +LL | let mut d: D; + | ----- binding declared here but left uninitialized +LL | d.x = 10; + | ^^^^^^^^ `d` assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0382]: assign of moved value: `d` + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5 + | +LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; + | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait +LL | drop(d); + | - value moved here +LL | d.x = 10; + | ^^^^^^^^ value assigned here after move + +error[E0381]: partially assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5 + | +LL | let d: D; + | - binding declared here but left uninitialized +LL | d.s.y = 20; + | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0381]: partially assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5 + | +LL | let mut d: D; + | ----- binding declared here but left uninitialized +LL | d.s.y = 20; + | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0382]: assign to part of moved value: `d` + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5 + | +LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; + | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait +LL | drop(d); + | - value moved here +LL | d.s.y = 20; + | ^^^^^^^^^^ value partially assigned here after move + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. From 0e01218c836a6cc0ac192b061c82d5ffa983f22a Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:32:08 -0700 Subject: [PATCH 5/6] structural init tests with incorrect error output though --- src/tools/tidy/src/issues.txt | 2 - tests/ui/borrowck/structural_init.rs | 71 ++++++++++--------- .../ui/borrowck/structural_init.stable.stderr | 58 +++++++-------- .../structural_init_invalid.feature.stderr | 24 +++---- tests/ui/borrowck/structural_init_invalid.rs | 16 +++-- .../structural_init_invalid.stable.stderr | 12 ++-- 6 files changed, 93 insertions(+), 90 deletions(-) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index cac4dba2b49d7..54c49158c41ad 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2971,8 +2971,6 @@ ui/nll/issue-112604-closure-output-normalize.rs ui/nll/issue-16223.rs ui/nll/issue-21114-ebfull.rs ui/nll/issue-21114-kixunil.rs -ui/nll/issue-21232-partial-init-and-erroneous-use.rs -ui/nll/issue-21232-partial-init-and-use.rs ui/nll/issue-22323-temp-destruction.rs ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs ui/nll/issue-27282-move-match-input-into-guard.rs diff --git a/tests/ui/borrowck/structural_init.rs b/tests/ui/borrowck/structural_init.rs index ad3eb248351d4..76e7c27f6b431 100644 --- a/tests/ui/borrowck/structural_init.rs +++ b/tests/ui/borrowck/structural_init.rs @@ -1,16 +1,17 @@ +//@ revisions: stable feature +//@[feature] run-pass +// gate-test-structural_init +#![cfg_attr(feature, feature(structural_init))] + // This test enumerates various cases of interest for partial // [re]initialization of ADTs and tuples. // -// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987. -// -// All of tests in this file are expected to change from being -// rejected, at least under NLL (by rust-lang/rust#54986) to being -// **accepted** when rust-lang/rust#54987 is implemented. -// (That's why there are assertions in the code.) +// All of the tests in this file should fail to compile normally +// and compile with `feature(structural_init)`. // -// See issue-21232-partial-init-and-erroneous-use.rs for cases of -// tests that are meant to continue failing to compile once -// rust-lang/rust#54987 is implemented. +// See structural_init_invalid.rs for cases of +// tests that are meant to continue failing to compile +// with `feature(structural_init)`. struct S { x: u32, @@ -37,11 +38,13 @@ fn borrow_t(t: &T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); } fn move_t(t: T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); } struct Q { + #[allow(dead_code)] v: u32, r: R, } struct R { + #[allow(dead_code)] w: u32, f: F, } @@ -94,65 +97,65 @@ macro_rules! use_part { fn test_0000_local_fully_init_and_use_struct() { let s: S; - s.x = 10; s.y = Box::new(20); //~ ERROR E0381 + s.x = 10; s.y = Box::new(20); //[stable]~ ERROR E0381 use_fully!(struct s); } fn test_0001_local_fully_init_and_use_tuple() { let t: T; - t.0 = 10; t.1 = Box::new(20); //~ ERROR E0381 + t.0 = 10; t.1 = Box::new(20); //[stable]~ ERROR E0381 use_fully!(tuple t); } fn test_0010_local_fully_reinit_and_use_struct() { let mut s: S = S::new(); drop(s); s.x = 10; s.y = Box::new(20); - //~^ ERROR assign to part of moved value: `s` [E0382] + //[stable]~^ ERROR assign to part of moved value: `s` [E0382] use_fully!(struct s); } fn test_0011_local_fully_reinit_and_use_tuple() { let mut t: T = (0, Box::new(0)); drop(t); t.0 = 10; t.1 = Box::new(20); - //~^ ERROR assign to part of moved value: `t` [E0382] + //[stable]~^ ERROR assign to part of moved value: `t` [E0382] use_fully!(tuple t); } fn test_0100_local_partial_init_and_use_struct() { let s: S; - s.x = 10; //~ ERROR E0381 + s.x = 10; //[stable]~ ERROR E0381 use_part!(struct s); } fn test_0101_local_partial_init_and_use_tuple() { let t: T; - t.0 = 10; //~ ERROR E0381 + t.0 = 10; //[stable]~ ERROR E0381 use_part!(tuple t); } fn test_0110_local_partial_reinit_and_use_struct() { let mut s: S = S::new(); drop(s); s.x = 10; - //~^ ERROR assign to part of moved value: `s` [E0382] + //[stable]~^ ERROR assign to part of moved value: `s` [E0382] use_part!(struct s); } fn test_0111_local_partial_reinit_and_use_tuple() { let mut t: T = (0, Box::new(0)); drop(t); t.0 = 10; - //~^ ERROR assign to part of moved value: `t` [E0382] + //[stable]~^ ERROR assign to part of moved value: `t` [E0382] use_part!(tuple t); } fn test_0200_local_void_init_and_use_struct() { let s: S; - s.x = 10; //~ ERROR E0381 + s.x = 10; //[stable]~ ERROR E0381 use_part!(struct s); } fn test_0201_local_void_init_and_use_tuple() { let t: Tvoid; - t.0 = 10; //~ ERROR E0381 + t.0 = 10; //[stable]~ ERROR E0381 use_part!(tuple t); } @@ -167,65 +170,65 @@ fn test_0201_local_void_init_and_use_tuple() { fn test_1000_field_fully_init_and_use_struct() { let q: Q>; - q.r.f.x = 10; q.r.f.y = Box::new(20); //~ ERROR E0381 + q.r.f.x = 10; q.r.f.y = Box::new(20); //[stable]~ ERROR E0381 use_fully!(struct q.r.f); } fn test_1001_field_fully_init_and_use_tuple() { let q: Q; - q.r.f.0 = 10; q.r.f.1 = Box::new(20); //~ ERROR E0381 + q.r.f.0 = 10; q.r.f.1 = Box::new(20); //[stable]~ ERROR E0381 use_fully!(tuple q.r.f); } fn test_1010_field_fully_reinit_and_use_struct() { let mut q: Q> = Q::new(S::new()); drop(q.r); q.r.f.x = 10; q.r.f.y = Box::new(20); - //~^ ERROR assign to part of moved value: `q.r` [E0382] + //[stable]~^ ERROR assign to part of moved value: `q.r` [E0382] use_fully!(struct q.r.f); } fn test_1011_field_fully_reinit_and_use_tuple() { let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); q.r.f.0 = 10; q.r.f.1 = Box::new(20); - //~^ ERROR assign to part of moved value: `q.r` [E0382] + //[stable]~^ ERROR assign to part of moved value: `q.r` [E0382] use_fully!(tuple q.r.f); } fn test_1100_field_partial_init_and_use_struct() { let q: Q>; - q.r.f.x = 10; //~ ERROR E0381 + q.r.f.x = 10; //[stable]~ ERROR E0381 use_part!(struct q.r.f); } fn test_1101_field_partial_init_and_use_tuple() { let q: Q; - q.r.f.0 = 10; //~ ERROR E0381 + q.r.f.0 = 10; //[stable]~ ERROR E0381 use_part!(tuple q.r.f); } fn test_1110_field_partial_reinit_and_use_struct() { let mut q: Q> = Q::new(S::new()); drop(q.r); q.r.f.x = 10; - //~^ ERROR assign to part of moved value: `q.r` [E0382] + //[stable]~^ ERROR assign to part of moved value: `q.r` [E0382] use_part!(struct q.r.f); } fn test_1111_field_partial_reinit_and_use_tuple() { let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); q.r.f.0 = 10; - //~^ ERROR assign to part of moved value: `q.r` [E0382] + //[stable]~^ ERROR assign to part of moved value: `q.r` [E0382] use_part!(tuple q.r.f); } fn test_1200_field_void_init_and_use_struct() { - let mut q: Q>; - q.r.f.x = 10; //~ ERROR E0381 + let q: Q>; + q.r.f.x = 10; //[stable]~ ERROR E0381 use_part!(struct q.r.f); } fn test_1201_field_void_init_and_use_tuple() { - let mut q: Q; - q.r.f.0 = 10; //~ ERROR E0381 + let q: Q; + q.r.f.0 = 10; //[stable]~ ERROR E0381 use_part!(tuple q.r.f); } @@ -242,7 +245,7 @@ fn issue_26996() { let mut c = (1, "".to_owned()); match c { c2 => { - c.0 = 2; //~ ERROR assign to part of moved value + c.0 = 2; //[stable]~ ERROR assign to part of moved value assert_eq!(c2.0, 1); } } @@ -252,7 +255,7 @@ fn issue_27021() { let mut c = (1, (1, "".to_owned())); match c { c2 => { - (c.1).0 = 2; //~ ERROR assign to part of moved value + (c.1).0 = 2; //[stable]~ ERROR assign to part of moved value assert_eq!((c2.1).0, 1); } } @@ -260,7 +263,7 @@ fn issue_27021() { let mut c = (1, (1, (1, "".to_owned()))); match c.1 { c2 => { - ((c.1).1).0 = 3; //~ ERROR assign to part of moved value + ((c.1).1).0 = 3; //[stable]~ ERROR assign to part of moved value assert_eq!((c2.1).0, 1); } } diff --git a/tests/ui/borrowck/structural_init.stable.stderr b/tests/ui/borrowck/structural_init.stable.stderr index 496a298a36ce9..fff52d99e061e 100644 --- a/tests/ui/borrowck/structural_init.stable.stderr +++ b/tests/ui/borrowck/structural_init.stable.stderr @@ -1,5 +1,5 @@ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:97:5 + --> $DIR/structural_init.rs:104:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | s.x = 10; s.y = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:103:5 + --> $DIR/structural_init.rs:110:5 | LL | let t: T; | - binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | t.0 = 10; t.1 = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:109:5 + --> $DIR/structural_init.rs:116:5 | LL | let mut s: S = S::new(); drop(s); | ----- - value moved here @@ -29,7 +29,7 @@ LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move | note: if `S>` implemented `Clone`, you could clone the value - --> $DIR/issue-21232-partial-init-and-use.rs:15:1 + --> $DIR/structural_init.rs:20:1 | LL | struct S { | ^^^^^^^^^^^ consider implementing `Clone` for this type @@ -38,7 +38,7 @@ LL | let mut s: S = S::new(); drop(s); | - you could clone this value error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:116:5 + --> $DIR/structural_init.rs:123:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -53,7 +53,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:123:5 + --> $DIR/structural_init.rs:130:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -63,7 +63,7 @@ LL | s.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:129:5 + --> $DIR/structural_init.rs:136:5 | LL | let t: T; | - binding declared here but left uninitialized @@ -73,7 +73,7 @@ LL | t.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:135:5 + --> $DIR/structural_init.rs:142:5 | LL | let mut s: S = S::new(); drop(s); | ----- - value moved here @@ -83,7 +83,7 @@ LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move | note: if `S>` implemented `Clone`, you could clone the value - --> $DIR/issue-21232-partial-init-and-use.rs:15:1 + --> $DIR/structural_init.rs:20:1 | LL | struct S { | ^^^^^^^^^^^ consider implementing `Clone` for this type @@ -92,7 +92,7 @@ LL | let mut s: S = S::new(); drop(s); | - you could clone this value error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:142:5 + --> $DIR/structural_init.rs:149:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -107,7 +107,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:149:5 + --> $DIR/structural_init.rs:156:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -117,7 +117,7 @@ LL | s.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:155:5 + --> $DIR/structural_init.rs:162:5 | LL | let t: Tvoid; | - binding declared here but left uninitialized @@ -127,7 +127,7 @@ LL | t.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:170:5 + --> $DIR/structural_init.rs:177:5 | LL | let q: Q>; | - binding declared here but left uninitialized @@ -137,7 +137,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:176:5 + --> $DIR/structural_init.rs:183:5 | LL | let q: Q; | - binding declared here but left uninitialized @@ -147,7 +147,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:182:5 + --> $DIR/structural_init.rs:189:5 | LL | let mut q: Q> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -157,7 +157,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20); = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:189:5 + --> $DIR/structural_init.rs:196:5 | LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -167,7 +167,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:196:5 + --> $DIR/structural_init.rs:203:5 | LL | let q: Q>; | - binding declared here but left uninitialized @@ -177,7 +177,7 @@ LL | q.r.f.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:202:5 + --> $DIR/structural_init.rs:209:5 | LL | let q: Q; | - binding declared here but left uninitialized @@ -187,7 +187,7 @@ LL | q.r.f.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:208:5 + --> $DIR/structural_init.rs:215:5 | LL | let mut q: Q> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -197,7 +197,7 @@ LL | q.r.f.x = 10; = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:215:5 + --> $DIR/structural_init.rs:222:5 | LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -207,27 +207,27 @@ LL | q.r.f.0 = 10; = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:222:5 + --> $DIR/structural_init.rs:229:5 | -LL | let mut q: Q>; - | ----- binding declared here but left uninitialized +LL | let q: Q>; + | - binding declared here but left uninitialized LL | q.r.f.x = 10; | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized | = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-use.rs:228:5 + --> $DIR/structural_init.rs:235:5 | -LL | let mut q: Q; - | ----- binding declared here but left uninitialized +LL | let q: Q; + | - binding declared here but left uninitialized LL | q.r.f.0 = 10; | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized | = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `c` - --> $DIR/issue-21232-partial-init-and-use.rs:245:13 + --> $DIR/structural_init.rs:252:13 | LL | let mut c = (1, "".to_owned()); | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait @@ -243,7 +243,7 @@ LL | ref c2 => { | +++ error[E0382]: assign to part of moved value: `c` - --> $DIR/issue-21232-partial-init-and-use.rs:255:13 + --> $DIR/structural_init.rs:262:13 | LL | let mut c = (1, (1, "".to_owned())); | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait @@ -259,7 +259,7 @@ LL | ref c2 => { | +++ error[E0382]: assign to part of moved value: `c.1` - --> $DIR/issue-21232-partial-init-and-use.rs:263:13 + --> $DIR/structural_init.rs:270:13 | LL | c2 => { | -- value moved here diff --git a/tests/ui/borrowck/structural_init_invalid.feature.stderr b/tests/ui/borrowck/structural_init_invalid.feature.stderr index 63f230be7d4b3..2b770c41cf019 100644 --- a/tests/ui/borrowck/structural_init_invalid.feature.stderr +++ b/tests/ui/borrowck/structural_init_invalid.feature.stderr @@ -1,5 +1,5 @@ error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5 + --> $DIR/structural_init_invalid.rs:31:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5 + --> $DIR/structural_init_invalid.rs:36:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5 + --> $DIR/structural_init_invalid.rs:42:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -28,35 +28,35 @@ LL | drop(d); LL | d.x = 10; | ^^^^^^^^ value assigned here after move -error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5 +error[E0381]: assigned binding `d` isn't fully initialized + --> $DIR/structural_init_invalid.rs:48:5 | LL | let d: D; | - binding declared here but left uninitialized LL | d.s.y = 20; - | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | ^^^^^^^^^^ `d` assigned here but it isn't fully initialized | = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5 +error[E0381]: assigned binding `d` isn't fully initialized + --> $DIR/structural_init_invalid.rs:53:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized LL | d.s.y = 20; - | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | ^^^^^^^^^^ `d` assigned here but it isn't fully initialized | = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0382]: assign to part of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5 +error[E0382]: assign of moved value: `d` + --> $DIR/structural_init_invalid.rs:59:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait LL | drop(d); | - value moved here LL | d.s.y = 20; - | ^^^^^^^^^^ value partially assigned here after move + | ^^^^^^^^^^ value assigned here after move error: aborting due to 6 previous errors diff --git a/tests/ui/borrowck/structural_init_invalid.rs b/tests/ui/borrowck/structural_init_invalid.rs index 46a156d2af9ee..e004d61dd4c9c 100644 --- a/tests/ui/borrowck/structural_init_invalid.rs +++ b/tests/ui/borrowck/structural_init_invalid.rs @@ -1,12 +1,12 @@ +//@ revisions: stable feature +#![cfg_attr(feature, feature(structural_init))] + // This test enumerates various cases of interest where an ADT or tuple is // partially initialized and then used in some way that is wrong *even* -// after rust-lang/rust#54987 is implemented. -// -// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987. +// with `feature(structural_init)`. The error output in both cases should be identical. // -// See issue-21232-partial-init-and-use.rs for cases of tests that are -// meant to compile and run successfully once rust-lang/rust#54987 is -// implemented. +// See structural_init.rs for cases of tests that are +// meant to compile and run successfully with `structural_init`. struct D { x: u32, @@ -54,7 +54,9 @@ fn cannot_partially_reinit_inner_adt_via_outer_with_drop() { let mut d = D { x: 0, s: S{ y: 0, z: 0} }; drop(d); d.s.y = 20; - //~^ ERROR assign to part of moved value: `d` [E0382] + //[stable]~^ ERROR assign to part of moved value: `d` [E0382] + //[feature]~^^ ERROR assign of moved value: `d` [E0382] + // FIXME: nonsense diagnostic } fn main() { } diff --git a/tests/ui/borrowck/structural_init_invalid.stable.stderr b/tests/ui/borrowck/structural_init_invalid.stable.stderr index 63f230be7d4b3..cfd7fd27ca367 100644 --- a/tests/ui/borrowck/structural_init_invalid.stable.stderr +++ b/tests/ui/borrowck/structural_init_invalid.stable.stderr @@ -1,5 +1,5 @@ error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5 + --> $DIR/structural_init_invalid.rs:31:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5 + --> $DIR/structural_init_invalid.rs:36:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5 + --> $DIR/structural_init_invalid.rs:42:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | d.x = 10; | ^^^^^^^^ value assigned here after move error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5 + --> $DIR/structural_init_invalid.rs:48:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -39,7 +39,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5 + --> $DIR/structural_init_invalid.rs:53:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -49,7 +49,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5 + --> $DIR/structural_init_invalid.rs:59:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait From b056ed098908133db3efe2fcbabe1d21194fdea1 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:26:54 -0700 Subject: [PATCH 6/6] add empty struct tests and fix behavior for empty structs with dtors --- compiler/rustc_borrowck/src/lib.rs | 4 +- tests/ui/borrowck/structural_init.rs | 18 +++++ .../ui/borrowck/structural_init.stable.stderr | 78 ++++++++++++------- .../structural_init_invalid.feature.stderr | 27 +++++-- tests/ui/borrowck/structural_init_invalid.rs | 10 +++ .../structural_init_invalid.stable.stderr | 27 +++++-- 6 files changed, 121 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index f2a5fd0ef1078..250ca798cd465 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2093,7 +2093,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let path = &self.move_data.move_paths[mpi]; let field_count = match path.place.ty(self.body(), tcx).ty.kind() { - ty::Adt(adt, _) if adt.is_struct() => { + ty::Adt(adt, _) if adt.is_struct() && !adt.has_dtor(tcx) => { let variant = adt.non_enum_variant(); if variant.field_list_has_applicable_non_exhaustive() { @@ -2107,8 +2107,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { _ => return true, }; - // FIXME: destructors? - // A structurally initialized type is "uninit" but all of it's fields are init. // This means all of it's fields must have MovePaths // because fields that are never written to will not have MovePaths. diff --git a/tests/ui/borrowck/structural_init.rs b/tests/ui/borrowck/structural_init.rs index 76e7c27f6b431..7ea75ca8313cb 100644 --- a/tests/ui/borrowck/structural_init.rs +++ b/tests/ui/borrowck/structural_init.rs @@ -52,6 +52,8 @@ struct R { impl Q { fn new(f: F) -> Self { Q { v: 0, r: R::new(f) } } } impl R { fn new(f: F) -> Self { R { w: 0, f } } } +struct Empty; + // Axes to cover: // * local/field: Is the structure in a local or a field // * fully/partial/void: Are we fully initializing it before using any part? @@ -269,6 +271,19 @@ fn issue_27021() { } } +// Strange case discovered during implementation. +// FIXME: not decided if this should compile or not. +fn test_empty_struct() { + let e: Empty; + drop(e); //[stable]~ ERROR used binding `e` isn't initialized [E0381] +} + +#[expect(dropping_copy_types)] +fn test_empty_tuple() { + let t: (); + drop(t); //[stable]~ ERROR used binding `t` isn't initialized [E0381] +} + fn main() { test_0000_local_fully_init_and_use_struct(); test_0001_local_fully_init_and_use_tuple(); @@ -297,4 +312,7 @@ fn main() { issue_26996(); issue_27021(); + + test_empty_struct(); + test_empty_tuple(); } diff --git a/tests/ui/borrowck/structural_init.stable.stderr b/tests/ui/borrowck/structural_init.stable.stderr index fff52d99e061e..26607c0fd9a20 100644 --- a/tests/ui/borrowck/structural_init.stable.stderr +++ b/tests/ui/borrowck/structural_init.stable.stderr @@ -1,5 +1,5 @@ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/structural_init.rs:104:5 + --> $DIR/structural_init.rs:102:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | s.x = 10; s.y = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/structural_init.rs:110:5 + --> $DIR/structural_init.rs:108:5 | LL | let t: T; | - binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | t.0 = 10; t.1 = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/structural_init.rs:116:5 + --> $DIR/structural_init.rs:114:5 | LL | let mut s: S = S::new(); drop(s); | ----- - value moved here @@ -29,7 +29,7 @@ LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move | note: if `S>` implemented `Clone`, you could clone the value - --> $DIR/structural_init.rs:20:1 + --> $DIR/structural_init.rs:16:1 | LL | struct S { | ^^^^^^^^^^^ consider implementing `Clone` for this type @@ -38,7 +38,7 @@ LL | let mut s: S = S::new(); drop(s); | - you could clone this value error[E0382]: assign to part of moved value: `t` - --> $DIR/structural_init.rs:123:5 + --> $DIR/structural_init.rs:121:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -53,7 +53,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/structural_init.rs:130:5 + --> $DIR/structural_init.rs:128:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -63,7 +63,7 @@ LL | s.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/structural_init.rs:136:5 + --> $DIR/structural_init.rs:134:5 | LL | let t: T; | - binding declared here but left uninitialized @@ -73,7 +73,7 @@ LL | t.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/structural_init.rs:142:5 + --> $DIR/structural_init.rs:140:5 | LL | let mut s: S = S::new(); drop(s); | ----- - value moved here @@ -83,7 +83,7 @@ LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move | note: if `S>` implemented `Clone`, you could clone the value - --> $DIR/structural_init.rs:20:1 + --> $DIR/structural_init.rs:16:1 | LL | struct S { | ^^^^^^^^^^^ consider implementing `Clone` for this type @@ -92,7 +92,7 @@ LL | let mut s: S = S::new(); drop(s); | - you could clone this value error[E0382]: assign to part of moved value: `t` - --> $DIR/structural_init.rs:149:5 + --> $DIR/structural_init.rs:147:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -107,7 +107,7 @@ LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized - --> $DIR/structural_init.rs:156:5 + --> $DIR/structural_init.rs:154:5 | LL | let s: S; | - binding declared here but left uninitialized @@ -117,7 +117,7 @@ LL | s.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `t` isn't fully initialized - --> $DIR/structural_init.rs:162:5 + --> $DIR/structural_init.rs:160:5 | LL | let t: Tvoid; | - binding declared here but left uninitialized @@ -127,7 +127,7 @@ LL | t.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:177:5 + --> $DIR/structural_init.rs:175:5 | LL | let q: Q>; | - binding declared here but left uninitialized @@ -137,7 +137,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:183:5 + --> $DIR/structural_init.rs:181:5 | LL | let q: Q; | - binding declared here but left uninitialized @@ -147,7 +147,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/structural_init.rs:189:5 + --> $DIR/structural_init.rs:187:5 | LL | let mut q: Q> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -157,7 +157,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20); = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/structural_init.rs:196:5 + --> $DIR/structural_init.rs:194:5 | LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -167,7 +167,7 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:203:5 + --> $DIR/structural_init.rs:201:5 | LL | let q: Q>; | - binding declared here but left uninitialized @@ -177,7 +177,7 @@ LL | q.r.f.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:209:5 + --> $DIR/structural_init.rs:207:5 | LL | let q: Q; | - binding declared here but left uninitialized @@ -187,7 +187,7 @@ LL | q.r.f.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/structural_init.rs:215:5 + --> $DIR/structural_init.rs:213:5 | LL | let mut q: Q> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -197,7 +197,7 @@ LL | q.r.f.x = 10; = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/structural_init.rs:222:5 + --> $DIR/structural_init.rs:220:5 | LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -207,7 +207,7 @@ LL | q.r.f.0 = 10; = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:229:5 + --> $DIR/structural_init.rs:227:5 | LL | let q: Q>; | - binding declared here but left uninitialized @@ -217,7 +217,7 @@ LL | q.r.f.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `q` isn't fully initialized - --> $DIR/structural_init.rs:235:5 + --> $DIR/structural_init.rs:233:5 | LL | let q: Q; | - binding declared here but left uninitialized @@ -227,7 +227,7 @@ LL | q.r.f.0 = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `c` - --> $DIR/structural_init.rs:252:13 + --> $DIR/structural_init.rs:250:13 | LL | let mut c = (1, "".to_owned()); | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait @@ -243,7 +243,7 @@ LL | ref c2 => { | +++ error[E0382]: assign to part of moved value: `c` - --> $DIR/structural_init.rs:262:13 + --> $DIR/structural_init.rs:260:13 | LL | let mut c = (1, (1, "".to_owned())); | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait @@ -259,7 +259,7 @@ LL | ref c2 => { | +++ error[E0382]: assign to part of moved value: `c.1` - --> $DIR/structural_init.rs:270:13 + --> $DIR/structural_init.rs:268:13 | LL | c2 => { | -- value moved here @@ -272,7 +272,33 @@ help: borrow this binding in the pattern to avoid moving the value LL | ref c2 => { | +++ -error: aborting due to 23 previous errors +error[E0381]: used binding `e` isn't initialized + --> $DIR/structural_init.rs:278:10 + | +LL | let e: Empty; + | - binding declared here but left uninitialized +LL | drop(e); + | ^ `e` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let e: Empty = /* value */; + | +++++++++++++ + +error[E0381]: used binding `t` isn't initialized + --> $DIR/structural_init.rs:284:10 + | +LL | let t: (); + | - binding declared here but left uninitialized +LL | drop(t); + | ^ `t` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let t: () = (); + | ++++ + +error: aborting due to 25 previous errors Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/structural_init_invalid.feature.stderr b/tests/ui/borrowck/structural_init_invalid.feature.stderr index 2b770c41cf019..32dbafddd6f80 100644 --- a/tests/ui/borrowck/structural_init_invalid.feature.stderr +++ b/tests/ui/borrowck/structural_init_invalid.feature.stderr @@ -1,5 +1,5 @@ error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:31:5 + --> $DIR/structural_init_invalid.rs:33:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:36:5 + --> $DIR/structural_init_invalid.rs:38:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/structural_init_invalid.rs:42:5 + --> $DIR/structural_init_invalid.rs:44:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | d.x = 10; | ^^^^^^^^ value assigned here after move error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:48:5 + --> $DIR/structural_init_invalid.rs:50:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -39,7 +39,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:53:5 + --> $DIR/structural_init_invalid.rs:55:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -49,7 +49,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/structural_init_invalid.rs:59:5 + --> $DIR/structural_init_invalid.rs:61:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -58,7 +58,20 @@ LL | drop(d); LL | d.s.y = 20; | ^^^^^^^^^^ value assigned here after move -error: aborting due to 6 previous errors +error[E0381]: used binding `e` isn't initialized + --> $DIR/structural_init_invalid.rs:69:10 + | +LL | let e: EmptyWithDrop; + | - binding declared here but left uninitialized +LL | drop(e); + | ^ `e` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let e: EmptyWithDrop = /* value */; + | +++++++++++++ + +error: aborting due to 7 previous errors Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/structural_init_invalid.rs b/tests/ui/borrowck/structural_init_invalid.rs index e004d61dd4c9c..1dfb124aeefbb 100644 --- a/tests/ui/borrowck/structural_init_invalid.rs +++ b/tests/ui/borrowck/structural_init_invalid.rs @@ -18,11 +18,16 @@ struct S { z: u32, } +struct EmptyWithDrop; impl Drop for D { fn drop(&mut self) { } } +impl Drop for EmptyWithDrop { + fn drop(&mut self) { } +} + fn cannot_partially_init_adt_with_drop() { let d: D; d.x = 10; //~ ERROR E0381 @@ -59,4 +64,9 @@ fn cannot_partially_reinit_inner_adt_via_outer_with_drop() { // FIXME: nonsense diagnostic } +fn empty_struct_with_drop() { + let e: EmptyWithDrop; + drop(e); //~ ERROR E0381 +} + fn main() { } diff --git a/tests/ui/borrowck/structural_init_invalid.stable.stderr b/tests/ui/borrowck/structural_init_invalid.stable.stderr index cfd7fd27ca367..34e2c382ab2b5 100644 --- a/tests/ui/borrowck/structural_init_invalid.stable.stderr +++ b/tests/ui/borrowck/structural_init_invalid.stable.stderr @@ -1,5 +1,5 @@ error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:31:5 + --> $DIR/structural_init_invalid.rs:33:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -9,7 +9,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:36:5 + --> $DIR/structural_init_invalid.rs:38:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -19,7 +19,7 @@ LL | d.x = 10; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/structural_init_invalid.rs:42:5 + --> $DIR/structural_init_invalid.rs:44:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | d.x = 10; | ^^^^^^^^ value assigned here after move error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:48:5 + --> $DIR/structural_init_invalid.rs:50:5 | LL | let d: D; | - binding declared here but left uninitialized @@ -39,7 +39,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0381]: partially assigned binding `d` isn't fully initialized - --> $DIR/structural_init_invalid.rs:53:5 + --> $DIR/structural_init_invalid.rs:55:5 | LL | let mut d: D; | ----- binding declared here but left uninitialized @@ -49,7 +49,7 @@ LL | d.s.y = 20; = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `d` - --> $DIR/structural_init_invalid.rs:59:5 + --> $DIR/structural_init_invalid.rs:61:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -58,7 +58,20 @@ LL | drop(d); LL | d.s.y = 20; | ^^^^^^^^^^ value partially assigned here after move -error: aborting due to 6 previous errors +error[E0381]: used binding `e` isn't initialized + --> $DIR/structural_init_invalid.rs:69:10 + | +LL | let e: EmptyWithDrop; + | - binding declared here but left uninitialized +LL | drop(e); + | ^ `e` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let e: EmptyWithDrop = /* value */; + | +++++++++++++ + +error: aborting due to 7 previous errors Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`.