|
1 | 1 | //! See docs in build/expr/mod.rs |
2 | 2 |
|
| 3 | +use rustc_abi::FieldIdx; |
3 | 4 | use rustc_ast::{AsmMacro, InlineAsmOptions}; |
4 | 5 | use rustc_data_structures::fx::FxHashMap; |
5 | 6 | use rustc_data_structures::stack::ensure_sufficient_stack; |
@@ -398,73 +399,95 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
398 | 399 | sym::write_box_via_move => { |
399 | 400 | // `write_box_via_move(b, val)` becomes |
400 | 401 | // ``` |
401 | | - // *box_uninit_as_mut_ptr(&mut b) = val; |
| 402 | + // let _tmp = b.0.pointer.pointer as *mut _; |
| 403 | + // *_tmp.value.value = val; |
402 | 404 | // b |
403 | 405 | // ``` |
404 | | - let tcx = this.tcx; |
405 | | - let t = generic_args.type_at(0); |
406 | 406 | let [b, val] = **args else { |
407 | 407 | span_bug!(expr_span, "invalid init_box_via_move call") |
408 | 408 | }; |
409 | | - let box_ty = this.thir.exprs[b].ty; |
410 | 409 | let Some(b) = unpack!(block = this.as_local_operand(block, b)).place() |
411 | 410 | else { |
412 | 411 | span_bug!(expr_span, "invalid init_box_via_move call") |
413 | 412 | }; |
414 | 413 |
|
415 | | - // Create reference to `b`. |
416 | | - let box_ref = this |
| 414 | + // Projecting to a field requires the type of that field. |
| 415 | + // Computing all those types for our 5 projections is quite annoying... |
| 416 | + // we are projecting through: `Unique<MaybeUninit<T>>`, |
| 417 | + // `NonNull<MaybeUninit<T>>`, `*mut MaybeUninit<T>` `MaybeUninit<T>`, |
| 418 | + // `ManuallyDrop<T>`, `T`. |
| 419 | + let tcx = this.tcx; |
| 420 | + let field_ty = |adt: ty::AdtDef<'tcx>, idx: FieldIdx| { |
| 421 | + let field = adt.non_enum_variant().fields[idx].did; |
| 422 | + tcx.type_of(field).instantiate_identity() |
| 423 | + }; |
| 424 | + let box_adt = |
| 425 | + tcx.adt_def(tcx.require_lang_item(LangItem::OwnedBox, DUMMY_SP)); |
| 426 | + let unique_adt = field_ty(box_adt, FieldIdx::ZERO).ty_adt_def().unwrap(); |
| 427 | + let nonnull_adt = |
| 428 | + field_ty(unique_adt, FieldIdx::ZERO).ty_adt_def().unwrap(); |
| 429 | + let manually_drop_adt = |
| 430 | + tcx.adt_def(tcx.require_lang_item(LangItem::ManuallyDrop, DUMMY_SP)); |
| 431 | + |
| 432 | + let ty = generic_args.type_at(0); |
| 433 | + let manually_drop_ty = |
| 434 | + Ty::new_adt(tcx, manually_drop_adt, tcx.mk_args(&[ty.into()])); |
| 435 | + let maybe_uninit_ty = Ty::new_maybe_uninit(tcx, ty); |
| 436 | + let const_ptr_maybe_uninit_ty = Ty::new_imm_ptr(tcx, maybe_uninit_ty); |
| 437 | + let mut_ptr_maybe_uninit_ty = Ty::new_mut_ptr(tcx, maybe_uninit_ty); |
| 438 | + |
| 439 | + let maybe_uninit_ty_args = tcx.mk_args(&[maybe_uninit_ty.into()]); |
| 440 | + let unique_ty = Ty::new_adt(tcx, unique_adt, maybe_uninit_ty_args); |
| 441 | + let nonnull_ty = Ty::new_adt(tcx, nonnull_adt, maybe_uninit_ty_args); |
| 442 | + |
| 443 | + // We need a temporary to store the pointer cast to `*mut`. |
| 444 | + let tmp_ptr = this |
417 | 445 | .local_decls |
418 | | - .push(LocalDecl::new(Ty::new_mut_ptr(tcx, box_ty), expr_span)); |
| 446 | + .push(LocalDecl::new(mut_ptr_maybe_uninit_ty, expr_span)); |
419 | 447 | this.cfg.push( |
420 | 448 | block, |
421 | | - Statement::new(source_info, StatementKind::StorageLive(box_ref)), |
| 449 | + Statement::new(source_info, StatementKind::StorageLive(tmp_ptr)), |
422 | 450 | ); |
423 | 451 | // Make sure `StorageDead` gets emitted. |
424 | 452 | this.schedule_drop_storage_and_value( |
425 | 453 | expr_span, |
426 | 454 | this.local_scope(), |
427 | | - box_ref, |
| 455 | + tmp_ptr, |
428 | 456 | ); |
| 457 | + |
| 458 | + // Generate `let _tmp = b.0.pointer.pointer as *mut _;` using a |
| 459 | + // `ConstToMut` cast so that borrowck makes sure this cast does not change |
| 460 | + // lifetimes. |
429 | 461 | this.cfg.push_assign( |
430 | 462 | block, |
431 | 463 | source_info, |
432 | | - box_ref.into(), |
433 | | - Rvalue::RawPtr(RawPtrKind::Mut, b), |
| 464 | + tmp_ptr.into(), |
| 465 | + Rvalue::Cast( |
| 466 | + CastKind::ConstToMut, |
| 467 | + Operand::Copy(b.project_deeper( |
| 468 | + &[ |
| 469 | + ProjectionElem::Field(FieldIdx::ZERO, unique_ty), |
| 470 | + ProjectionElem::Field(FieldIdx::ZERO, nonnull_ty), |
| 471 | + ProjectionElem::Field( |
| 472 | + FieldIdx::ZERO, |
| 473 | + const_ptr_maybe_uninit_ty, |
| 474 | + ), |
| 475 | + ], |
| 476 | + tcx, |
| 477 | + )), |
| 478 | + mut_ptr_maybe_uninit_ty, |
| 479 | + ), |
434 | 480 | ); |
435 | 481 |
|
436 | | - // Invoke `box_uninit_as_mut_ptr`. |
437 | | - let as_mut_ptr_fn = Operand::function_handle( |
| 482 | + // Generate `*_tmp.value.value = val;` |
| 483 | + let ptr_deref = Place::from(tmp_ptr).project_deeper( |
| 484 | + &[ |
| 485 | + ProjectionElem::Deref, |
| 486 | + ProjectionElem::Field(FieldIdx::from_u32(1), manually_drop_ty), |
| 487 | + ProjectionElem::Field(FieldIdx::ZERO, ty), |
| 488 | + ], |
438 | 489 | tcx, |
439 | | - tcx.require_lang_item(LangItem::BoxUninitAsMutPtr, expr_span), |
440 | | - [t.into()], |
441 | | - expr_span, |
442 | 490 | ); |
443 | | - let inner_ptr = this.temp(Ty::new_mut_ptr(tcx, t), expr_span); |
444 | | - let success = this.cfg.start_new_block(); |
445 | | - this.cfg.terminate( |
446 | | - block, |
447 | | - source_info, |
448 | | - TerminatorKind::Call { |
449 | | - func: as_mut_ptr_fn, |
450 | | - args: [Spanned { |
451 | | - node: Operand::Copy(box_ref.into()), |
452 | | - span: expr_span, |
453 | | - }] |
454 | | - .into(), |
455 | | - destination: inner_ptr, |
456 | | - target: Some(success), |
457 | | - unwind: UnwindAction::Unreachable, |
458 | | - call_source: CallSource::Misc, |
459 | | - fn_span: expr_span, |
460 | | - }, |
461 | | - ); |
462 | | - this.diverge_from(block); |
463 | | - block = success; |
464 | | - |
465 | | - // Store `val` into `inner_ptr`. |
466 | | - let ptr_deref = Place::from(inner_ptr) |
467 | | - .project_deeper(&[ProjectionElem::Deref], this.tcx); |
468 | 491 | unpack!(block = this.expr_into_dest(ptr_deref, block, val)); |
469 | 492 |
|
470 | 493 | // Return `b` |
|
0 commit comments