Auto merge of #148190 - RalfJung:box_new, r=RalfJung

replace box_new with lower-level intrinsics

The `box_new` intrinsic is super special: during THIR construction it turns into an `ExprKind::Box` (formerly known as the `box` keyword), which then during MIR building turns into a special instruction sequence that invokes the exchange_malloc lang item (which has a name from a different time) and a special MIR statement to represent a shallowly-initialized `Box` (which raises [interesting opsem questions](https://github.com/rust-lang/rust/issues/97270)).

This PR is the n-th attempt to get rid of `box_new`. That's non-trivial because it usually causes a perf regression: replacing `box_new` by naive unsafe code will incur extra copies in debug builds, making the resulting binaries a lot slower, and will generate a lot more MIR, making compilation measurably slower. Furthermore, `vec!` is a macro, so the exact code it expands to is highly relevant for borrow checking, type inference, and temporary scopes.

To avoid those problems, this PR does its best to make the MIR almost exactly the same as what it was before. `box_new` is used in two places, `Box::new` and `vec!`:
- For `Box::new` that is fairly easy: the `move_by_value` intrinsic is basically all we need. However, to avoid the extra copy that would usually be generated for the argument of a function call, we need to special-case this intrinsic during MIR building. That's what the first commit does.
- `vec!` is a lot more tricky. As a macro, its details leak to stable code, so almost every variant I tried broke either type inference or the lifetimes of temporaries in some ui test or ended up accepting unsound code due to the borrow checker not enforcing all the constraints I hoped it would enforce. I ended up with a variant that involves a new intrinsic, `fn write_box_via_move<T>(b: Box<MaybeUninit<T>>, x: T) -> Box<MaybeUninit<T>>`, that writes a value into a `Box<MaybeUninit<T>>` and returns that box again. In exchange we can get rid of somewhat similar code in the lowering for `ExprKind::Box`, and the `exchange_malloc` lang item. (We can also get rid of `Rvalue::ShallowInitBox`; I didn't include that in this PR -- I think @cjgillot has a commit for this somewhere [around here](https://github.com/rust-lang/rust/pull/147862/commits).)

See [here](https://github.com/rust-lang/rust/pull/148190#issuecomment-3457454814) for the latest perf numbers. Most of the regressions are in deep-vector which consists entirely of an invocation of `vec!`, so any change to that macro affects this benchmark disproportionally.

This is my first time even looking at MIR building code, so I am very low confidence in that part of the patch, in particular when it comes to scopes and drops and things like that.

I also had do nerf some clippy tests because clippy gets confused by the new expansion of `vec!` so it makes fewer suggestions when `vec!` is involved.

### `vec!` FAQ

- Why does `write_box_via_move` return the `Box` again? Because we need to expand `vec!` to a bunch of method invocations without any blocks or let-statements, or else the temporary scopes (and type inference) don't work out.
- Why is `box_assume_init_into_vec_unsafe` (unsoundly!) a safe function? Because we can't use an unsafe block in `vec!` as that would necessarily also include the `$x` (due to it all being one big method invocation) and therefore interpret the user's code as being inside `unsafe`, which would be bad (and 10 years later, we still don't have safe blocks for macros like this).
- Why does `write_box_via_move` use `Box` as input/output type, and not, say, raw pointers? Because that is the only way to get the correct behavior when `$x` panics or has control effects: we need the `Box` to be dropped in that case. (As a nice side-effect this also makes the intrinsic safe, which is imported as explained in the previous bullet.)
- Can't we make it safe by having `write_box_via_move` return `Box<T>`? Yes we could, but there's no easy way for the intrinsic to convert its `Box<MaybeUninit<T>>` to a `Box<T>`. Transmuting would be unsound as the borrow checker would no longer properly enforce that lifetimes involved in a `vec!` invocation behave correctly.
- Is this macro truly cursed? Yes, yes it is.
This commit is contained in:
bors 2026-02-16 18:46:10 +00:00
commit 3c9faa0d03
100 changed files with 1256 additions and 1508 deletions

View file

@ -622,11 +622,6 @@ impl<T: ?Sized> Deref for Box<T> {
}
}
#[lang = "exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
unsafe { libc::malloc(size) }
}
#[lang = "drop"]
pub trait Drop {
fn drop(&mut self);

View file

@ -628,11 +628,6 @@ impl<T: ?Sized, A: Allocator> Deref for Box<T, A> {
}
}
#[lang = "exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
libc::malloc(size)
}
#[lang = "drop"]
pub trait Drop {
fn drop(&mut self);

View file

@ -850,13 +850,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
// This can be called on stable via the `vec!` macro.
if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) {
self.check_op(ops::HeapAllocation);
// Allow this call, skip all the checks below.
return;
}
// Intrinsics are language primitives, not regular calls, so treat them separately.
if let Some(intrinsic) = tcx.intrinsic(callee) {
if !tcx.is_const_fn(callee) {

View file

@ -561,18 +561,6 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
}
}
#[derive(Debug)]
pub(crate) struct HeapAllocation;
impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.dcx().create_err(errors::UnallowedHeapAllocations {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0010),
})
}
}
#[derive(Debug)]
pub(crate) struct InlineAsm;
impl<'tcx> NonConstOp<'tcx> for InlineAsm {

View file

@ -289,31 +289,6 @@ pub(crate) struct UnallowedOpInConstContext {
pub msg: String,
}
#[derive(Diagnostic)]
#[diag(r#"allocations are not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0010)]
pub(crate) struct UnallowedHeapAllocations {
#[primary_span]
#[label(
r#"allocation not allowed in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#
)]
pub span: Span,
pub kind: ConstContext,
#[note(
"the runtime heap is not yet available at compile-time, so no runtime heap allocations can be created"
)]
pub teach: bool,
}
#[derive(Diagnostic)]
#[diag(r#"inline assembly is not allowed in {$kind ->
[const] constant

View file

@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler.
The value of statics and constants must be known at compile time, and they live
for the entire lifetime of a program. Creating a boxed value allocates memory on
the heap at runtime, and therefore cannot be done at compile time.
Erroneous code example:
```compile_fail,E0010
```ignore (no longer emitted)
const CON : Vec<i32> = vec![1, 2, 3];
```

View file

@ -20,7 +20,8 @@
//
// Do *not* remove entries from this list. Instead, just add a note to the corresponding markdown
// file saying that this error is not emitted by the compiler any more (see E0001.md for an
// example), and remove all code examples that do not build any more.
// example), and remove all code examples that do not build any more by marking them
// with `ignore (no longer emitted)`.
#[macro_export]
#[rustfmt::skip]
macro_rules! error_codes {

View file

@ -320,7 +320,6 @@ language_item_table! {
FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None;
FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None;
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;

View file

@ -77,7 +77,6 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::autodiff
| sym::bitreverse
| sym::black_box
| sym::box_new
| sym::breakpoint
| sym::bswap
| sym::caller_location
@ -223,6 +222,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::wrapping_add
| sym::wrapping_mul
| sym::wrapping_sub
| sym::write_box_via_move
// tidy-alphabetical-end
=> hir::Safety::Safe,
_ => hir::Safety::Unsafe,
@ -584,6 +584,13 @@ pub(crate) fn check_intrinsic_type(
sym::write_via_move => {
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)
}
sym::write_box_via_move => {
let t = param(0);
let maybe_uninit_t = Ty::new_maybe_uninit(tcx, t);
let box_mu_t = Ty::new_box(tcx, maybe_uninit_t);
(1, 0, vec![box_mu_t, param(0)], box_mu_t)
}
sym::typed_swap_nonoverlapping => {
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit)
@ -689,8 +696,6 @@ pub(crate) fn check_intrinsic_type(
sym::ub_checks | sym::overflow_checks => (0, 0, Vec::new(), tcx.types.bool),
sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
// contract_check_requires::<C>(C) -> bool, where C: impl Fn() -> bool
sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit),
sym::contract_check_ensures => {

View file

@ -3110,6 +3110,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let deref_kind = if checked_ty.is_box() {
// detect Box::new(..)
// FIXME: use `box_new` diagnostic item instead?
if let ExprKind::Call(box_new, [_]) = expr.kind
&& let ExprKind::Path(qpath) = &box_new.kind
&& let Res::Def(DefKind::AssocFn, fn_id) =

View file

@ -432,6 +432,22 @@ impl<'tcx> Place<'tcx> {
self.as_ref().project_deeper(more_projections, tcx)
}
/// Return a place that projects to a field of the current place.
///
/// The type of the current place must be an ADT.
pub fn project_to_field(
self,
idx: FieldIdx,
local_decls: &impl HasLocalDecls<'tcx>,
tcx: TyCtxt<'tcx>,
) -> Self {
let ty = self.ty(local_decls, tcx).ty;
let ty::Adt(adt, args) = ty.kind() else { panic!("projecting to field of non-ADT {ty}") };
let field = &adt.non_enum_variant().fields[idx];
let field_ty = field.ty(tcx, args);
self.project_deeper(&[ProjectionElem::Field(idx, field_ty)], tcx)
}
pub fn ty_from<D>(
local: Local,
projection: &[PlaceElem<'tcx>],

View file

@ -268,10 +268,6 @@ pub enum ExprKind<'tcx> {
hir_id: HirId,
value: ExprId,
},
/// A `box <value>` expression.
Box {
value: ExprId,
},
/// An `if` expression.
If {
if_then_scope: region::Scope,

View file

@ -48,7 +48,6 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
let Expr { kind, ty: _, temp_scope_id: _, span: _ } = expr;
match *kind {
Scope { value, region_scope: _, hir_id: _ } => visitor.visit_expr(&visitor.thir()[value]),
Box { value } => visitor.visit_expr(&visitor.thir()[value]),
If { cond, then, else_opt, if_then_scope: _ } => {
visitor.visit_expr(&visitor.thir()[cond]);
visitor.visit_expr(&visitor.thir()[then]);

View file

@ -552,7 +552,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Unary { .. }
| ExprKind::Binary { .. }
| ExprKind::LogicalOp { .. }
| ExprKind::Box { .. }
| ExprKind::Cast { .. }
| ExprKind::Use { .. }
| ExprKind::NeverToAny { .. }

View file

@ -1,7 +1,6 @@
//! See docs in `build/expr/mod.rs`.
use rustc_abi::FieldIdx;
use rustc_hir::lang_items::LangItem;
use rustc_index::{Idx, IndexVec};
use rustc_middle::bug;
use rustc_middle::middle::region::{self, TempLifetime};
@ -124,65 +123,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
block.and(Rvalue::UnaryOp(op, arg))
}
ExprKind::Box { value } => {
let value_ty = this.thir[value].ty;
let tcx = this.tcx;
let source_info = this.source_info(expr_span);
let size = tcx.require_lang_item(LangItem::SizeOf, expr_span);
let size = Operand::unevaluated_constant(tcx, size, &[value_ty.into()], expr_span);
let align = tcx.require_lang_item(LangItem::AlignOf, expr_span);
let align =
Operand::unevaluated_constant(tcx, align, &[value_ty.into()], expr_span);
// malloc some memory of suitable size and align:
let exchange_malloc = Operand::function_handle(
tcx,
tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span),
[],
expr_span,
);
let storage = this.temp(Ty::new_mut_ptr(tcx, tcx.types.u8), expr_span);
let success = this.cfg.start_new_block();
this.cfg.terminate(
block,
source_info,
TerminatorKind::Call {
func: exchange_malloc,
args: [
Spanned { node: size, span: DUMMY_SP },
Spanned { node: align, span: DUMMY_SP },
]
.into(),
destination: storage,
target: Some(success),
unwind: UnwindAction::Continue,
call_source: CallSource::Misc,
fn_span: expr_span,
},
);
this.diverge_from(block);
block = success;
let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span));
this.cfg
.push(block, Statement::new(source_info, StatementKind::StorageLive(result)));
if let Some(scope) = scope.temp_lifetime {
// schedule a shallow free of that memory, lest we unwind:
this.schedule_drop_storage_and_value(expr_span, scope, result);
}
// Transmute `*mut u8` to the box (thus far, uninitialized):
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
this.cfg.push_assign(block, source_info, Place::from(result), box_);
// initialize the box contents:
block = this
.expr_into_dest(this.tcx.mk_place_deref(Place::from(result)), block, value)
.into_block();
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
}
ExprKind::Cast { source } => {
let source_expr = &this.thir[source];

View file

@ -64,7 +64,6 @@ impl Category {
| ExprKind::Closure { .. }
| ExprKind::Unary { .. }
| ExprKind::Binary { .. }
| ExprKind::Box { .. }
| ExprKind::Cast { .. }
| ExprKind::PointerCoercion { .. }
| ExprKind::Repeat { .. }

View file

@ -1,5 +1,6 @@
//! See docs in build/expr/mod.rs
use rustc_abi::FieldIdx;
use rustc_ast::{AsmMacro, InlineAsmOptions};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
@ -9,8 +10,8 @@ use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::DUMMY_SP;
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, sym};
use rustc_trait_selection::infer::InferCtxtExt;
use tracing::{debug, instrument};
@ -366,6 +367,87 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None
})
}
// Some intrinsics are handled here because they desperately want to avoid introducing
// unnecessary copies.
ExprKind::Call { ty, fun, ref args, .. }
if let ty::FnDef(def_id, generic_args) = ty.kind()
&& let Some(intrinsic) = this.tcx.intrinsic(def_id)
&& matches!(intrinsic.name, sym::write_via_move | sym::write_box_via_move) =>
{
// We still have to evaluate the callee expression as normal (but we don't care
// about its result).
let _fun = unpack!(block = this.as_local_operand(block, fun));
match intrinsic.name {
sym::write_via_move => {
// `write_via_move(ptr, val)` becomes `*ptr = val` but without any dropping.
// The destination must have unit type (so we don't actually have to store anything
// into it).
assert!(destination.ty(&this.local_decls, this.tcx).ty.is_unit());
// Compile this to an assignment of the argument into the destination.
let [ptr, val] = **args else {
span_bug!(expr_span, "invalid write_via_move call")
};
let Some(ptr) = unpack!(block = this.as_local_operand(block, ptr)).place()
else {
span_bug!(expr_span, "invalid write_via_move call")
};
let ptr_deref = ptr.project_deeper(&[ProjectionElem::Deref], this.tcx);
this.expr_into_dest(ptr_deref, block, val)
}
sym::write_box_via_move => {
// The signature is:
// `fn write_box_via_move<T>(b: Box<MaybeUninit<T>>, val: T) -> Box<MaybeUninit<T>>`.
// `write_box_via_move(b, val)` becomes
// ```
// (*b).value.value.value = val;
// b
// ```
// One crucial aspect of this lowering is that the generated code must
// cause the borrow checker to enforce that `val` lives sufficiently
// long to be stored in `b`. The above lowering does this; anything that
// involves a `*const T` or a `NonNull<T>` does not as those are covariant.
// Extract the operands, compile `b`.
let [b, val] = **args else {
span_bug!(expr_span, "invalid init_box_via_move call")
};
let Some(b) = unpack!(block = this.as_local_operand(block, b)).place()
else {
span_bug!(expr_span, "invalid init_box_via_move call")
};
let tcx = this.tcx;
let decls = &this.local_decls;
// `b` is a `Box<MaybeUninit<T>>`.
let place = b.project_deeper(&[ProjectionElem::Deref], tcx);
// Current type: `MaybeUninit<T>`. Field #1 is `ManuallyDrop<T>`.
let place = place.project_to_field(FieldIdx::from_u32(1), decls, tcx);
// Current type: `ManuallyDrop<T>`. Field #0 is `MaybeDangling<T>`.
let place = place.project_to_field(FieldIdx::ZERO, decls, tcx);
// Current type: `MaybeDangling<T>`. Field #0 is `T`.
let place = place.project_to_field(FieldIdx::ZERO, decls, tcx);
// Sanity check.
assert_eq!(place.ty(decls, tcx).ty, generic_args.type_at(0));
// Store `val` into place.
unpack!(block = this.expr_into_dest(place, block, val));
// Return `b`
this.cfg.push_assign(
block,
source_info,
destination,
// Move from `b` so that does not get dropped any more.
Rvalue::Use(Operand::Move(b)),
);
block.unit()
}
_ => rustc_middle::bug!(),
}
}
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
let fun = unpack!(block = this.as_local_operand(block, fun));
let args: Box<[_]> = args
@ -770,7 +852,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// these are the cases that are more naturally handled by some other mode
ExprKind::Unary { .. }
| ExprKind::Binary { .. }
| ExprKind::Box { .. }
| ExprKind::Cast { .. }
| ExprKind::PointerCoercion { .. }
| ExprKind::Repeat { .. }

View file

@ -449,7 +449,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::LoopMatch { .. }
| ExprKind::Let { .. }
| ExprKind::Match { .. }
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LogicalOp { .. }

View file

@ -20,7 +20,7 @@ use rustc_middle::ty::{
self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{Span, sym};
use rustc_span::Span;
use tracing::{debug, info, instrument, trace};
use crate::errors::*;
@ -385,24 +385,6 @@ impl<'tcx> ThirBuildCx<'tcx> {
from_hir_call: true,
fn_span: expr.span,
}
} else if let ty::FnDef(def_id, _) = self.typeck_results.expr_ty(fun).kind()
&& let Some(intrinsic) = self.tcx.intrinsic(def_id)
&& intrinsic.name == sym::box_new
{
// We don't actually evaluate `fun` here, so make sure that doesn't miss any side-effects.
if !matches!(fun.kind, hir::ExprKind::Path(_)) {
span_bug!(
expr.span,
"`box_new` intrinsic can only be called via path expression"
);
}
let value = &args[0];
return Expr {
temp_scope_id: expr.hir_id.local_id,
ty: expr_ty,
span: expr.span,
kind: ExprKind::Box { value: self.mirror_expr(value) },
};
} else {
// Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind

View file

@ -342,7 +342,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
| Binary { .. }
| Block { .. }
| Borrow { .. }
| Box { .. }
| Call { .. }
| ByUse { .. }
| Closure { .. }

View file

@ -223,11 +223,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_expr(*value, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
Box { value } => {
print_indented!(self, "Box {", depth_lvl);
self.print_expr(*value, depth_lvl + 1);
print_indented!(self, "}", depth_lvl);
}
If { if_then_scope, cond, then, else_opt } => {
print_indented!(self, "If {", depth_lvl);
print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1);

View file

@ -177,30 +177,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
Some(target) => TerminatorKind::Goto { target },
}
}
sym::write_via_move => {
let target = target.unwrap();
let Ok([ptr, val]) = take_array(args) else {
span_bug!(
terminator.source_info.span,
"Wrong number of arguments for write_via_move intrinsic",
);
};
let derefed_place = if let Some(place) = ptr.node.place()
&& let Some(local) = place.as_local()
{
tcx.mk_place_deref(local.into())
} else {
span_bug!(
terminator.source_info.span,
"Only passing a local is supported"
);
};
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))),
));
terminator.kind = TerminatorKind::Goto { target };
}
// `write_via_move` is already lowered during MIR building.
sym::discriminant_value => {
let target = target.unwrap();
let Ok([arg]) = take_array(args) else {

View file

@ -991,7 +991,6 @@ symbols! {
exact_div,
except,
exception_handling: "exception-handling",
exchange_malloc,
exclusive_range_pattern,
exhaustive_integer_patterns,
exhaustive_patterns,
@ -2183,7 +2182,6 @@ symbols! {
slice_from_raw_parts_mut,
slice_from_ref,
slice_get_unchecked,
slice_into_vec,
slice_iter,
slice_len_fn,
slice_patterns,
@ -2542,6 +2540,7 @@ symbols! {
wrapping_rem_euclid,
wrapping_sub,
wreg,
write_box_via_move,
write_bytes,
write_fmt,
write_macro,

View file

@ -174,7 +174,6 @@ fn recurse_build<'tcx>(
| ExprKind::LoopMatch { .. } => {
error(GenericConstantTooComplexSub::LoopNotSupported(node.span))?
}
ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?,
ExprKind::ByUse { .. } => {
error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))?
}
@ -260,7 +259,6 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
count.has_non_region_param()
}
thir::ExprKind::Scope { .. }
| thir::ExprKind::Box { .. }
| thir::ExprKind::If { .. }
| thir::ExprKind::Call { .. }
| thir::ExprKind::ByUse { .. }

View file

@ -51,8 +51,6 @@ pub(crate) enum GenericConstantTooComplexSub {
YieldNotSupported(#[primary_span] Span),
#[label("loops and loop control flow are not supported in generic constants")]
LoopNotSupported(#[primary_span] Span),
#[label("allocations are not allowed in generic constants")]
BoxNotSupported(#[primary_span] Span),
#[label("unsupported binary operation in generic constants")]
BinaryNotSupported(#[primary_span] Span),
#[label(".use is not allowed in generic constants")]

View file

@ -479,19 +479,6 @@ unsafe impl const Allocator for Global {
}
}
/// The allocator for `Box`.
#[cfg(not(no_global_oom_handling))]
#[lang = "exchange_malloc"]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
match Global.allocate(layout) {
Ok(ptr) => ptr.as_mut_ptr(),
Err(_) => handle_alloc_error(layout),
}
}
// # Allocation error handler
#[cfg(not(no_global_oom_handling))]

View file

@ -236,14 +236,35 @@ pub struct Box<
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
>(Unique<T>, A);
/// Constructs a `Box<T>` by calling the `exchange_malloc` lang item and moving the argument into
/// the newly allocated memory. This is an intrinsic to avoid unnecessary copies.
/// Monomorphic function for allocating an uninit `Box`.
///
/// This is the surface syntax for `box <expr>` expressions.
/// # Safety
///
/// size and align need to be safe for `Layout::from_size_align_unchecked`.
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[cfg(not(no_global_oom_handling))]
unsafe fn box_new_uninit(size: usize, align: usize) -> *mut u8 {
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
match Global.allocate(layout) {
Ok(ptr) => ptr.as_mut_ptr(),
Err(_) => handle_alloc_error(layout),
}
}
/// Helper for `vec!`.
///
/// This is unsafe, but has to be marked as safe or else we couldn't use it in `vec!`.
#[doc(hidden)]
#[rustc_intrinsic]
#[unstable(feature = "liballoc_internals", issue = "none")]
pub fn box_new<T>(x: T) -> Box<T>;
#[inline(always)]
#[cfg(not(no_global_oom_handling))]
#[rustc_diagnostic_item = "box_assume_init_into_vec_unsafe"]
pub fn box_assume_init_into_vec_unsafe<T, const N: usize>(
b: Box<MaybeUninit<[T; N]>>,
) -> crate::vec::Vec<T> {
unsafe { (b.assume_init() as Box<[T]>).into_vec() }
}
impl<T> Box<T> {
/// Allocates memory on the heap and then places `x` into it.
@ -262,7 +283,16 @@ impl<T> Box<T> {
#[rustc_diagnostic_item = "box_new"]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn new(x: T) -> Self {
return box_new(x);
// This is `Box::new_uninit` but inlined to avoid build time regressions.
// SAFETY: The size and align of a valid type `T` are always valid for `Layout`.
let ptr = unsafe {
box_new_uninit(<T as SizedTypeProperties>::SIZE, <T as SizedTypeProperties>::ALIGN)
} as *mut T;
// Nothing below can panic so we do not have to worry about deallocating `ptr`.
// SAFETY: we just allocated the box to store `x`.
unsafe { core::intrinsics::write_via_move(ptr, x) };
// SAFETY: we just initialized `b`.
unsafe { mem::transmute(ptr) }
}
/// Constructs a new box with uninitialized contents.
@ -280,9 +310,21 @@ impl<T> Box<T> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "new_uninit", since = "1.82.0")]
#[must_use]
#[inline]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
Self::new_uninit_in(Global)
// This is the same as `Self::new_uninit_in(Global)`, but manually inlined (just like
// `Box::new`).
// SAFETY:
// - The size and align of a valid type `T` are always valid for `Layout`.
// - If `allocate` succeeds, the returned pointer exactly matches what `Box` needs.
unsafe {
mem::transmute(box_new_uninit(
<T as SizedTypeProperties>::SIZE,
<T as SizedTypeProperties>::ALIGN,
))
}
}
/// Constructs a new `Box` with uninitialized contents, with the memory
@ -1142,10 +1184,12 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
/// assert_eq!(*five, 5)
/// ```
#[stable(feature = "new_uninit", since = "1.82.0")]
#[inline]
#[inline(always)]
pub unsafe fn assume_init(self) -> Box<T, A> {
let (raw, alloc) = Box::into_raw_with_allocator(self);
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
// This is used in the `vec!` macro, so we optimize for minimal IR generation
// even in debug builds.
// SAFETY: `Box<T>` and `Box<MaybeUninit<T>>` have the same layout.
unsafe { core::intrinsics::transmute_unchecked(self) }
}
/// Writes the value and converts to `Box<T, A>`.

View file

@ -0,0 +1,15 @@
//! Intrinsics that cannot be moved to `core` because they depend on `alloc` types.
#![unstable(feature = "liballoc_internals", issue = "none")]
use core::mem::MaybeUninit;
use crate::boxed::Box;
/// Writes `x` into `b`.
///
/// This is needed for `vec!`, which can't afford any extra copies of the argument (or else debug
/// builds regress), has to be written fully as a call chain without `let` (or else this breaks inference
/// of e.g. unsizing coercions), and can't use an `unsafe` block as that would then also
/// include the user-provided `$x`.
#[rustc_intrinsic]
pub fn write_box_via_move<T>(b: Box<MaybeUninit<T>>, x: T) -> Box<MaybeUninit<T>>;

View file

@ -224,6 +224,7 @@ pub mod collections;
#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
pub mod ffi;
pub mod fmt;
pub mod intrinsics;
#[cfg(not(no_rc))]
pub mod rc;
pub mod slice;

View file

@ -47,10 +47,16 @@ macro_rules! vec {
$crate::vec::from_elem($elem, $n)
);
($($x:expr),+ $(,)?) => (
<[_]>::into_vec(
// Using the intrinsic produces a dramatic improvement in stack usage for
// unoptimized programs using this code path to construct large Vecs.
$crate::boxed::box_new([$($x),+])
// Using `write_box_via_move` produces a dramatic improvement in stack usage for unoptimized
// programs using this code path to construct large Vecs. We can't use `write_via_move`
// because this entire invocation has to remain a call chain without `let` bindings, or else
// inference and temporary lifetimes change and things break (see `vec-macro-rvalue-scope`,
// `vec-macro-coercions`, and `autoderef-vec-box-fn-36786` tests).
//
// `box_assume_init_into_vec_unsafe` isn't actually safe but the way we use it here is. We
// can't use an unsafe block as that would also wrap `$x`.
$crate::boxed::box_assume_init_into_vec_unsafe(
$crate::intrinsics::write_box_via_move($crate::boxed::Box::new_uninit(), [$($x),+])
)
);
}

View file

@ -477,7 +477,6 @@ impl<T> [T] {
#[rustc_allow_incoherent_impl]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[rustc_diagnostic_item = "slice_into_vec"]
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
unsafe {
let len = self.len();

View file

@ -297,12 +297,12 @@ impl<'a> VecArgs<'a> {
// `vec![elem; size]` case
Some(VecArgs::Repeat(elem, size))
},
(sym::slice_into_vec, [slice])
if let ExprKind::Call(_, [arg]) = slice.kind
&& let ExprKind::Array(args) = arg.kind =>
(sym::box_assume_init_into_vec_unsafe, [write_box_via_move])
if let ExprKind::Call(_, [_box, elems]) = write_box_via_move.kind
&& let ExprKind::Array(elems) = elems.kind =>
{
// `vec![a, b, c]` case
Some(VecArgs::Vec(args))
Some(VecArgs::Vec(elems))
},
(sym::vec_new, []) => Some(VecArgs::Vec(&[])),
_ => None,

View file

@ -91,6 +91,7 @@ generate! {
author,
borrow,
borrow_mut,
box_assume_init_into_vec_unsafe,
build_hasher,
by_ref,
bytes,

View file

@ -113,10 +113,7 @@ fn main() {
}
// #6811
match Some(0) {
Some(x) => Some(vec![x]),
None => None,
};
Some(0).map(|x| vec![x]);
// Don't lint, coercion
let x: Option<Vec<&[u8]>> = match Some(()) {

View file

@ -183,6 +183,7 @@ fn main() {
// #6811
match Some(0) {
//~^ manual_map
Some(x) => Some(vec![x]),
None => None,
};

View file

@ -173,7 +173,17 @@ LL | | };
| |_____^ help: try: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
error: manual implementation of `Option::map`
--> tests/ui/manual_map_option.rs:196:5
--> tests/ui/manual_map_option.rs:185:5
|
LL | / match Some(0) {
LL | |
LL | | Some(x) => Some(vec![x]),
LL | | None => None,
LL | | };
| |_____^ help: try: `Some(0).map(|x| vec![x])`
error: manual implementation of `Option::map`
--> tests/ui/manual_map_option.rs:197:5
|
LL | / match option_env!("") {
LL | |
@ -183,7 +193,7 @@ LL | | };
| |_____^ help: try: `option_env!("").map(String::from)`
error: manual implementation of `Option::map`
--> tests/ui/manual_map_option.rs:217:12
--> tests/ui/manual_map_option.rs:218:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
@ -195,7 +205,7 @@ LL | | };
| |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
error: manual implementation of `Option::map`
--> tests/ui/manual_map_option.rs:226:12
--> tests/ui/manual_map_option.rs:227:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
@ -206,5 +216,5 @@ LL | | None
LL | | };
| |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
error: aborting due to 20 previous errors
error: aborting due to 21 previous errors

View file

@ -53,7 +53,7 @@ fn or_fun_call() {
with_constructor.unwrap_or_else(make);
//~^ or_fun_call
let with_new = Some(vec![1]);
let with_new: Option<Vec<i32>> = Some(vec![1]);
with_new.unwrap_or_default();
//~^ unwrap_or_default
@ -101,7 +101,7 @@ fn or_fun_call() {
real_default.unwrap_or_default();
//~^ unwrap_or_default
let with_vec = Some(vec![1]);
let with_vec: Option<Vec<i32>> = Some(vec![1]);
with_vec.unwrap_or_default();
//~^ unwrap_or_default
@ -329,7 +329,7 @@ mod lazy {
}
}
let with_new = Some(vec![1]);
let with_new: Option<Vec<i32>> = Some(vec![1]);
with_new.unwrap_or_default();
//~^ unwrap_or_default

View file

@ -53,7 +53,7 @@ fn or_fun_call() {
with_constructor.unwrap_or(make());
//~^ or_fun_call
let with_new = Some(vec![1]);
let with_new: Option<Vec<i32>> = Some(vec![1]);
with_new.unwrap_or(Vec::new());
//~^ unwrap_or_default
@ -101,7 +101,7 @@ fn or_fun_call() {
real_default.unwrap_or(<FakeDefault as Default>::default());
//~^ unwrap_or_default
let with_vec = Some(vec![1]);
let with_vec: Option<Vec<i32>> = Some(vec![1]);
with_vec.unwrap_or(Vec::new());
//~^ unwrap_or_default
@ -329,7 +329,7 @@ mod lazy {
}
}
let with_new = Some(vec![1]);
let with_new: Option<Vec<i32>> = Some(vec![1]);
with_new.unwrap_or_else(Vec::new);
//~^ unwrap_or_default

View file

@ -43,8 +43,7 @@ fn unwrap_or_else_default() {
with_enum.unwrap_or_else(Enum::A);
let with_new = Some(vec![1]);
with_new.unwrap_or_default();
//~^ unwrap_or_default
with_new.unwrap_or_else(Vec::new);
let with_err: Result<_, ()> = Ok(vec![1]);
with_err.unwrap_or_else(make);

View file

@ -44,7 +44,6 @@ fn unwrap_or_else_default() {
let with_new = Some(vec![1]);
with_new.unwrap_or_else(Vec::new);
//~^ unwrap_or_default
let with_err: Result<_, ()> = Ok(vec![1]);
with_err.unwrap_or_else(make);

View file

@ -1,101 +1,95 @@
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:46:14
--> tests/ui/unwrap_or_else_default.rs:60:23
|
LL | with_new.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
|
= note: `-D clippy::unwrap-or-default` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:61:23
|
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:65:24
--> tests/ui/unwrap_or_else_default.rs:64:24
|
LL | with_default_trait.unwrap_or_else(Default::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:69:23
--> tests/ui/unwrap_or_else_default.rs:68:23
|
LL | with_default_type.unwrap_or_else(u64::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:73:23
--> tests/ui/unwrap_or_else_default.rs:72:23
|
LL | with_default_type.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:77:18
--> tests/ui/unwrap_or_else_default.rs:76:18
|
LL | empty_string.unwrap_or_else(|| "".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:82:12
--> tests/ui/unwrap_or_else_default.rs:81:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:86:12
--> tests/ui/unwrap_or_else_default.rs:85:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:90:12
--> tests/ui/unwrap_or_else_default.rs:89:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:94:12
--> tests/ui/unwrap_or_else_default.rs:93:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:98:12
--> tests/ui/unwrap_or_else_default.rs:97:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:102:12
--> tests/ui/unwrap_or_else_default.rs:101:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:106:12
--> tests/ui/unwrap_or_else_default.rs:105:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:110:12
--> tests/ui/unwrap_or_else_default.rs:109:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/unwrap_or_else_default.rs:127:12
--> tests/ui/unwrap_or_else_default.rs:126:12
|
LL | option.unwrap_or_else(Vec::new).push(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `or_insert_with` to construct default value
--> tests/ui/unwrap_or_else_default.rs:145:32
--> tests/ui/unwrap_or_else_default.rs:144:32
|
LL | let _ = inner_map.entry(0).or_insert_with(Default::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: aborting due to 16 previous errors
error: aborting due to 15 previous errors

View file

@ -2,7 +2,7 @@ error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
--> RUSTLIB/core/src/mem/mod.rs:LL:CC
|
LL | crate::intrinsics::write_via_move(dest, src);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
| ^^^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information

View file

@ -178,6 +178,24 @@ fn extract_if() {
}
}
fn vec_macro_cleanup() {
// Ensure memory gets deallocated when control flow leaves the `vec!` macro.
#[allow(unreachable_code)]
loop {
let _v = vec![Box::new(0), break];
}
fn panic<T>() -> T {
panic!()
}
// Ensure all memory gets deallocated on a panic: the `Box` we construct, and the `Box`
// constructed inside `vec!` to eventually turn into a `Vec`.
std::panic::catch_unwind(|| {
let _v = vec![Box::new(0), panic()];
})
.unwrap_err();
}
fn main() {
assert_eq!(vec_reallocate().len(), 5);
@ -209,4 +227,5 @@ fn main() {
reverse();
miri_issue_2759();
extract_if();
vec_macro_cleanup();
}

View file

@ -0,0 +1,5 @@
thread 'main' ($TID) panicked at tests/pass/vec.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View file

@ -0,0 +1,5 @@
thread 'main' ($TID) panicked at tests/pass/vec.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View file

@ -2450,7 +2450,6 @@ ui/single-use-lifetime/issue-107998.rs
ui/single-use-lifetime/issue-117965.rs
ui/span/issue-107353.rs
ui/span/issue-11925.rs
ui/span/issue-15480.rs
ui/span/issue-23338-locals-die-before-temps-of-body.rs
ui/span/issue-23729.rs
ui/span/issue-23827.rs

View file

@ -42,7 +42,6 @@ pub fn foo2() -> Box<dyn TestTrait2> {
}
//~ MONO_ITEM fn <TestStruct2 as TestTrait2>::test_func2
//~ MONO_ITEM fn alloc::alloc::exchange_malloc
//~ MONO_ITEM fn foo2
//~ MONO_ITEM fn std::alloc::Global::alloc_impl_runtime
//~ MONO_ITEM fn std::boxed::Box::<TestStruct2>::new

View file

@ -1,89 +0,0 @@
- // MIR for `main` before ElaborateDrops
+ // MIR for `main` after ElaborateDrops
fn main() -> () {
let mut _0: ();
let _1: std::boxed::Box<S>;
let mut _2: *mut u8;
let mut _3: std::boxed::Box<S>;
let _4: ();
let mut _5: std::boxed::Box<S>;
+ let mut _6: &mut std::boxed::Box<S>;
+ let mut _7: ();
+ let mut _8: *const S;
scope 1 {
debug x => _1;
}
bb0: {
StorageLive(_1);
_2 = alloc::alloc::exchange_malloc(const <S as std::mem::SizedTypeProperties>::SIZE, const <S as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind continue];
}
bb1: {
StorageLive(_3);
_3 = ShallowInitBox(move _2, S);
(*_3) = S::new() -> [return: bb2, unwind: bb8];
}
bb2: {
_1 = move _3;
- drop(_3) -> [return: bb3, unwind continue];
+ goto -> bb3;
}
bb3: {
StorageDead(_3);
StorageLive(_4);
StorageLive(_5);
_5 = move _1;
_4 = std::mem::drop::<Box<S>>(move _5) -> [return: bb4, unwind: bb6];
}
bb4: {
StorageDead(_5);
StorageDead(_4);
_0 = const ();
- drop(_1) -> [return: bb5, unwind continue];
+ goto -> bb5;
}
bb5: {
StorageDead(_1);
return;
}
bb6 (cleanup): {
- drop(_5) -> [return: bb7, unwind terminate(cleanup)];
+ goto -> bb7;
}
bb7 (cleanup): {
- drop(_1) -> [return: bb9, unwind terminate(cleanup)];
+ goto -> bb9;
}
bb8 (cleanup): {
- drop(_3) -> [return: bb9, unwind terminate(cleanup)];
+ goto -> bb12;
}
bb9 (cleanup): {
resume;
+ }
+
+ bb10 (cleanup): {
+ _6 = &mut _3;
+ _7 = <Box<S> as Drop>::drop(move _6) -> [return: bb9, unwind terminate(cleanup)];
+ }
+
+ bb11 (cleanup): {
+ goto -> bb10;
+ }
+
+ bb12 (cleanup): {
+ _8 = copy ((_3.0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>) as *const S (Transmute);
+ goto -> bb11;
}
}

View file

@ -1,39 +0,0 @@
//@ test-mir-pass: ElaborateDrops
//@ needs-unwind
#![feature(rustc_attrs, liballoc_internals)]
// EMIT_MIR box_expr.main.ElaborateDrops.diff
fn main() {
// CHECK-LABEL: fn main(
// CHECK: [[ptr:_.*]] = move {{_.*}} as *const S (Transmute);
// CHECK: [[nonnull:_.*]] = NonNull::<S> { pointer: move [[ptr]] };
// CHECK: [[unique:_.*]] = std::ptr::Unique::<S> { pointer: move [[nonnull]], _marker: const PhantomData::<S> };
// CHECK: [[box:_.*]] = Box::<S>(move [[unique]], const std::alloc::Global);
// CHECK: [[ptr:_.*]] = copy (([[box]].0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>) as *const S (Transmute);
// CHECK: (*[[ptr]]) = S::new() -> [return: [[ret:bb.*]], unwind: [[unwind:bb.*]]];
// CHECK: [[ret]]: {
// CHECK: [[box2:_.*]] = move [[box]];
// CHECK: [[box3:_.*]] = move [[box2]];
// CHECK: std::mem::drop::<Box<S>>(move [[box3]])
// CHECK: [[unwind]] (cleanup): {
// CHECK: [[boxref:_.*]] = &mut [[box]];
// CHECK: <Box<S> as Drop>::drop(move [[boxref]])
let x = std::boxed::box_new(S::new());
drop(x);
}
struct S;
impl S {
fn new() -> Self {
S
}
}
impl Drop for S {
fn drop(&mut self) {
println!("splat!");
}
}

View file

@ -0,0 +1,68 @@
// MIR for `move_out_by_subslice` after CleanupPostBorrowck
fn move_out_by_subslice() -> () {
let mut _0: ();
let _1: [std::boxed::Box<i32>; 2];
let mut _2: std::boxed::Box<i32>;
let mut _3: std::boxed::Box<i32>;
scope 1 {
debug a => _1;
let _4: [std::boxed::Box<i32>; 2];
scope 2 {
debug _y => _4;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = Box::<i32>::new(const 1_i32) -> [return: bb1, unwind: bb9];
}
bb1: {
StorageLive(_3);
_3 = Box::<i32>::new(const 2_i32) -> [return: bb2, unwind: bb8];
}
bb2: {
_1 = [move _2, move _3];
drop(_3) -> [return: bb3, unwind: bb8];
}
bb3: {
StorageDead(_3);
drop(_2) -> [return: bb4, unwind: bb9];
}
bb4: {
StorageDead(_2);
nop;
PlaceMention(_1);
StorageLive(_4);
_4 = move _1[0..2];
_0 = const ();
drop(_4) -> [return: bb5, unwind: bb7];
}
bb5: {
StorageDead(_4);
drop(_1) -> [return: bb6, unwind: bb9];
}
bb6: {
StorageDead(_1);
return;
}
bb7 (cleanup): {
drop(_1) -> [return: bb9, unwind terminate(cleanup)];
}
bb8 (cleanup): {
drop(_2) -> [return: bb9, unwind terminate(cleanup)];
}
bb9 (cleanup): {
resume;
}
}

View file

@ -1,99 +0,0 @@
// MIR for `move_out_by_subslice` after built
fn move_out_by_subslice() -> () {
let mut _0: ();
let _1: [std::boxed::Box<i32>; 2];
let mut _2: std::boxed::Box<i32>;
let mut _3: *mut u8;
let mut _4: std::boxed::Box<i32>;
let mut _5: std::boxed::Box<i32>;
let mut _6: *mut u8;
let mut _7: std::boxed::Box<i32>;
scope 1 {
debug a => _1;
let _8: [std::boxed::Box<i32>; 2];
scope 2 {
debug _y => _8;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_3 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind: bb13];
}
bb1: {
StorageLive(_4);
_4 = ShallowInitBox(move _3, i32);
(*_4) = const 1_i32;
_2 = move _4;
drop(_4) -> [return: bb2, unwind: bb12];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
_6 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb3, unwind: bb12];
}
bb3: {
StorageLive(_7);
_7 = ShallowInitBox(move _6, i32);
(*_7) = const 2_i32;
_5 = move _7;
drop(_7) -> [return: bb4, unwind: bb11];
}
bb4: {
StorageDead(_7);
_1 = [move _2, move _5];
drop(_5) -> [return: bb5, unwind: bb12];
}
bb5: {
StorageDead(_5);
drop(_2) -> [return: bb6, unwind: bb13];
}
bb6: {
StorageDead(_2);
FakeRead(ForLet(None), _1);
PlaceMention(_1);
StorageLive(_8);
_8 = move _1[0..2];
_0 = const ();
drop(_8) -> [return: bb8, unwind: bb10];
}
bb7: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb8: {
StorageDead(_8);
drop(_1) -> [return: bb9, unwind: bb13];
}
bb9: {
StorageDead(_1);
return;
}
bb10 (cleanup): {
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
}
bb11 (cleanup): {
drop(_5) -> [return: bb12, unwind terminate(cleanup)];
}
bb12 (cleanup): {
drop(_2) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,68 @@
// MIR for `move_out_from_end` after CleanupPostBorrowck
fn move_out_from_end() -> () {
let mut _0: ();
let _1: [std::boxed::Box<i32>; 2];
let mut _2: std::boxed::Box<i32>;
let mut _3: std::boxed::Box<i32>;
scope 1 {
debug a => _1;
let _4: std::boxed::Box<i32>;
scope 2 {
debug _y => _4;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = Box::<i32>::new(const 1_i32) -> [return: bb1, unwind: bb9];
}
bb1: {
StorageLive(_3);
_3 = Box::<i32>::new(const 2_i32) -> [return: bb2, unwind: bb8];
}
bb2: {
_1 = [move _2, move _3];
drop(_3) -> [return: bb3, unwind: bb8];
}
bb3: {
StorageDead(_3);
drop(_2) -> [return: bb4, unwind: bb9];
}
bb4: {
StorageDead(_2);
nop;
PlaceMention(_1);
StorageLive(_4);
_4 = move _1[1 of 2];
_0 = const ();
drop(_4) -> [return: bb5, unwind: bb7];
}
bb5: {
StorageDead(_4);
drop(_1) -> [return: bb6, unwind: bb9];
}
bb6: {
StorageDead(_1);
return;
}
bb7 (cleanup): {
drop(_1) -> [return: bb9, unwind terminate(cleanup)];
}
bb8 (cleanup): {
drop(_2) -> [return: bb9, unwind terminate(cleanup)];
}
bb9 (cleanup): {
resume;
}
}

View file

@ -1,99 +0,0 @@
// MIR for `move_out_from_end` after built
fn move_out_from_end() -> () {
let mut _0: ();
let _1: [std::boxed::Box<i32>; 2];
let mut _2: std::boxed::Box<i32>;
let mut _3: *mut u8;
let mut _4: std::boxed::Box<i32>;
let mut _5: std::boxed::Box<i32>;
let mut _6: *mut u8;
let mut _7: std::boxed::Box<i32>;
scope 1 {
debug a => _1;
let _8: std::boxed::Box<i32>;
scope 2 {
debug _y => _8;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_3 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind: bb13];
}
bb1: {
StorageLive(_4);
_4 = ShallowInitBox(move _3, i32);
(*_4) = const 1_i32;
_2 = move _4;
drop(_4) -> [return: bb2, unwind: bb12];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
_6 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb3, unwind: bb12];
}
bb3: {
StorageLive(_7);
_7 = ShallowInitBox(move _6, i32);
(*_7) = const 2_i32;
_5 = move _7;
drop(_7) -> [return: bb4, unwind: bb11];
}
bb4: {
StorageDead(_7);
_1 = [move _2, move _5];
drop(_5) -> [return: bb5, unwind: bb12];
}
bb5: {
StorageDead(_5);
drop(_2) -> [return: bb6, unwind: bb13];
}
bb6: {
StorageDead(_2);
FakeRead(ForLet(None), _1);
PlaceMention(_1);
StorageLive(_8);
_8 = move _1[1 of 2];
_0 = const ();
drop(_8) -> [return: bb8, unwind: bb10];
}
bb7: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb8: {
StorageDead(_8);
drop(_1) -> [return: bb9, unwind: bb13];
}
bb9: {
StorageDead(_1);
return;
}
bb10 (cleanup): {
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
}
bb11 (cleanup): {
drop(_5) -> [return: bb12, unwind terminate(cleanup)];
}
bb12 (cleanup): {
drop(_2) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume;
}
}

View file

@ -1,16 +1,17 @@
//@ compile-flags: -Zmir-opt-level=0
// skip-filecheck
#![feature(liballoc_internals, rustc_attrs)]
// EMIT_MIR uniform_array_move_out.move_out_from_end.built.after.mir
// Can't emit `built.after` here as that contains user type annotations which contain DefId that
// change all the time.
// EMIT_MIR uniform_array_move_out.move_out_from_end.CleanupPostBorrowck.after.mir
fn move_out_from_end() {
let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
let a = [Box::new(1), Box::new(2)];
let [.., _y] = a;
}
// EMIT_MIR uniform_array_move_out.move_out_by_subslice.built.after.mir
// EMIT_MIR uniform_array_move_out.move_out_by_subslice.CleanupPostBorrowck.after.mir
fn move_out_by_subslice() {
let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
let a = [Box::new(1), Box::new(2)];
let [_y @ ..] = a;
}

View file

@ -0,0 +1,58 @@
// MIR for `box_new` after CleanupPostBorrowck
fn box_new(_1: T) -> Box<[T; 1024]> {
debug x => _1;
let mut _0: std::boxed::Box<[T; 1024]>;
let mut _2: std::boxed::Box<std::mem::MaybeUninit<[T; 1024]>>;
let mut _3: std::boxed::Box<std::mem::MaybeUninit<[T; 1024]>>;
let mut _4: std::boxed::Box<std::mem::MaybeUninit<[T; 1024]>>;
let mut _5: T;
scope 1 {
debug b => _2;
}
bb0: {
StorageLive(_2);
_2 = Box::<[T; 1024]>::new_uninit() -> [return: bb1, unwind: bb7];
}
bb1: {
nop;
StorageLive(_3);
StorageLive(_4);
_4 = move _2;
StorageLive(_5);
_5 = copy _1;
((((*_4).1: std::mem::ManuallyDrop<[T; 1024]>).0: std::mem::MaybeDangling<[T; 1024]>).0: [T; 1024]) = [move _5; 1024];
StorageDead(_5);
_3 = move _4;
drop(_4) -> [return: bb2, unwind: bb5];
}
bb2: {
StorageDead(_4);
_0 = Box::<MaybeUninit<[T; 1024]>>::assume_init(move _3) -> [return: bb3, unwind: bb5];
}
bb3: {
StorageDead(_3);
drop(_2) -> [return: bb4, unwind: bb7];
}
bb4: {
StorageDead(_2);
return;
}
bb5 (cleanup): {
drop(_3) -> [return: bb6, unwind terminate(cleanup)];
}
bb6 (cleanup): {
drop(_2) -> [return: bb7, unwind terminate(cleanup)];
}
bb7 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,29 @@
//! Ensure we don't generate unnecessary copys for `write_via_move`.
//@ compile-flags: -Zmir-opt-level=0
#![feature(liballoc_internals)]
extern crate alloc;
// Can't emit `built.after` here as that contains user type annotations which contain DefId that
// change all the time.
// EMIT_MIR write_box_via_move.box_new.CleanupPostBorrowck.after.mir
// CHECK-LABEL: fn box_new
#[inline(never)]
fn box_new<T: Copy>(x: T) -> Box<[T; 1024]> {
let mut b = Box::new_uninit();
// Ensure the array gets constructed directly into the deref'd pointer.
// CHECK: (*[[TEMP1:_.+]]) = [{{(move|copy) _.+}}; 1024];
unsafe { alloc::intrinsics::write_box_via_move(b, [x; 1024]).assume_init() }
}
// EMIT_MIR write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir
// CHECK-LABEL: fn vec_macro
fn vec_macro() -> Vec<i32> {
// CHECK: (*[[TEMP1:_.+]]) = [const 0_i32, const 1_i32,
vec![0, 1, 2, 3, 4, 5, 6, 7]
}
fn main() {
box_new(0);
vec_macro();
}

View file

@ -0,0 +1,37 @@
// MIR for `vec_macro` after CleanupPostBorrowck
fn vec_macro() -> Vec<i32> {
let mut _0: std::vec::Vec<i32>;
let mut _1: std::boxed::Box<std::mem::MaybeUninit<[i32; 8]>>;
let mut _2: std::boxed::Box<std::mem::MaybeUninit<[i32; 8]>>;
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = Box::<[i32; 8]>::new_uninit() -> [return: bb1, unwind: bb5];
}
bb1: {
((((*_2).1: std::mem::ManuallyDrop<[i32; 8]>).0: std::mem::MaybeDangling<[i32; 8]>).0: [i32; 8]) = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32, const 6_i32, const 7_i32];
_1 = move _2;
drop(_2) -> [return: bb2, unwind: bb4];
}
bb2: {
StorageDead(_2);
_0 = std::boxed::box_assume_init_into_vec_unsafe::<i32, 8>(move _1) -> [return: bb3, unwind: bb4];
}
bb3: {
StorageDead(_1);
return;
}
bb4 (cleanup): {
drop(_1) -> [return: bb5, unwind terminate(cleanup)];
}
bb5 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,76 @@
// MIR for `box_new` after CleanupPostBorrowck
fn box_new(_1: T) -> Box<[T; 1024]> {
debug x => _1;
let mut _0: std::boxed::Box<[T; 1024]>;
let mut _2: std::boxed::Box<std::mem::MaybeUninit<[T; 1024]>>;
let mut _4: &mut std::mem::MaybeUninit<[T; 1024]>;
let mut _5: &mut std::mem::MaybeUninit<[T; 1024]>;
let _6: ();
let mut _7: *mut [T; 1024];
let mut _8: T;
let mut _9: std::boxed::Box<std::mem::MaybeUninit<[T; 1024]>>;
scope 1 {
debug b => _2;
let _3: *mut [T; 1024];
scope 2 {
debug ptr => _3;
}
}
bb0: {
StorageLive(_2);
_2 = Box::<[T; 1024]>::new_uninit() -> [return: bb1, unwind: bb7];
}
bb1: {
nop;
StorageLive(_3);
StorageLive(_4);
StorageLive(_5);
_5 = &mut (*_2);
_4 = &mut (*_5);
_3 = MaybeUninit::<[T; 1024]>::as_mut_ptr(move _4) -> [return: bb2, unwind: bb6];
}
bb2: {
StorageDead(_4);
nop;
StorageDead(_5);
StorageLive(_6);
StorageLive(_7);
_7 = copy _3;
StorageLive(_8);
_8 = copy _1;
(*_7) = [move _8; 1024];
StorageDead(_8);
StorageDead(_7);
StorageDead(_6);
StorageLive(_9);
_9 = move _2;
_0 = Box::<MaybeUninit<[T; 1024]>>::assume_init(move _9) -> [return: bb3, unwind: bb5];
}
bb3: {
StorageDead(_9);
StorageDead(_3);
drop(_2) -> [return: bb4, unwind: bb7];
}
bb4: {
StorageDead(_2);
return;
}
bb5 (cleanup): {
drop(_9) -> [return: bb6, unwind terminate(cleanup)];
}
bb6 (cleanup): {
drop(_2) -> [return: bb7, unwind terminate(cleanup)];
}
bb7 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,23 @@
//! Ensure we don't generate unnecessary copys for `write_via_move`.
//@ compile-flags: -Zmir-opt-level=0
#![feature(core_intrinsics)]
use std::mem;
// Can't emit `built.after` here as that contains user type annotations which contain DefId that
// change all the time.
// EMIT_MIR write_via_move.box_new.CleanupPostBorrowck.after.mir
// CHECK-LABEL: fn box_new
#[inline(never)]
fn box_new<T: Copy>(x: T) -> Box<[T; 1024]> {
let mut b = Box::new_uninit();
let ptr = mem::MaybeUninit::as_mut_ptr(&mut *b);
// Ensure the array gets constructed directly into the deref'd pointer.
// CHECK: (*[[TEMP1:_.+]]) = [{{(move|copy) _.+}}; 1024];
unsafe { std::intrinsics::write_via_move(ptr, [x; 1024]) };
unsafe { b.assume_init() }
}
fn main() {
box_new(0);
}

View file

@ -1,59 +0,0 @@
- // MIR for `main` before GVN
+ // MIR for `main` after GVN
fn main() -> () {
let mut _0: ();
let _1: i32;
let mut _2: i32;
let mut _3: std::boxed::Box<i32>;
let mut _4: *mut u8;
let mut _5: std::boxed::Box<i32>;
let mut _6: *const i32;
let mut _7: std::ptr::NonNull<i32>;
let mut _8: std::ptr::Unique<i32>;
let mut _9: *const i32;
let mut _10: *const i32;
scope 1 {
debug x => _1;
}
bb0: {
StorageLive(_1);
- StorageLive(_2);
+ nop;
StorageLive(_3);
_4 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind unreachable];
}
bb1: {
StorageLive(_5);
- _6 = move _4 as *const i32 (Transmute);
- _7 = NonNull::<i32> { pointer: move _6 };
- _8 = std::ptr::Unique::<i32> { pointer: move _7, _marker: const PhantomData::<i32> };
+ _6 = copy _4 as *const i32 (PtrToPtr);
+ _7 = NonNull::<i32> { pointer: copy _6 };
+ _8 = std::ptr::Unique::<i32> { pointer: copy _7, _marker: const PhantomData::<i32> };
_5 = Box::<i32>(move _8, const std::alloc::Global);
- _9 = copy ((_5.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
- (*_9) = const 42_i32;
+ _9 = copy _6;
+ (*_6) = const 42_i32;
_3 = move _5;
StorageDead(_5);
_10 = copy ((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
_2 = copy (*_10);
- _1 = Add(move _2, const 0_i32);
- StorageDead(_2);
+ _1 = copy _2;
+ nop;
drop(_3) -> [return: bb2, unwind unreachable];
}
bb2: {
StorageDead(_3);
_0 = const ();
StorageDead(_1);
return;
}
}

View file

@ -1,63 +0,0 @@
- // MIR for `main` before GVN
+ // MIR for `main` after GVN
fn main() -> () {
let mut _0: ();
let _1: i32;
let mut _2: i32;
let mut _3: std::boxed::Box<i32>;
let mut _4: *mut u8;
let mut _5: std::boxed::Box<i32>;
let mut _6: *const i32;
let mut _7: std::ptr::NonNull<i32>;
let mut _8: std::ptr::Unique<i32>;
let mut _9: *const i32;
let mut _10: *const i32;
scope 1 {
debug x => _1;
}
bb0: {
StorageLive(_1);
- StorageLive(_2);
+ nop;
StorageLive(_3);
_4 = alloc::alloc::exchange_malloc(const <i32 as std::mem::SizedTypeProperties>::SIZE, const <i32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind continue];
}
bb1: {
StorageLive(_5);
- _6 = move _4 as *const i32 (Transmute);
- _7 = NonNull::<i32> { pointer: move _6 };
- _8 = std::ptr::Unique::<i32> { pointer: move _7, _marker: const PhantomData::<i32> };
+ _6 = copy _4 as *const i32 (PtrToPtr);
+ _7 = NonNull::<i32> { pointer: copy _6 };
+ _8 = std::ptr::Unique::<i32> { pointer: copy _7, _marker: const PhantomData::<i32> };
_5 = Box::<i32>(move _8, const std::alloc::Global);
- _9 = copy ((_5.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
- (*_9) = const 42_i32;
+ _9 = copy _6;
+ (*_6) = const 42_i32;
_3 = move _5;
StorageDead(_5);
_10 = copy ((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
_2 = copy (*_10);
- _1 = Add(move _2, const 0_i32);
- StorageDead(_2);
+ _1 = copy _2;
+ nop;
drop(_3) -> [return: bb2, unwind: bb3];
}
bb2: {
StorageDead(_3);
_0 = const ();
StorageDead(_1);
return;
}
bb3 (cleanup): {
resume;
}
}

View file

@ -1,17 +0,0 @@
//@ test-mir-pass: GVN
//@ compile-flags: -O
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![feature(rustc_attrs, liballoc_internals)]
// Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
// EMIT_MIR boxes.main.GVN.diff
fn main() {
// CHECK-LABEL: fn main(
// CHECK: debug x => [[x:_.*]];
// CHECK: (*{{_.*}}) = const 42_i32;
// CHECK: [[tmp:_.*]] = copy (*{{_.*}});
// CHECK: [[x]] = copy [[tmp]];
let x = *(std::boxed::box_new(42)) + 0;
}

View file

@ -11,9 +11,9 @@
let mut _9: *const [()];
let mut _10: std::boxed::Box<()>;
let mut _11: *const ();
let mut _16: usize;
let mut _17: usize;
let mut _26: usize;
let mut _14: usize;
let mut _15: usize;
let mut _24: usize;
scope 1 {
debug vp_ctx => _1;
let _5: *const ();
@ -26,49 +26,49 @@
scope 4 {
debug _x => _8;
}
scope 19 (inlined foo) {
let mut _27: *const [()];
scope 20 (inlined foo) {
let mut _25: *const [()];
}
}
scope 17 (inlined slice_from_raw_parts::<()>) {
scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) {
scope 18 (inlined slice_from_raw_parts::<()>) {
scope 19 (inlined std::ptr::from_raw_parts::<[()], ()>) {
}
}
}
}
scope 5 (inlined Box::<()>::new) {
let mut _12: *mut u8;
let mut _13: *const ();
let mut _14: std::ptr::NonNull<()>;
let mut _15: std::ptr::Unique<()>;
scope 6 (inlined alloc::alloc::exchange_malloc) {
let _18: std::alloc::Layout;
let mut _19: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _20: isize;
let mut _22: !;
scope 7 {
let _21: std::ptr::NonNull<[u8]>;
scope 8 {
scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 14 (inlined NonNull::<[u8]>::cast::<u8>) {
let mut _25: *mut [u8];
scope 15 (inlined NonNull::<[u8]>::as_ptr) {
let mut _12: *mut ();
let mut _13: *mut u8;
scope 6 {
}
scope 7 (inlined boxed::box_new_uninit) {
let _16: std::alloc::Layout;
let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _18: isize;
let mut _20: !;
scope 8 {
let _19: std::ptr::NonNull<[u8]>;
scope 9 {
scope 13 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 14 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 15 (inlined NonNull::<[u8]>::cast::<u8>) {
let mut _23: *mut [u8];
scope 16 (inlined NonNull::<[u8]>::as_ptr) {
}
}
}
scope 16 (inlined NonNull::<u8>::as_ptr) {
scope 17 (inlined NonNull::<u8>::as_ptr) {
}
}
}
scope 10 (inlined <std::alloc::Global as Allocator>::allocate) {
scope 11 (inlined std::alloc::Global::alloc_impl) {
scope 11 (inlined <std::alloc::Global as Allocator>::allocate) {
scope 12 (inlined std::alloc::Global::alloc_impl) {
}
}
}
scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) {
let _23: ();
let mut _24: std::ptr::Alignment;
scope 10 (inlined #[track_caller] Layout::from_size_align_unchecked) {
let _21: ();
let mut _22: std::ptr::Alignment;
}
}
}
@ -83,18 +83,16 @@
StorageLive(_12);
StorageLive(_13);
StorageLive(_14);
- _14 = const <() as std::mem::SizedTypeProperties>::SIZE;
+ _14 = const 0_usize;
StorageLive(_15);
- _15 = const <() as std::mem::SizedTypeProperties>::ALIGN;
+ _15 = const 1_usize;
StorageLive(_16);
- _16 = const <() as std::mem::SizedTypeProperties>::SIZE;
+ _16 = const 0_usize;
StorageLive(_17);
- _17 = const <() as std::mem::SizedTypeProperties>::ALIGN;
+ _17 = const 1_usize;
StorageLive(_18);
StorageLive(_19);
StorageLive(_20);
StorageLive(_21);
StorageLive(_22);
StorageLive(_23);
switchInt(UbChecks) -> [0: bb6, otherwise: bb5];
}
@ -109,35 +107,31 @@
}
bb3: {
- _22 = handle_alloc_error(move _18) -> unwind unreachable;
+ _22 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> unwind unreachable;
- _20 = handle_alloc_error(move _16) -> unwind unreachable;
+ _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> unwind unreachable;
}
bb4: {
_21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>);
- StorageLive(_25);
_19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>);
- StorageLive(_23);
+ nop;
_25 = copy _21 as *mut [u8] (Transmute);
_12 = copy _25 as *mut u8 (PtrToPtr);
- StorageDead(_25);
_23 = copy _19 as *mut [u8] (Transmute);
_13 = copy _23 as *mut u8 (PtrToPtr);
- StorageDead(_23);
+ nop;
StorageDead(_19);
StorageDead(_23);
StorageDead(_22);
StorageDead(_17);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
StorageDead(_18);
StorageDead(_17);
StorageDead(_16);
- _13 = copy _12 as *const () (PtrToPtr);
+ _13 = copy _25 as *const () (PtrToPtr);
_14 = NonNull::<()> { pointer: copy _13 };
_15 = std::ptr::Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> };
_3 = Box::<()>(move _15, const std::alloc::Global);
- (*_13) = move _4;
+ (*_13) = const ();
StorageDead(_15);
StorageDead(_14);
- _12 = copy _13 as *mut () (PtrToPtr);
- (*_12) = move _4;
+ _12 = copy _23 as *mut () (PtrToPtr);
+ (*_12) = const ();
_3 = copy _13 as std::boxed::Box<()> (Transmute);
StorageDead(_13);
StorageDead(_12);
StorageDead(_4);
@ -153,21 +147,21 @@
+ nop;
StorageLive(_7);
_7 = copy _5;
StorageLive(_26);
_26 = const 1_usize;
- _6 = *const [()] from (copy _7, copy _26);
StorageLive(_24);
_24 = const 1_usize;
- _6 = *const [()] from (copy _7, copy _24);
+ _6 = *const [()] from (copy _5, const 1_usize);
StorageDead(_26);
StorageDead(_24);
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
_9 = copy _6;
StorageLive(_27);
- _27 = copy _9;
StorageLive(_25);
- _25 = copy _9;
- _8 = copy _9 as *mut () (PtrToPtr);
+ _27 = copy _6;
+ _25 = copy _6;
+ _8 = copy _5 as *mut () (PtrToPtr);
StorageDead(_27);
StorageDead(_25);
StorageDead(_9);
_0 = const ();
StorageDead(_8);
@ -179,25 +173,25 @@
}
bb5: {
- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable];
+ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
- _21 = Layout::from_size_align_unchecked::precondition_check(copy _14, copy _15) -> [return: bb6, unwind unreachable];
+ _21 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
}
bb6: {
StorageLive(_24);
- _24 = copy _17 as std::ptr::Alignment (Transmute);
- _18 = Layout { size: copy _16, align: move _24 };
+ _24 = const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }};
+ _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }};
StorageDead(_24);
StorageLive(_19);
- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable];
+ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}, const false) -> [return: bb7, unwind unreachable];
StorageLive(_22);
- _22 = copy _15 as std::ptr::Alignment (Transmute);
- _16 = Layout { size: copy _14, align: move _22 };
+ _22 = const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }};
+ _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }};
StorageDead(_22);
StorageLive(_17);
- _17 = std::alloc::Global::alloc_impl_runtime(copy _16, const false) -> [return: bb7, unwind unreachable];
+ _17 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}, const false) -> [return: bb7, unwind unreachable];
}
bb7: {
_20 = discriminant(_19);
switchInt(move _20) -> [0: bb4, 1: bb3, otherwise: bb2];
_18 = discriminant(_17);
switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2];
}
+ }
+

View file

@ -11,9 +11,9 @@
let mut _9: *const [()];
let mut _10: std::boxed::Box<()>;
let mut _11: *const ();
let mut _16: usize;
let mut _17: usize;
let mut _26: usize;
let mut _14: usize;
let mut _15: usize;
let mut _24: usize;
scope 1 {
debug vp_ctx => _1;
let _5: *const ();
@ -26,49 +26,49 @@
scope 4 {
debug _x => _8;
}
scope 19 (inlined foo) {
let mut _27: *const [()];
scope 20 (inlined foo) {
let mut _25: *const [()];
}
}
scope 17 (inlined slice_from_raw_parts::<()>) {
scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) {
scope 18 (inlined slice_from_raw_parts::<()>) {
scope 19 (inlined std::ptr::from_raw_parts::<[()], ()>) {
}
}
}
}
scope 5 (inlined Box::<()>::new) {
let mut _12: *mut u8;
let mut _13: *const ();
let mut _14: std::ptr::NonNull<()>;
let mut _15: std::ptr::Unique<()>;
scope 6 (inlined alloc::alloc::exchange_malloc) {
let _18: std::alloc::Layout;
let mut _19: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _20: isize;
let mut _22: !;
scope 7 {
let _21: std::ptr::NonNull<[u8]>;
scope 8 {
scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 14 (inlined NonNull::<[u8]>::cast::<u8>) {
let mut _25: *mut [u8];
scope 15 (inlined NonNull::<[u8]>::as_ptr) {
let mut _12: *mut ();
let mut _13: *mut u8;
scope 6 {
}
scope 7 (inlined boxed::box_new_uninit) {
let _16: std::alloc::Layout;
let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _18: isize;
let mut _20: !;
scope 8 {
let _19: std::ptr::NonNull<[u8]>;
scope 9 {
scope 13 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 14 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 15 (inlined NonNull::<[u8]>::cast::<u8>) {
let mut _23: *mut [u8];
scope 16 (inlined NonNull::<[u8]>::as_ptr) {
}
}
}
scope 16 (inlined NonNull::<u8>::as_ptr) {
scope 17 (inlined NonNull::<u8>::as_ptr) {
}
}
}
scope 10 (inlined <std::alloc::Global as Allocator>::allocate) {
scope 11 (inlined std::alloc::Global::alloc_impl) {
scope 11 (inlined <std::alloc::Global as Allocator>::allocate) {
scope 12 (inlined std::alloc::Global::alloc_impl) {
}
}
}
scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) {
let _23: ();
let mut _24: std::ptr::Alignment;
scope 10 (inlined #[track_caller] Layout::from_size_align_unchecked) {
let _21: ();
let mut _22: std::ptr::Alignment;
}
}
}
@ -83,18 +83,16 @@
StorageLive(_12);
StorageLive(_13);
StorageLive(_14);
- _14 = const <() as std::mem::SizedTypeProperties>::SIZE;
+ _14 = const 0_usize;
StorageLive(_15);
- _15 = const <() as std::mem::SizedTypeProperties>::ALIGN;
+ _15 = const 1_usize;
StorageLive(_16);
- _16 = const <() as std::mem::SizedTypeProperties>::SIZE;
+ _16 = const 0_usize;
StorageLive(_17);
- _17 = const <() as std::mem::SizedTypeProperties>::ALIGN;
+ _17 = const 1_usize;
StorageLive(_18);
StorageLive(_19);
StorageLive(_20);
StorageLive(_21);
StorageLive(_22);
StorageLive(_23);
switchInt(UbChecks) -> [0: bb6, otherwise: bb5];
}
@ -109,35 +107,31 @@
}
bb3: {
- _22 = handle_alloc_error(move _18) -> unwind unreachable;
+ _22 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> unwind unreachable;
- _20 = handle_alloc_error(move _16) -> unwind unreachable;
+ _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}) -> unwind unreachable;
}
bb4: {
_21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>);
- StorageLive(_25);
_19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>);
- StorageLive(_23);
+ nop;
_25 = copy _21 as *mut [u8] (Transmute);
_12 = copy _25 as *mut u8 (PtrToPtr);
- StorageDead(_25);
_23 = copy _19 as *mut [u8] (Transmute);
_13 = copy _23 as *mut u8 (PtrToPtr);
- StorageDead(_23);
+ nop;
StorageDead(_19);
StorageDead(_23);
StorageDead(_22);
StorageDead(_17);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
StorageDead(_18);
StorageDead(_17);
StorageDead(_16);
- _13 = copy _12 as *const () (PtrToPtr);
+ _13 = copy _25 as *const () (PtrToPtr);
_14 = NonNull::<()> { pointer: copy _13 };
_15 = std::ptr::Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> };
_3 = Box::<()>(move _15, const std::alloc::Global);
- (*_13) = move _4;
+ (*_13) = const ();
StorageDead(_15);
StorageDead(_14);
- _12 = copy _13 as *mut () (PtrToPtr);
- (*_12) = move _4;
+ _12 = copy _23 as *mut () (PtrToPtr);
+ (*_12) = const ();
_3 = copy _13 as std::boxed::Box<()> (Transmute);
StorageDead(_13);
StorageDead(_12);
StorageDead(_4);
@ -153,21 +147,21 @@
+ nop;
StorageLive(_7);
_7 = copy _5;
StorageLive(_26);
_26 = const 1_usize;
- _6 = *const [()] from (copy _7, copy _26);
StorageLive(_24);
_24 = const 1_usize;
- _6 = *const [()] from (copy _7, copy _24);
+ _6 = *const [()] from (copy _5, const 1_usize);
StorageDead(_26);
StorageDead(_24);
StorageDead(_7);
StorageLive(_8);
StorageLive(_9);
_9 = copy _6;
StorageLive(_27);
- _27 = copy _9;
StorageLive(_25);
- _25 = copy _9;
- _8 = copy _9 as *mut () (PtrToPtr);
+ _27 = copy _6;
+ _25 = copy _6;
+ _8 = copy _5 as *mut () (PtrToPtr);
StorageDead(_27);
StorageDead(_25);
StorageDead(_9);
_0 = const ();
StorageDead(_8);
@ -179,25 +173,25 @@
}
bb5: {
- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable];
+ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
- _21 = Layout::from_size_align_unchecked::precondition_check(copy _14, copy _15) -> [return: bb6, unwind unreachable];
+ _21 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
}
bb6: {
StorageLive(_24);
- _24 = copy _17 as std::ptr::Alignment (Transmute);
- _18 = Layout { size: copy _16, align: move _24 };
+ _24 = const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }};
+ _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }};
StorageDead(_24);
StorageLive(_19);
- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable];
+ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}, const false) -> [return: bb7, unwind unreachable];
StorageLive(_22);
- _22 = copy _15 as std::ptr::Alignment (Transmute);
- _16 = Layout { size: copy _14, align: move _22 };
+ _22 = const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }};
+ _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }};
StorageDead(_22);
StorageLive(_17);
- _17 = std::alloc::Global::alloc_impl_runtime(copy _16, const false) -> [return: bb7, unwind unreachable];
+ _17 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }} }}, const false) -> [return: bb7, unwind unreachable];
}
bb7: {
_20 = discriminant(_19);
switchInt(move _20) -> [0: bb4, 1: bb3, otherwise: bb2];
_18 = discriminant(_17);
switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2];
}
+ }
+

View file

@ -202,7 +202,7 @@
+ StorageLive(_42);
+ _42 = Option::<()>::None;
+ _35 = copy ((*_37).0: std::option::Option<()>);
+ ((*_37).0: std::option::Option<()>) = copy _42;
+ ((*_37).0: std::option::Option<()>) = move _42;
+ StorageDead(_42);
+ StorageLive(_43);
+ _43 = discriminant(_35);

View file

@ -213,7 +213,7 @@
+ StorageLive(_42);
+ _42 = Option::<()>::None;
+ _35 = copy ((*_37).0: std::option::Option<()>);
+ ((*_37).0: std::option::Option<()>) = copy _42;
+ ((*_37).0: std::option::Option<()>) = move _42;
+ StorageDead(_42);
+ StorageLive(_43);
+ _43 = discriminant(_35);

View file

@ -5,9 +5,9 @@
#![feature(rustc_attrs, liballoc_internals)]
// EMIT_MIR issue_62289.test.ElaborateDrops.before.mir
fn test() -> Option<Box<u32>> {
Some(std::boxed::box_new(None?))
// EMIT_MIR issue_62289.test.ElaborateDrops.after.mir
fn test() -> Option<Vec<u32>> {
Some(vec![None?])
}
fn main() {

View file

@ -0,0 +1,119 @@
// MIR for `test` after ElaborateDrops
fn test() -> Option<Vec<u32>> {
let mut _0: std::option::Option<std::vec::Vec<u32>>;
let mut _1: std::vec::Vec<u32>;
let mut _2: std::boxed::Box<std::mem::MaybeUninit<[u32; 1]>>;
let mut _3: std::boxed::Box<std::mem::MaybeUninit<[u32; 1]>>;
let mut _4: u32;
let mut _5: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>;
let mut _6: std::option::Option<u32>;
let mut _7: isize;
let _8: std::option::Option<std::convert::Infallible>;
let mut _9: !;
let mut _10: std::option::Option<std::convert::Infallible>;
let _11: u32;
scope 1 {
debug residual => _8;
scope 2 {
}
}
scope 3 {
debug val => _11;
scope 4 {
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
_3 = Box::<[u32; 1]>::new_uninit() -> [return: bb1, unwind: bb14];
}
bb1: {
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_6 = Option::<u32>::None;
_5 = <Option<u32> as Try>::branch(move _6) -> [return: bb2, unwind: bb13];
}
bb2: {
StorageDead(_6);
PlaceMention(_5);
_7 = discriminant(_5);
switchInt(move _7) -> [0: bb4, 1: bb5, otherwise: bb3];
}
bb3: {
unreachable;
}
bb4: {
StorageLive(_11);
_11 = copy ((_5 as Continue).0: u32);
_4 = copy _11;
StorageDead(_11);
((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4];
StorageDead(_4);
_2 = move _3;
goto -> bb7;
}
bb5: {
StorageLive(_8);
_8 = copy ((_5 as Break).0: std::option::Option<std::convert::Infallible>);
StorageLive(_10);
_10 = copy _8;
_0 = <Option<Vec<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _10) -> [return: bb6, unwind: bb13];
}
bb6: {
StorageDead(_10);
StorageDead(_8);
StorageDead(_4);
drop(_3) -> [return: bb10, unwind: bb14];
}
bb7: {
StorageDead(_3);
_1 = std::boxed::box_assume_init_into_vec_unsafe::<u32, 1>(move _2) -> [return: bb8, unwind: bb12];
}
bb8: {
StorageDead(_2);
_0 = Option::<Vec<u32>>::Some(move _1);
goto -> bb9;
}
bb9: {
StorageDead(_1);
StorageDead(_5);
goto -> bb11;
}
bb10: {
StorageDead(_3);
StorageDead(_2);
StorageDead(_1);
StorageDead(_5);
goto -> bb11;
}
bb11: {
return;
}
bb12 (cleanup): {
goto -> bb14;
}
bb13 (cleanup): {
drop(_3) -> [return: bb14, unwind terminate(cleanup)];
}
bb14 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,119 @@
// MIR for `test` after ElaborateDrops
fn test() -> Option<Vec<u32>> {
let mut _0: std::option::Option<std::vec::Vec<u32>>;
let mut _1: std::vec::Vec<u32>;
let mut _2: std::boxed::Box<std::mem::MaybeUninit<[u32; 1]>>;
let mut _3: std::boxed::Box<std::mem::MaybeUninit<[u32; 1]>>;
let mut _4: u32;
let mut _5: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>;
let mut _6: std::option::Option<u32>;
let mut _7: isize;
let _8: std::option::Option<std::convert::Infallible>;
let mut _9: !;
let mut _10: std::option::Option<std::convert::Infallible>;
let _11: u32;
scope 1 {
debug residual => _8;
scope 2 {
}
}
scope 3 {
debug val => _11;
scope 4 {
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
_3 = Box::<[u32; 1]>::new_uninit() -> [return: bb1, unwind continue];
}
bb1: {
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_6 = Option::<u32>::None;
_5 = <Option<u32> as Try>::branch(move _6) -> [return: bb2, unwind: bb13];
}
bb2: {
StorageDead(_6);
PlaceMention(_5);
_7 = discriminant(_5);
switchInt(move _7) -> [0: bb4, 1: bb5, otherwise: bb3];
}
bb3: {
unreachable;
}
bb4: {
StorageLive(_11);
_11 = copy ((_5 as Continue).0: u32);
_4 = copy _11;
StorageDead(_11);
((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4];
StorageDead(_4);
_2 = move _3;
goto -> bb7;
}
bb5: {
StorageLive(_8);
_8 = copy ((_5 as Break).0: std::option::Option<std::convert::Infallible>);
StorageLive(_10);
_10 = copy _8;
_0 = <Option<Vec<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _10) -> [return: bb6, unwind: bb13];
}
bb6: {
StorageDead(_10);
StorageDead(_8);
StorageDead(_4);
drop(_3) -> [return: bb10, unwind: bb14];
}
bb7: {
StorageDead(_3);
_1 = std::boxed::box_assume_init_into_vec_unsafe::<u32, 1>(move _2) -> [return: bb8, unwind: bb12];
}
bb8: {
StorageDead(_2);
_0 = Option::<Vec<u32>>::Some(move _1);
goto -> bb9;
}
bb9: {
StorageDead(_1);
StorageDead(_5);
goto -> bb11;
}
bb10: {
StorageDead(_3);
StorageDead(_2);
StorageDead(_1);
StorageDead(_5);
goto -> bb11;
}
bb11: {
return;
}
bb12 (cleanup): {
goto -> bb14;
}
bb13 (cleanup): {
drop(_3) -> [return: bb14, unwind terminate(cleanup)];
}
bb14 (cleanup): {
resume;
}
}

View file

@ -1,108 +0,0 @@
// MIR for `test` before ElaborateDrops
fn test() -> Option<Box<u32>> {
let mut _0: std::option::Option<std::boxed::Box<u32>>;
let mut _1: std::boxed::Box<u32>;
let mut _2: *mut u8;
let mut _3: std::boxed::Box<u32>;
let mut _4: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>;
let mut _5: std::option::Option<u32>;
let mut _6: isize;
let _7: std::option::Option<std::convert::Infallible>;
let mut _8: !;
let mut _9: std::option::Option<std::convert::Infallible>;
let _10: u32;
scope 1 {
debug residual => _7;
scope 2 {
}
}
scope 3 {
debug val => _10;
scope 4 {
}
}
bb0: {
StorageLive(_1);
_2 = alloc::alloc::exchange_malloc(const <u32 as std::mem::SizedTypeProperties>::SIZE, const <u32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind: bb13];
}
bb1: {
StorageLive(_3);
_3 = ShallowInitBox(move _2, u32);
StorageLive(_4);
StorageLive(_5);
_5 = Option::<u32>::None;
_4 = <Option<u32> as Try>::branch(move _5) -> [return: bb2, unwind: bb12];
}
bb2: {
StorageDead(_5);
PlaceMention(_4);
_6 = discriminant(_4);
switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb3];
}
bb3: {
unreachable;
}
bb4: {
StorageLive(_10);
_10 = copy ((_4 as Continue).0: u32);
(*_3) = copy _10;
StorageDead(_10);
_1 = move _3;
drop(_3) -> [return: bb7, unwind: bb11];
}
bb5: {
StorageLive(_7);
_7 = copy ((_4 as Break).0: std::option::Option<std::convert::Infallible>);
StorageLive(_9);
_9 = copy _7;
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _9) -> [return: bb6, unwind: bb12];
}
bb6: {
StorageDead(_9);
StorageDead(_7);
drop(_3) -> [return: bb9, unwind: bb13];
}
bb7: {
StorageDead(_3);
_0 = Option::<Box<u32>>::Some(move _1);
drop(_1) -> [return: bb8, unwind: bb13];
}
bb8: {
StorageDead(_1);
StorageDead(_4);
goto -> bb10;
}
bb9: {
StorageDead(_3);
StorageDead(_1);
StorageDead(_4);
goto -> bb10;
}
bb10: {
return;
}
bb11 (cleanup): {
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
}
bb12 (cleanup): {
drop(_3) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume;
}
}

View file

@ -1,108 +0,0 @@
// MIR for `test` before ElaborateDrops
fn test() -> Option<Box<u32>> {
let mut _0: std::option::Option<std::boxed::Box<u32>>;
let mut _1: std::boxed::Box<u32>;
let mut _2: *mut u8;
let mut _3: std::boxed::Box<u32>;
let mut _4: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>;
let mut _5: std::option::Option<u32>;
let mut _6: isize;
let _7: std::option::Option<std::convert::Infallible>;
let mut _8: !;
let mut _9: std::option::Option<std::convert::Infallible>;
let _10: u32;
scope 1 {
debug residual => _7;
scope 2 {
}
}
scope 3 {
debug val => _10;
scope 4 {
}
}
bb0: {
StorageLive(_1);
_2 = alloc::alloc::exchange_malloc(const <u32 as std::mem::SizedTypeProperties>::SIZE, const <u32 as std::mem::SizedTypeProperties>::ALIGN) -> [return: bb1, unwind continue];
}
bb1: {
StorageLive(_3);
_3 = ShallowInitBox(move _2, u32);
StorageLive(_4);
StorageLive(_5);
_5 = Option::<u32>::None;
_4 = <Option<u32> as Try>::branch(move _5) -> [return: bb2, unwind: bb12];
}
bb2: {
StorageDead(_5);
PlaceMention(_4);
_6 = discriminant(_4);
switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb3];
}
bb3: {
unreachable;
}
bb4: {
StorageLive(_10);
_10 = copy ((_4 as Continue).0: u32);
(*_3) = copy _10;
StorageDead(_10);
_1 = move _3;
drop(_3) -> [return: bb7, unwind: bb11];
}
bb5: {
StorageLive(_7);
_7 = copy ((_4 as Break).0: std::option::Option<std::convert::Infallible>);
StorageLive(_9);
_9 = copy _7;
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _9) -> [return: bb6, unwind: bb12];
}
bb6: {
StorageDead(_9);
StorageDead(_7);
drop(_3) -> [return: bb9, unwind continue];
}
bb7: {
StorageDead(_3);
_0 = Option::<Box<u32>>::Some(move _1);
drop(_1) -> [return: bb8, unwind continue];
}
bb8: {
StorageDead(_1);
StorageDead(_4);
goto -> bb10;
}
bb9: {
StorageDead(_3);
StorageDead(_1);
StorageDead(_4);
goto -> bb10;
}
bb10: {
return;
}
bb11 (cleanup): {
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
}
bb12 (cleanup): {
drop(_3) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume;
}
}

View file

@ -197,17 +197,6 @@ pub fn read_via_copy_uninhabited(r: &Never) -> Never {
unsafe { core::intrinsics::read_via_copy(r) }
}
// EMIT_MIR lower_intrinsics.write_via_move_string.LowerIntrinsics.diff
pub fn write_via_move_string(r: &mut String, v: String) {
// CHECK-LABEL: fn write_via_move_string(
// CHECK: [[ptr:_.*]] = &raw mut (*_1);
// CHECK: [[tmp:_.*]] = move _2;
// CHECK: (*[[ptr]]) = move [[tmp]];
// CHECK: return;
unsafe { core::intrinsics::write_via_move(r, v) }
}
pub enum Never {}
// EMIT_MIR lower_intrinsics.ptr_offset.LowerIntrinsics.diff

View file

@ -1,31 +0,0 @@
- // MIR for `write_via_move_string` before LowerIntrinsics
+ // MIR for `write_via_move_string` after LowerIntrinsics
fn write_via_move_string(_1: &mut String, _2: String) -> () {
debug r => _1;
debug v => _2;
let mut _0: ();
let mut _3: *mut std::string::String;
let mut _4: std::string::String;
bb0: {
StorageLive(_3);
_3 = &raw mut (*_1);
StorageLive(_4);
_4 = move _2;
- _0 = write_via_move::<String>(move _3, move _4) -> [return: bb1, unwind unreachable];
+ (*_3) = move _4;
+ goto -> bb1;
}
bb1: {
StorageDead(_4);
StorageDead(_3);
goto -> bb2;
}
bb2: {
return;
}
}

View file

@ -1,31 +0,0 @@
- // MIR for `write_via_move_string` before LowerIntrinsics
+ // MIR for `write_via_move_string` after LowerIntrinsics
fn write_via_move_string(_1: &mut String, _2: String) -> () {
debug r => _1;
debug v => _2;
let mut _0: ();
let mut _3: *mut std::string::String;
let mut _4: std::string::String;
bb0: {
StorageLive(_3);
_3 = &raw mut (*_1);
StorageLive(_4);
_4 = move _2;
- _0 = write_via_move::<String>(move _3, move _4) -> [return: bb1, unwind unreachable];
+ (*_3) = move _4;
+ goto -> bb1;
}
bb1: {
StorageDead(_4);
StorageDead(_3);
goto -> bb2;
}
bb2: {
return;
}
}

View file

@ -5,33 +5,36 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
debug f => _2;
let mut _0: ();
let mut _10: usize;
let mut _28: std::option::Option<(usize, &T)>;
let mut _31: &impl Fn(usize, &T);
let mut _32: (usize, &T);
let _33: ();
let mut _31: std::option::Option<(usize, &T)>;
let mut _34: &impl Fn(usize, &T);
let mut _35: (usize, &T);
let _36: ();
scope 1 {
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6;
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _9;
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>;
debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _10;
let _29: usize;
let _30: &T;
let _32: usize;
let _33: &T;
scope 2 {
debug i => _29;
debug x => _30;
debug i => _32;
debug x => _33;
}
scope 18 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) {
let mut _23: std::option::Option<&T>;
let mut _26: (usize, bool);
let mut _27: (usize, &T);
let mut _21: std::option::Option<std::convert::Infallible>;
let mut _26: std::option::Option<&T>;
let mut _29: (usize, bool);
let mut _30: (usize, &T);
scope 19 {
let _25: usize;
let _28: usize;
scope 24 {
}
}
scope 20 {
scope 21 {
scope 27 (inlined <Option<(usize, &T)> as FromResidual<Option<Infallible>>>::from_residual) {
let mut _20: isize;
let mut _22: bool;
}
}
}
@ -40,7 +43,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
}
scope 25 (inlined <Option<&T> as Try>::branch) {
let _24: &T;
let _27: &T;
scope 26 {
}
}
@ -49,8 +52,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
let _11: std::ptr::NonNull<T>;
let _13: std::ptr::NonNull<T>;
let mut _16: bool;
let mut _20: usize;
let _22: &T;
let mut _23: usize;
let _25: &T;
scope 29 {
let _12: *const T;
scope 30 {
@ -84,7 +87,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
}
scope 43 (inlined NonNull::<T>::as_ref::<'_>) {
let _21: *const T;
let _24: *const T;
scope 44 (inlined NonNull::<T>::as_ptr) {
}
scope 45 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
@ -169,16 +172,16 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
bb4: {
StorageLive(_31);
StorageLive(_28);
StorageLive(_25);
StorageLive(_29);
StorageLive(_26);
StorageLive(_23);
StorageLive(_11);
StorageLive(_12);
StorageLive(_19);
StorageLive(_20);
StorageLive(_23);
StorageLive(_13);
StorageLive(_22);
StorageLive(_25);
_11 = copy _6;
_12 = copy _9;
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
@ -224,16 +227,23 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
bb10: {
StorageDead(_22);
StorageDead(_25);
StorageDead(_13);
StorageDead(_20);
StorageDead(_23);
StorageDead(_19);
StorageDead(_12);
StorageDead(_11);
StorageDead(_23);
StorageDead(_26);
StorageDead(_25);
StorageLive(_20);
StorageLive(_22);
_20 = discriminant(_21);
_22 = Eq(copy _20, const 0_isize);
assume(move _22);
StorageDead(_22);
StorageDead(_20);
StorageDead(_29);
StorageDead(_28);
StorageDead(_31);
StorageDead(_10);
drop(_2) -> [return: bb11, unwind unreachable];
}
@ -243,51 +253,51 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
}
bb12: {
_20 = SubUnchecked(copy _19, const 1_usize);
_9 = copy _20 as *const T (Transmute);
_23 = SubUnchecked(copy _19, const 1_usize);
_9 = copy _23 as *const T (Transmute);
goto -> bb13;
}
bb13: {
StorageLive(_21);
_21 = copy _11 as *const T (Transmute);
_22 = &(*_21);
StorageDead(_21);
_23 = Option::<&T>::Some(copy _22);
StorageDead(_22);
StorageLive(_24);
_24 = copy _11 as *const T (Transmute);
_25 = &(*_24);
StorageDead(_24);
_26 = Option::<&T>::Some(copy _25);
StorageDead(_25);
StorageDead(_13);
StorageDead(_20);
StorageDead(_23);
StorageDead(_19);
StorageDead(_12);
StorageDead(_11);
_24 = copy ((_23 as Some).0: &T);
StorageDead(_23);
_25 = copy _10;
_26 = AddWithOverflow(copy _10, const 1_usize);
assert(!move (_26.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _10, const 1_usize) -> [success: bb14, unwind unreachable];
_27 = copy ((_26 as Some).0: &T);
StorageDead(_26);
_28 = copy _10;
_29 = AddWithOverflow(copy _10, const 1_usize);
assert(!move (_29.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _10, const 1_usize) -> [success: bb14, unwind unreachable];
}
bb14: {
_10 = move (_26.0: usize);
StorageLive(_27);
_27 = (copy _25, copy _24);
_28 = Option::<(usize, &T)>::Some(move _27);
StorageDead(_27);
StorageDead(_26);
StorageDead(_25);
_29 = copy (((_28 as Some).0: (usize, &T)).0: usize);
_30 = copy (((_28 as Some).0: (usize, &T)).1: &T);
StorageLive(_31);
_31 = &_2;
StorageLive(_32);
_32 = (copy _29, copy _30);
_33 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _31, move _32) -> [return: bb15, unwind unreachable];
_10 = move (_29.0: usize);
StorageLive(_30);
_30 = (copy _28, copy _27);
_31 = Option::<(usize, &T)>::Some(move _30);
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
_32 = copy (((_31 as Some).0: (usize, &T)).0: usize);
_33 = copy (((_31 as Some).0: (usize, &T)).1: &T);
StorageLive(_34);
_34 = &_2;
StorageLive(_35);
_35 = (copy _32, copy _33);
_36 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _34, move _35) -> [return: bb15, unwind unreachable];
}
bb15: {
StorageDead(_32);
StorageDead(_35);
StorageDead(_34);
StorageDead(_31);
StorageDead(_28);
goto -> bb4;
}
}

View file

@ -0,0 +1,12 @@
//@ check-pass
fn main() {
let functions = &vec![
|x: i32| -> i32 { x + 3 },
|x: i32| -> i32 { x + 3 },
];
let string = String::new();
let a = vec![&string, "abc"];
let b = vec!["abc", &string];
}

View file

@ -1,7 +1,7 @@
const fn foo(a: i32) -> Vec<i32> {
vec![1, 2, 3]
//~^ ERROR allocations are not allowed
//~| ERROR cannot call non-const method
//~^ ERROR cannot call non-const
//~| ERROR cannot call non-const
}
fn main() {}

View file

@ -1,10 +1,4 @@
error[E0010]: allocations are not allowed in constant functions
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
LL | vec![1, 2, 3]
| ^^^^^^^^^^^^^ allocation not allowed in constant functions
error[E0015]: cannot call non-const method `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constant functions
error[E0015]: cannot call non-const associated function `Box::<[i32; 3]>::new_uninit` in constant functions
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
LL | vec![1, 2, 3]
@ -12,7 +6,16 @@ LL | vec![1, 2, 3]
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<i32, 3>` in constant functions
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
LL | vec![1, 2, 3]
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0010, E0015.
For more information about an error, try `rustc --explain E0010`.
For more information about this error, try `rustc --explain E0015`.

View file

@ -15,11 +15,11 @@ fn main() {
let mut g = #[coroutine]
|| {
// This is desuraged as 4 stages:
// - allocate a `*mut u8` with `exchange_malloc`;
// - create a Box that is ignored for trait computations;
// - `vec!` macro
// - `write_via_move`
// - compute fields (and yields);
// - assign to `t`.
let t = std::boxed::box_new((5, yield));
let t = vec![(5, yield)];
drop(t);
};
@ -30,7 +30,7 @@ fn main() {
// As it is not taken into account for trait computation,
// the coroutine is `Copy`.
let mut h = copy(g);
//~^ ERROR the trait bound `Box<(i32, ())>: Copy` is not satisfied in
//~^ ERROR the trait bound `Box<MaybeUninit<[(i32, ()); 1]>>: Copy` is not satisfied in
// We now have 2 boxes with the same backing allocation:
// one inside `g` and one inside `h`.

View file

@ -1,20 +1,20 @@
error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
error[E0277]: the trait bound `Box<MaybeUninit<[(i32, ()); 1]>>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
--> $DIR/issue-105084.rs:32:17
|
LL | || {
| -- within this `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
...
LL | let mut h = copy(g);
| ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
| ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, the trait `Copy` is not implemented for `Box<MaybeUninit<[(i32, ()); 1]>>`
|
note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/issue-105084.rs:22:41
--> $DIR/issue-105084.rs:22:26
|
LL | let t = std::boxed::box_new((5, yield));
| ------------------------^^^^^--
| | |
| | yield occurs here, with `std::boxed::box_new((5, yield))` maybe used later
| has type `Box<(i32, ())>` which does not implement `Copy`
LL | let t = vec![(5, yield)];
| ---------^^^^^--
| | |
| | yield occurs here, with the value maybe used later
| has type `Box<MaybeUninit<[(i32, ()); 1]>>` which does not implement `Copy`
note: required by a bound in `copy`
--> $DIR/issue-105084.rs:10:12
|

View file

@ -1,7 +0,0 @@
//@ compile-flags: -Z teach
#![allow(warnings)]
const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010
//~| ERROR cannot call non-const method
fn main() {}

View file

@ -1,20 +0,0 @@
error[E0010]: allocations are not allowed in constants
--> $DIR/E0010-teach.rs:5:23
|
LL | const CON: Vec<i32> = vec![1, 2, 3];
| ^^^^^^^^^^^^^ allocation not allowed in constants
|
= note: the runtime heap is not yet available at compile-time, so no runtime heap allocations can be created
error[E0015]: cannot call non-const method `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constants
--> $DIR/E0010-teach.rs:5:23
|
LL | const CON: Vec<i32> = vec![1, 2, 3];
| ^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0010, E0015.
For more information about an error, try `rustc --explain E0010`.

View file

@ -1,5 +0,0 @@
#![allow(warnings)]
const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010
//~| ERROR cannot call non-const method
fn main() {}

View file

@ -1,18 +0,0 @@
error[E0010]: allocations are not allowed in constants
--> $DIR/E0010.rs:3:23
|
LL | const CON: Vec<i32> = vec![1, 2, 3];
| ^^^^^^^^^^^^^ allocation not allowed in constants
error[E0015]: cannot call non-const method `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constants
--> $DIR/E0010.rs:3:23
|
LL | const CON: Vec<i32> = vec![1, 2, 3];
| ^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0010, E0015.
For more information about an error, try `rustc --explain E0010`.

View file

@ -390,14 +390,6 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani
- impl<F, Args> Fn<Args> for Exclusive<F>
where F: Sync, F: Fn<Args>, Args: std::marker::Tuple;
error[E0118]: no nominal type found for inherent implementation
--> $DIR/where-allowed.rs:241:1
|
LL | impl<T = impl Debug> T {}
| ^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
|
= note: either implement a trait on it or create a newtype to wrap it instead
error: unconstrained opaque type
--> $DIR/where-allowed.rs:122:16
|
@ -414,6 +406,14 @@ LL | type InTypeAlias<R> = impl Debug;
|
= note: `InTypeAlias` must be used in combination with a concrete type within the same crate
error[E0118]: no nominal type found for inherent implementation
--> $DIR/where-allowed.rs:241:1
|
LL | impl<T = impl Debug> T {}
| ^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
|
= note: either implement a trait on it or create a newtype to wrap it instead
error: aborting due to 48 previous errors
Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0658, E0666.

View file

@ -6,7 +6,7 @@ fn main() {
match Some(vec![42]) {
Some(vec![43]) => {} //~ ERROR expected a pattern, found a function call
//~| ERROR found associated function
//~| ERROR usage of qualified paths in this context is experimental
//~| ERROR expected a pattern, found a function call
_ => {}
}
}

View file

@ -6,17 +6,15 @@ LL | Some(vec![43]) => {}
|
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error[E0658]: usage of qualified paths in this context is experimental
error[E0532]: expected a pattern, found a function call
--> $DIR/vec-macro-in-pattern.rs:7:14
|
LL | Some(vec![43]) => {}
| ^^^^^^^^
| ^^^^^^^^ not a tuple struct or tuple variant
|
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec`
error[E0164]: expected tuple struct or tuple variant, found associated function `::alloc::boxed::Box::new_uninit`
--> $DIR/vec-macro-in-pattern.rs:7:14
|
LL | Some(vec![43]) => {}
@ -26,5 +24,5 @@ LL | Some(vec![43]) => {}
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0164, E0532, E0658.
Some errors have detailed explanations: E0164, E0532.
For more information about an error, try `rustc --explain E0164`.

View file

@ -1,5 +0,0 @@
//! regression test for issue <https://github.com/rust-lang/rust/issues/47184>
fn main() {
let _vec: Vec<&'static String> = vec![&String::new()];
//~^ ERROR temporary value dropped while borrowed [E0716]
}

View file

@ -1,12 +0,0 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/borrowck-annotate-static-lifetime.rs:3:44
|
LL | let _vec: Vec<&'static String> = vec![&String::new()];
| -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| type annotation requires that borrow lasts for `'static`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0716`.

View file

@ -70,6 +70,11 @@ fn underscore_with_initializer() {
//~^ ERROR temporary value dropped while borrowed [E0716]
}
fn issue_47184() {
let _vec: Vec<&'static String> = vec![&String::new()];
//~^ ERROR temporary value dropped while borrowed [E0716]
}
fn pair_underscores_with_initializer() {
let x = 22;
let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR

View file

@ -111,8 +111,17 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| | creates a temporary value which is freed while still in use
| type annotation requires that borrow lasts for `'static`
error[E0716]: temporary value dropped while borrowed
--> $DIR/patterns.rs:74:44
|
LL | let _vec: Vec<&'static String> = vec![&String::new()];
| -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| type annotation requires that borrow lasts for `'static`
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:75:40
--> $DIR/patterns.rs:80:40
|
LL | let x = 22;
| - binding `x` declared here
@ -124,7 +133,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:80:40
--> $DIR/patterns.rs:85:40
|
LL | let x = 22;
| - binding `x` declared here
@ -136,7 +145,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:85:69
--> $DIR/patterns.rs:90:69
|
LL | let x = 22;
| - binding `x` declared here
@ -148,7 +157,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:90:69
--> $DIR/patterns.rs:95:69
|
LL | let x = 22;
| - binding `x` declared here
@ -160,7 +169,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:98:17
--> $DIR/patterns.rs:103:17
|
LL | let x = 22;
| - binding `x` declared here
@ -173,7 +182,7 @@ LL | }
| - `x` dropped here while still borrowed
error: lifetime may not live long enough
--> $DIR/patterns.rs:111:5
--> $DIR/patterns.rs:116:5
|
LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
@ -182,7 +191,7 @@ LL | y
| ^ returning this value requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/patterns.rs:123:5
--> $DIR/patterns.rs:128:5
|
LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
@ -191,7 +200,7 @@ LL | y
| ^ returning this value requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/patterns.rs:128:5
--> $DIR/patterns.rs:133:5
|
LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
@ -200,14 +209,14 @@ LL | y
| ^ returning this value requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/patterns.rs:132:18
--> $DIR/patterns.rs:137:18
|
LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | let (y, _z): (&'static u32, u32) = (x, 44);
| ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
error: aborting due to 19 previous errors
error: aborting due to 20 previous errors
Some errors have detailed explanations: E0597, E0716.
For more information about an error, try `rustc --explain E0597`.

View file

@ -4,7 +4,7 @@
fn main() {
let vec![const { vec![] }]: Vec<usize> = vec![];
//~^ ERROR expected a pattern, found a function call
//~| ERROR usage of qualified paths in this context is experimental
//~| ERROR expected a pattern, found a function call
//~| ERROR expected tuple struct or tuple variant
//~| ERROR arbitrary expressions aren't allowed in patterns
}

View file

@ -6,15 +6,13 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error[E0658]: usage of qualified paths in this context is experimental
error[E0532]: expected a pattern, found a function call
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error: arbitrary expressions aren't allowed in patterns
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:14
@ -24,7 +22,7 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec`
error[E0164]: expected tuple struct or tuple variant, found associated function `::alloc::boxed::Box::new_uninit`
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
@ -34,5 +32,5 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0164, E0532, E0658.
Some errors have detailed explanations: E0164, E0532.
For more information about an error, try `rustc --explain E0164`.

View file

@ -1,5 +1,5 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/issue-15480.rs:6:10
--> $DIR/vec-macro-outlives-issue-15480.rs:6:10
|
LL | &id(3)
| ^^^^^ creates a temporary value which is freed while still in use

View file

@ -79,8 +79,8 @@ static STATIC10: UnsafeStruct = UnsafeStruct;
struct MyOwned;
static STATIC11: Vec<MyOwned> = vec![MyOwned];
//~^ ERROR allocations are not allowed in statics
//~^^ ERROR cannot call non-const
//~^ ERROR cannot call non-const function
//~| ERROR cannot call non-const
static mut STATIC12: UnsafeStruct = UnsafeStruct;
@ -93,29 +93,29 @@ static mut STATIC14: SafeStruct = SafeStruct {
};
static STATIC15: &'static [Vec<MyOwned>] = &[
vec![MyOwned], //~ ERROR allocations are not allowed in statics
//~^ ERROR cannot call non-const
vec![MyOwned], //~ ERROR allocations are not allowed in statics
//~^ ERROR cannot call non-const
vec![MyOwned], //~ ERROR cannot call non-const function
//~| ERROR cannot call non-const
vec![MyOwned], //~ ERROR cannot call non-const function
//~| ERROR cannot call non-const
];
static STATIC16: (&'static Vec<MyOwned>, &'static Vec<MyOwned>) = (
&vec![MyOwned], //~ ERROR allocations are not allowed in statics
//~^ ERROR cannot call non-const
&vec![MyOwned], //~ ERROR allocations are not allowed in statics
//~^ ERROR cannot call non-const
&vec![MyOwned], //~ ERROR cannot call non-const function
//~| ERROR cannot call non-const
&vec![MyOwned], //~ ERROR cannot call non-const function
//~| ERROR cannot call non-const
);
static mut STATIC17: SafeEnum = SafeEnum::Variant1;
static STATIC19: Vec<isize> = vec![3];
//~^ ERROR allocations are not allowed in statics
//~^^ ERROR cannot call non-const
//~^ ERROR cannot call non-const function
//~| ERROR cannot call non-const
pub fn main() {
let y = {
static x: Vec<isize> = vec![3]; //~ ERROR allocations are not allowed in statics
//~^ ERROR cannot call non-const
static x: Vec<isize> = vec![3]; //~ ERROR cannot call non-const function
//~| ERROR cannot call non-const
x
//~^ ERROR cannot move out of static
};

View file

@ -11,13 +11,7 @@ LL | | }
LL | };
| - value is dropped here
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:81:33
|
LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
| ^^^^^^^^^^^^^ allocation not allowed in statics
error[E0015]: cannot call non-const method `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:81:33
|
LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
@ -26,6 +20,17 @@ LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<MyOwned, 1>` in statics
--> $DIR/check-values-constraints.rs:81:33
|
LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `<str as ToString>::to_string` in statics
--> $DIR/check-values-constraints.rs:92:38
|
@ -42,13 +47,7 @@ note: method `to_string` is not const because trait `ToString` is not const
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:96:5
|
LL | vec![MyOwned],
| ^^^^^^^^^^^^^ allocation not allowed in statics
error[E0015]: cannot call non-const method `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:96:5
|
LL | vec![MyOwned],
@ -57,13 +56,18 @@ LL | vec![MyOwned],
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:98:5
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<MyOwned, 1>` in statics
--> $DIR/check-values-constraints.rs:96:5
|
LL | vec![MyOwned],
| ^^^^^^^^^^^^^ allocation not allowed in statics
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:98:5
|
LL | vec![MyOwned],
@ -72,13 +76,18 @@ LL | vec![MyOwned],
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:103:6
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<MyOwned, 1>` in statics
--> $DIR/check-values-constraints.rs:98:5
|
LL | &vec![MyOwned],
| ^^^^^^^^^^^^^ allocation not allowed in statics
LL | vec![MyOwned],
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:103:6
|
LL | &vec![MyOwned],
@ -87,13 +96,18 @@ LL | &vec![MyOwned],
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:105:6
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<MyOwned, 1>` in statics
--> $DIR/check-values-constraints.rs:103:6
|
LL | &vec![MyOwned],
| ^^^^^^^^^^^^^ allocation not allowed in statics
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:105:6
|
LL | &vec![MyOwned],
@ -102,13 +116,18 @@ LL | &vec![MyOwned],
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:111:31
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<MyOwned, 1>` in statics
--> $DIR/check-values-constraints.rs:105:6
|
LL | static STATIC19: Vec<isize> = vec![3];
| ^^^^^^^ allocation not allowed in statics
LL | &vec![MyOwned],
| ^^^^^^^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[isize; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:111:31
|
LL | static STATIC19: Vec<isize> = vec![3];
@ -117,13 +136,18 @@ LL | static STATIC19: Vec<isize> = vec![3];
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:117:32
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<isize, 1>` in statics
--> $DIR/check-values-constraints.rs:111:31
|
LL | static x: Vec<isize> = vec![3];
| ^^^^^^^ allocation not allowed in statics
LL | static STATIC19: Vec<isize> = vec![3];
| ^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const method `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
error[E0015]: cannot call non-const associated function `Box::<[isize; 1]>::new_uninit` in statics
--> $DIR/check-values-constraints.rs:117:32
|
LL | static x: Vec<isize> = vec![3];
@ -132,6 +156,17 @@ LL | static x: Vec<isize> = vec![3];
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::<isize, 1>` in statics
--> $DIR/check-values-constraints.rs:117:32
|
LL | static x: Vec<isize> = vec![3];
| ^^^^^^^
|
note: function `box_assume_init_into_vec_unsafe` is not const
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0507]: cannot move out of static item `x`
--> $DIR/check-values-constraints.rs:119:9
|
@ -149,5 +184,5 @@ LL | x.clone()
error: aborting due to 17 previous errors
Some errors have detailed explanations: E0010, E0015, E0493, E0507.
For more information about an error, try `rustc --explain E0010`.
Some errors have detailed explanations: E0015, E0493, E0507.
For more information about an error, try `rustc --explain E0015`.

View file

@ -1,8 +0,0 @@
//@ compile-flags: -Zunpretty=thir-tree
//@ check-pass
#![feature(liballoc_internals)]
fn main() {
let _ = std::boxed::box_new(1);
}

View file

@ -1,90 +0,0 @@
DefId(0:3 ~ box[efb9]::main):
params: [
]
body:
Expr {
ty: ()
temp_scope_id: 11
span: $DIR/box.rs:6:11: 8:2 (#0)
kind:
Scope {
region_scope: Node(11)
hir_id: HirId(DefId(0:3 ~ box[efb9]::main).11)
value:
Expr {
ty: ()
temp_scope_id: 11
span: $DIR/box.rs:6:11: 8:2 (#0)
kind:
Block {
targeted_by_break: false
span: $DIR/box.rs:6:11: 8:2 (#0)
region_scope: Node(1)
safety_mode: Safe
stmts: [
Stmt {
kind: Let {
remainder_scope: Remainder { block: 1, first_statement_index: 0}
init_scope: Node(2)
pattern:
Pat {
ty: std::boxed::Box<i32, std::alloc::Global>
span: $DIR/box.rs:7:9: 7:10 (#0)
kind: PatKind {
Wild
}
}
,
initializer: Some(
Expr {
ty: std::boxed::Box<i32, std::alloc::Global>
temp_scope_id: 3
span: $DIR/box.rs:7:13: 7:35 (#0)
kind:
Scope {
region_scope: Node(3)
hir_id: HirId(DefId(0:3 ~ box[efb9]::main).3)
value:
Expr {
ty: std::boxed::Box<i32, std::alloc::Global>
temp_scope_id: 3
span: $DIR/box.rs:7:13: 7:35 (#0)
kind:
Box {
Expr {
ty: i32
temp_scope_id: 8
span: $DIR/box.rs:7:33: 7:34 (#0)
kind:
Scope {
region_scope: Node(8)
hir_id: HirId(DefId(0:3 ~ box[efb9]::main).8)
value:
Expr {
ty: i32
temp_scope_id: 8
span: $DIR/box.rs:7:33: 7:34 (#0)
kind:
Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed), span: $DIR/box.rs:7:33: 7:34 (#0) }, neg: false)
}
}
}
}
}
}
}
)
else_block: None
hir_id: HirId(DefId(0:3 ~ box[efb9]::main).9)
span: $DIR/box.rs:7:5: 7:35 (#0)
}
}
]
expr: []
}
}
}
}