Skip to content

Allow phased initializing structs#152774

Open
dingxiangfei2009 wants to merge 1 commit into
rust-lang:mainfrom
dingxiangfei2009:partial-init
Open

Allow phased initializing structs#152774
dingxiangfei2009 wants to merge 1 commit into
rust-lang:mainfrom
dingxiangfei2009:partial-init

Conversation

@dingxiangfei2009
Copy link
Copy Markdown
Contributor

@dingxiangfei2009 dingxiangfei2009 commented Feb 17, 2026

Partially undoing #54986

This PR introduces an unstable feature partial_init_nodrop_types. This work corresponds to the new action item in rust-lang/rust-project-goals#548.

Action Items

  • What should we do with non_exhaustive?

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 17, 2026
@dingxiangfei2009
Copy link
Copy Markdown
Contributor Author

dingxiangfei2009 commented Feb 17, 2026

cc @BennoLossin @nxsaken FYI.

@rust-log-analyzer

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@BennoLossin BennoLossin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool to see that it's less than 200 lines changed!

Just two small things that I noticed. I can't speak on any of the actual modifications :)

View changes since this review

Comment thread tests/ui/borrowck/partial-init-locals.stderr
Comment thread compiler/rustc_feature/src/unstable.rs Outdated
@BennoLossin
Copy link
Copy Markdown
Contributor

Regarding non-exhaustive: I think it's pretty simple, the reference already covers all of this:

@dingxiangfei2009
Copy link
Copy Markdown
Contributor Author

This PR is ready for previewing. It is pending a formal RFC and a tracking issue.

@rust-log-analyzer

This comment has been minimized.

@theemathas
Copy link
Copy Markdown
Contributor

theemathas commented Mar 11, 2026

These two code snippets compile with this PR and causes a crash seemingly inside free.

#![feature(partial_init_locals)]

fn main() {
    let x: (String, String);
    x.0 = String::new();
}
#![feature(partial_init_locals)]

struct Thing(String, String);

fn main() {
    let x: Thing;
    x.0 = String::new();
}

@theemathas
Copy link
Copy Markdown
Contributor

This code compiles with this PR and prints garbage data:

#![feature(partial_init_locals)]

fn main() {
    let x: (i32, i32);
    x.0 = 123;
    let weird = x.1;
    println!("{}", weird);
}

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
@dingxiangfei2009 dingxiangfei2009 marked this pull request as ready for review May 18, 2026 12:55
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 18, 2026
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label May 18, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 18, 2026

r? @petrochenkov

rustbot has assigned @petrochenkov.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 18 candidates

@rust-log-analyzer
Copy link
Copy Markdown
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt check
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:38:
     }
 
     pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
-        Statement {
-            source_info,
-            kind,
-            debuginfos: StmtDebugInfos::default(),
-        }
+        Statement { source_info, kind, debuginfos: StmtDebugInfos::default() }
     }
 }
 
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:108:
 impl<'tcx> PlaceTy<'tcx> {
     #[inline]
     pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
-        PlaceTy {
-            ty,
-            variant_index: None,
-        }
+        PlaceTy { ty, variant_index: None }
     }
 
     /// `place_ty.field_ty(tcx, f)` computes the type of a given field.
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:167:
                 // Only prefix fields (upvars and current state) are
                 // accessible without a variant index.
                 ty::Coroutine(_, args) => Unnormalized::dummy(
-                    args.as_coroutine()
-                        .prefix_tys()
-                        .get(f.index())
-                        .copied()
-                        .unwrap_or_else(|| {
-                            bug!("field {f:?} out of range of prefixes for {self_ty}")
-                        }),
+                    args.as_coroutine().prefix_tys().get(f.index()).copied().unwrap_or_else(|| {
+                        bug!("field {f:?} out of range of prefixes for {self_ty}")
+                    }),
                 ),
                 ty::Tuple(tys) => Unnormalized::dummy(
                     tys.get(f.index())
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:190:
         tcx: TyCtxt<'tcx>,
         elems: &[PlaceElem<'tcx>],
     ) -> PlaceTy<'tcx> {
-        elems
-            .iter()
-            .fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
+        elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
     }
 
     /// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:230:
         }
         let answer = match *elem {
             ProjectionElem::Deref => {
-                let ty = structurally_normalize(self.ty)
-                    .builtin_deref(true)
-                    .unwrap_or_else(|| {
-                        bug!("deref projection of non-dereferenceable ty {:?}", self)
-                    });
+                let ty = structurally_normalize(self.ty).builtin_deref(true).unwrap_or_else(|| {
+                    bug!("deref projection of non-dereferenceable ty {:?}", self)
+                });
                 PlaceTy::from_ty(ty)
             }
             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:254:
                     _ => bug!("cannot subslice non-array type: `{:?}`", self),
                 })
             }
-            ProjectionElem::Downcast(_name, index) => PlaceTy {
-                ty: self.ty,
-                variant_index: Some(index),
-            },
+            ProjectionElem::Downcast(_name, index) => {
+                PlaceTy { ty: self.ty, variant_index: Some(index) }
+            }
             ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(
                 structurally_normalize(self.ty),
                 self.variant_index,
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:271:
                 PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty))
             }
         };
-        debug!(
-            "projection_ty self: {:?} elem: {:?} yields: {:?}",
-            self, elem, answer
-        );
+        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
     }
 }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:323:
     /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
     pub fn can_use_in_debuginfo(&self) -> bool {
---
             | Self::Field(_, _) => true,
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:356:
                 ProjectionElem::Downcast(name, read_variant)
             }
             ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, t(ty)),
-            ProjectionElem::ConstantIndex {
-                offset,
-                min_length,
-                from_end,
-            } => ProjectionElem::ConstantIndex {
-                offset,
-                min_length,
-                from_end,
-            },
+            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                ProjectionElem::ConstantIndex { offset, min_length, from_end }
+            }
             ProjectionElem::Subslice { from, to, from_end } => {
                 ProjectionElem::Subslice { from, to, from_end }
             }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:394:
 impl<'tcx> Place<'tcx> {
     // FIXME change this to a const fn by also making List::empty a const fn.
     pub fn return_place() -> Place<'tcx> {
---
 
     /// Iterate over the projections in evaluation order, i.e., the first element is the base with
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:487:
             }
             ty::Tuple(tys) => {
                 let Some(&field_ty) = tys.get(idx.index()) else {
-                    bug!(
-                        "projecting out-of-bound on {ty} into field {}",
-                        idx.as_u32()
-                    )
+                    bug!("projecting out-of-bound on {ty} into field {}", idx.as_u32())
                 };
                 self.project_deeper(&[ProjectionElem::Field(idx, field_ty)], tcx)
             }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:523:
 impl From<Local> for Place<'_> {
     #[inline]
     fn from(local: Local) -> Self {
-        Place {
-            local,
-            projection: List::empty(),
-        }
+        Place { local, projection: List::empty() }
---
-                projection: [],
-            }
-            | PlaceRef {
-                local,
-                projection: [ProjectionElem::Deref],
-            } => Some(local),
+            PlaceRef { local, projection: [] }
+            | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
             _ => None,
         }
     }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:579:
     #[inline]
     pub fn as_local(&self) -> Option<Local> {
         match *self {
-            PlaceRef {
-                local,
-                projection: [],
-            } => Some(local),
+            PlaceRef { local, projection: [] } => Some(local),
             _ => None,
         }
     }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:589:
 
     #[inline]
     pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
-        Place {
-            local: self.local,
-            projection: tcx.mk_place_elems(self.projection),
-        }
+        Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
     }
 
     #[inline]
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:599:
     pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
         if let &[ref proj_base @ .., elem] = self.projection {
-            Some((
-                PlaceRef {
-                    local: self.local,
-                    projection: proj_base,
-                },
-                elem,
-            ))
+            Some((PlaceRef { local: self.local, projection: proj_base }, elem))
         } else {
             None
         }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:622:
         self,
     ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
         self.projection.iter().enumerate().map(move |(i, proj)| {
-            let base = PlaceRef {
-                local: self.local,
-                projection: &self.projection[..i],
-            };
+            let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
             (base, *proj)
         })
     }
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:662:
             &v
         };
 
-        Place {
-            local: self.local,
-            projection: tcx.mk_place_elems(new_projections),
-        }
+        Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:679:
 impl From<Local> for PlaceRef<'_> {
     #[inline]
     fn from(local: Local) -> Self {
-        PlaceRef {
-            local,
-            projection: &[],
-        }
+        PlaceRef { local, projection: &[] }
     }
 }
 
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:715:
         args: &[GenericArg<'tcx>],
         span: Span,
     ) -> Self {
-        let const_ = Const::from_unevaluated(tcx, def_id)
-            .instantiate(tcx, args)
-            .skip_norm_wip();
-        Operand::Constant(Box::new(ConstOperand {
-            span,
-            user_ty: None,
-            const_,
-        }))
+        let const_ = Const::from_unevaluated(tcx, def_id).instantiate(tcx, args).skip_norm_wip();
+        Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
     }
 
     pub fn is_move(&self) -> bool {
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:787:
     /// find as the `func` in a [`TerminatorKind::Call`].
     pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
         let const_ty = self.constant()?.const_.ty();
-        if let ty::FnDef(def_id, args) = *const_ty.kind() {
-            Some((def_id, args))
-        } else {
-            None
-        }
+        if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:953:
         match *self {
             BorrowKind::Shared
             | BorrowKind::Fake(_)
-            | BorrowKind::Mut {
-                kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture,
-            } => false,
-            BorrowKind::Mut {
-                kind: MutBorrowKind::TwoPhaseBorrow,
-            } => true,
+            | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
+                false
+            }
+            BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
         }
     }
 
Diff in /checkout/compiler/rustc_middle/src/mir/statement.rs:1120:
     }
 }
 
-#[derive(
-    Default, Debug, Clone, TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable,
-)]
+#[derive(Default, Debug, Clone, TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable)]
 pub struct StmtDebugInfos<'tcx>(Vec<StmtDebugInfo<'tcx>>);
 
 impl<'tcx> StmtDebugInfos<'tcx> {
fmt: checked 6865 files
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:00:46

@petrochenkov
Copy link
Copy Markdown
Contributor

@rustbot reroll

@rustbot rustbot assigned nikomatsakis and unassigned petrochenkov May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants