Skip to content

Commit 500cf8b

Browse files
Auto merge of #148190 - RalfJung:box_new, r=<try>
replace box_new with lower-level intrinsics
2 parents df984ed + a1b255c commit 500cf8b

File tree

72 files changed

+1069
-1313
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1069
-1313
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
The value of statics and constants must be known at compile time, and they live
24
for the entire lifetime of a program. Creating a boxed value allocates memory on
35
the heap at runtime, and therefore cannot be done at compile time.
46

57
Erroneous code example:
68

7-
```compile_fail,E0010
9+
```
810
const CON : Vec<i32> = vec![1, 2, 3];
911
```

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
7676
| sym::autodiff
7777
| sym::bitreverse
7878
| sym::black_box
79-
| sym::box_new
8079
| sym::breakpoint
8180
| sym::bswap
8281
| sym::caller_location
@@ -132,6 +131,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
132131
| sym::forget
133132
| sym::frem_algebraic
134133
| sym::fsub_algebraic
134+
| sym::init_box_via_move
135135
| sym::is_val_statically_known
136136
| sym::log2f16
137137
| sym::log2f32
@@ -215,6 +215,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
215215
| sym::wrapping_add
216216
| sym::wrapping_mul
217217
| sym::wrapping_sub
218+
| sym::write_via_move_for_vec_unsafe
218219
// tidy-alphabetical-end
219220
=> hir::Safety::Safe,
220221
_ => hir::Safety::Unsafe,
@@ -550,7 +551,7 @@ pub(crate) fn check_intrinsic_type(
550551
sym::cold_path => (0, 0, vec![], tcx.types.unit),
551552

552553
sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
553-
sym::write_via_move => {
554+
sym::write_via_move | sym::write_via_move_for_vec_unsafe => {
554555
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)
555556
}
556557

@@ -645,8 +646,6 @@ pub(crate) fn check_intrinsic_type(
645646

646647
sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool),
647648

648-
sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
649-
650649
// contract_check_requires::<C>(C) -> bool, where C: impl Fn() -> bool
651650
sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit),
652651
sym::contract_check_ensures => {

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,6 +3024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30243024
{
30253025
let deref_kind = if checked_ty.is_box() {
30263026
// detect Box::new(..)
3027+
// FIXME: use `box_new` diagnostic item instead?
30273028
if let ExprKind::Call(box_new, [_]) = expr.kind
30283029
&& let ExprKind::Path(qpath) = &box_new.kind
30293030
&& let Res::Def(DefKind::AssocFn, fn_id) =

compiler/rustc_middle/src/thir.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,6 @@ pub enum ExprKind<'tcx> {
284284
lint_level: LintLevel,
285285
value: ExprId,
286286
},
287-
/// A `box <value>` expression.
288-
Box {
289-
value: ExprId,
290-
},
291287
/// An `if` expression.
292288
If {
293289
if_then_scope: region::Scope,

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
5050
Scope { value, region_scope: _, lint_level: _ } => {
5151
visitor.visit_expr(&visitor.thir()[value])
5252
}
53-
Box { value } => visitor.visit_expr(&visitor.thir()[value]),
5453
If { cond, then, else_opt, if_then_scope: _ } => {
5554
visitor.visit_expr(&visitor.thir()[cond]);
5655
visitor.visit_expr(&visitor.thir()[then]);

compiler/rustc_mir_build/src/builder/expr/as_place.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
553553
| ExprKind::Unary { .. }
554554
| ExprKind::Binary { .. }
555555
| ExprKind::LogicalOp { .. }
556-
| ExprKind::Box { .. }
557556
| ExprKind::Cast { .. }
558557
| ExprKind::Use { .. }
559558
| ExprKind::NeverToAny { .. }

compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! See docs in `build/expr/mod.rs`.
22
33
use rustc_abi::FieldIdx;
4-
use rustc_hir::lang_items::LangItem;
54
use rustc_index::{Idx, IndexVec};
65
use rustc_middle::bug;
76
use rustc_middle::middle::region;
@@ -121,65 +120,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
121120
}
122121
block.and(Rvalue::UnaryOp(op, arg))
123122
}
124-
ExprKind::Box { value } => {
125-
let value_ty = this.thir[value].ty;
126-
let tcx = this.tcx;
127-
let source_info = this.source_info(expr_span);
128-
129-
let size = tcx.require_lang_item(LangItem::SizeOf, expr_span);
130-
let size = Operand::unevaluated_constant(tcx, size, &[value_ty.into()], expr_span);
131-
132-
let align = tcx.require_lang_item(LangItem::AlignOf, expr_span);
133-
let align =
134-
Operand::unevaluated_constant(tcx, align, &[value_ty.into()], expr_span);
135-
136-
// malloc some memory of suitable size and align:
137-
let exchange_malloc = Operand::function_handle(
138-
tcx,
139-
tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span),
140-
[],
141-
expr_span,
142-
);
143-
let storage = this.temp(Ty::new_mut_ptr(tcx, tcx.types.u8), expr_span);
144-
let success = this.cfg.start_new_block();
145-
this.cfg.terminate(
146-
block,
147-
source_info,
148-
TerminatorKind::Call {
149-
func: exchange_malloc,
150-
args: [
151-
Spanned { node: size, span: DUMMY_SP },
152-
Spanned { node: align, span: DUMMY_SP },
153-
]
154-
.into(),
155-
destination: storage,
156-
target: Some(success),
157-
unwind: UnwindAction::Continue,
158-
call_source: CallSource::Misc,
159-
fn_span: expr_span,
160-
},
161-
);
162-
this.diverge_from(block);
163-
block = success;
164-
165-
let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span));
166-
this.cfg
167-
.push(block, Statement::new(source_info, StatementKind::StorageLive(result)));
168-
if let Some(scope) = scope.temp_lifetime {
169-
// schedule a shallow free of that memory, lest we unwind:
170-
this.schedule_drop_storage_and_value(expr_span, scope, result);
171-
}
172-
173-
// Transmute `*mut u8` to the box (thus far, uninitialized):
174-
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
175-
this.cfg.push_assign(block, source_info, Place::from(result), box_);
176-
177-
// initialize the box contents:
178-
block = this
179-
.expr_into_dest(this.tcx.mk_place_deref(Place::from(result)), block, value)
180-
.into_block();
181-
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
182-
}
183123
ExprKind::Cast { source } => {
184124
let source_expr = &this.thir[source];
185125

compiler/rustc_mir_build/src/builder/expr/category.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ impl Category {
6464
| ExprKind::Closure { .. }
6565
| ExprKind::Unary { .. }
6666
| ExprKind::Binary { .. }
67-
| ExprKind::Box { .. }
6867
| ExprKind::Cast { .. }
6968
| ExprKind::PointerCoercion { .. }
7069
| ExprKind::Repeat { .. }

compiler/rustc_mir_build/src/builder/expr/into.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_middle::mir::*;
99
use rustc_middle::span_bug;
1010
use rustc_middle::thir::*;
1111
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
12-
use rustc_span::DUMMY_SP;
1312
use rustc_span::source_map::Spanned;
13+
use rustc_span::{DUMMY_SP, sym};
1414
use rustc_trait_selection::infer::InferCtxtExt;
1515
use tracing::{debug, instrument};
1616

@@ -365,6 +365,97 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
365365
None
366366
})
367367
}
368+
// Some intrinsics are handled here because they desperately want to avoid introducing
369+
// unnecessary copies.
370+
ExprKind::Call { ty, fun, ref args, .. }
371+
if let ty::FnDef(def_id, _generic_args) = ty.kind()
372+
&& let Some(intrinsic) = this.tcx.intrinsic(def_id)
373+
&& matches!(
374+
intrinsic.name,
375+
sym::write_via_move
376+
| sym::write_via_move_for_vec_unsafe
377+
| sym::init_box_via_move
378+
) =>
379+
{
380+
// We still have to evaluate the callee expression as normal (but we don't care
381+
// about its result).
382+
let _fun = unpack!(block = this.as_local_operand(block, fun));
383+
384+
match intrinsic.name {
385+
sym::write_via_move | sym::write_via_move_for_vec_unsafe => {
386+
// `write_via_move(ptr, val)` becomes `*ptr = val` but without any dropping.
387+
388+
// The destination must have unit type (so we don't actually have to store anything
389+
// into it).
390+
assert!(destination.ty(&this.local_decls, this.tcx).ty.is_unit());
391+
392+
// Compile this to an assignment of the argument into the destination.
393+
let [ptr, val] = **args else {
394+
span_bug!(expr_span, "invalid write_via_move call")
395+
};
396+
let Some(ptr) = unpack!(block = this.as_local_operand(block, ptr)).place()
397+
else {
398+
span_bug!(expr_span, "invalid write_via_move call")
399+
};
400+
let ptr_deref = ptr.project_deeper(&[ProjectionElem::Deref], this.tcx);
401+
this.expr_into_dest(ptr_deref, block, val)
402+
}
403+
// sym::init_box_via_move => {
404+
// use rustc_abi::FieldIdx;
405+
// // `init_box_via_move(b, val)` becomes
406+
// // ```
407+
// // *(b.0.0.0) = val;
408+
// // ```
409+
// let [b, val] = **args else {
410+
// span_bug!(expr_span, "invalid init_box_via_move call")
411+
// };
412+
// let Some(b) = unpack!(block = this.as_local_operand(block, b)).place()
413+
// else {
414+
// span_bug!(expr_span, "invalid init_box_via_move call")
415+
// };
416+
// // Project to the pointer inside `b`. First we need to get the types of all
417+
// // the fields we are projecting through.
418+
// let field_ty = |adt: &ty::AdtDef<'tcx>, idx: FieldIdx| {
419+
// let field = adt.non_enum_variant().fields[idx].did;
420+
// this.tcx.type_of(field).instantiate_identity()
421+
// };
422+
// let ty::Adt(box_adt, box_adt_args) =
423+
// b.ty(&this.local_decls, this.tcx).ty.kind()
424+
// else {
425+
// span_bug!(expr_span, "invalid init_box_via_move call")
426+
// };
427+
// // The `<T>` shared by Box, Unique, NonNull.
428+
// let ty_arg = this.tcx.mk_args(&[box_adt_args[0]]);
429+
// let ty::Adt(unique_adt, _args) = field_ty(box_adt, FieldIdx::Zero).kind()
430+
// else {
431+
// span_bug!(expr_span, "invalid init_box_via_move call")
432+
// };
433+
// let unique_ty = Ty::new_adt(this.tcx, unique_def, ty_arg);
434+
// let ty::Adt(nonnull_adt, _args) =
435+
// field_ty(unique_adt, FieldIdx::Zero).kind()
436+
// else {
437+
// span_bug!(expr_span, "invalid init_box_via_move call")
438+
// };
439+
// let nonnull_ty = Ty::new_adt(this.tcx, nonnull_adt, ty_arg);
440+
// // Then we can construct the projection.
441+
// let b_ptr_deref = b.project_deeper(
442+
// &[
443+
// ProjectionElem::Field(FieldIdx::ZERO, unique_ty),
444+
// ProjectionElem::Field(FieldIdx::ZERO, nonnull_ty),
445+
// ProjectionElem::Field(
446+
// FieldIdx::ZERO,
447+
// Ty::new_mut_ptr(tcx, ty_arg.type_at(0)),
448+
// ),
449+
// ProjectionElem::Deref,
450+
// ],
451+
// this.tcx,
452+
// );
453+
// // Store `val` into `b_ptr`.
454+
// this.expr_into_dest(b_ptr_deref, block, val)
455+
// }
456+
_ => rustc_middle::bug!(),
457+
}
458+
}
368459
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
369460
let fun = unpack!(block = this.as_local_operand(block, fun));
370461
let args: Box<[_]> = args
@@ -769,7 +860,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
769860
// these are the cases that are more naturally handled by some other mode
770861
ExprKind::Unary { .. }
771862
| ExprKind::Binary { .. }
772-
| ExprKind::Box { .. }
773863
| ExprKind::Cast { .. }
774864
| ExprKind::PointerCoercion { .. }
775865
| ExprKind::Repeat { .. }

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
474474
| ExprKind::LoopMatch { .. }
475475
| ExprKind::Let { .. }
476476
| ExprKind::Match { .. }
477-
| ExprKind::Box { .. }
478477
| ExprKind::If { .. }
479478
| ExprKind::InlineAsm { .. }
480479
| ExprKind::OffsetOf { .. }

0 commit comments

Comments
 (0)