mv compiler to compiler/
This commit is contained in:
parent
db534b3ac2
commit
9e5f7d5631
1686 changed files with 941 additions and 1051 deletions
198
compiler/rustc_mir_build/src/build/expr/as_operand.rs
Normal file
198
compiler/rustc_mir_build/src/build/expr/as_operand.rs
Normal file
|
@ -0,0 +1,198 @@
|
|||
//! See docs in build/expr/mod.rs
|
||||
|
||||
use crate::build::expr::category::Category;
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::thir::*;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// Returns an operand suitable for use until the end of the current
|
||||
/// scope expression.
|
||||
///
|
||||
/// The operand returned from this function will *not be valid*
|
||||
/// after the current enclosing `ExprKind::Scope` has ended, so
|
||||
/// please do *not* return it from functions to avoid bad
|
||||
/// miscompiles.
|
||||
crate fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let local_scope = self.local_scope();
|
||||
self.as_operand(block, local_scope, expr)
|
||||
}
|
||||
|
||||
/// Returns an operand suitable for use until the end of the current scope expression and
|
||||
/// suitable also to be passed as function arguments.
|
||||
///
|
||||
/// The operand returned from this function will *not be valid* after an ExprKind::Scope is
|
||||
/// passed, so please do *not* return it from functions to avoid bad miscompiles. Returns an
|
||||
/// operand suitable for use as a call argument. This is almost always equivalent to
|
||||
/// `as_operand`, except for the particular case of passing values of (potentially) unsized
|
||||
/// types "by value" (see details below).
|
||||
///
|
||||
/// The operand returned from this function will *not be valid*
|
||||
/// after the current enclosing `ExprKind::Scope` has ended, so
|
||||
/// please do *not* return it from functions to avoid bad
|
||||
/// miscompiles.
|
||||
///
|
||||
/// # Parameters of unsized types
|
||||
///
|
||||
/// We tweak the handling of parameters of unsized type slightly to avoid the need to create a
|
||||
/// local variable of unsized type. For example, consider this program:
|
||||
///
|
||||
/// ```rust
|
||||
/// fn foo(p: dyn Debug) { ... }
|
||||
///
|
||||
/// fn bar(box_p: Box<dyn Debug>) { foo(*p); }
|
||||
/// ```
|
||||
///
|
||||
/// Ordinarily, for sized types, we would compile the call `foo(*p)` like so:
|
||||
///
|
||||
/// ```rust
|
||||
/// let tmp0 = *box_p; // tmp0 would be the operand returned by this function call
|
||||
/// foo(tmp0)
|
||||
/// ```
|
||||
///
|
||||
/// But because the parameter to `foo` is of the unsized type `dyn Debug`, and because it is
|
||||
/// being moved the deref of a box, we compile it slightly differently. The temporary `tmp0`
|
||||
/// that we create *stores the entire box*, and the parameter to the call itself will be
|
||||
/// `*tmp0`:
|
||||
///
|
||||
/// ```rust
|
||||
/// let tmp0 = box_p; call foo(*tmp0)
|
||||
/// ```
|
||||
///
|
||||
/// This way, the temporary `tmp0` that we create has type `Box<dyn Debug>`, which is sized.
|
||||
/// The value passed to the call (`*tmp0`) still has the `dyn Debug` type -- but the way that
|
||||
/// calls are compiled means that this parameter will be passed "by reference", meaning that we
|
||||
/// will actually provide a pointer to the interior of the box, and not move the `dyn Debug`
|
||||
/// value to the stack.
|
||||
///
|
||||
/// See #68034 for more details.
|
||||
crate fn as_local_call_operand<M>(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M,
|
||||
) -> BlockAnd<Operand<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let local_scope = self.local_scope();
|
||||
self.as_call_operand(block, local_scope, expr)
|
||||
}
|
||||
|
||||
/// Compile `expr` into a value that can be used as an operand.
|
||||
/// If `expr` is a place like `x`, this will introduce a
|
||||
/// temporary `tmp = x`, so that we capture the value of `x` at
|
||||
/// this time.
|
||||
///
|
||||
/// The operand is known to be live until the end of `scope`.
|
||||
crate fn as_operand<M>(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
scope: Option<region::Scope>,
|
||||
expr: M,
|
||||
) -> BlockAnd<Operand<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_operand(block, scope, expr)
|
||||
}
|
||||
|
||||
/// Like `as_local_call_operand`, except that the argument will
|
||||
/// not be valid once `scope` ends.
|
||||
fn as_call_operand<M>(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
scope: Option<region::Scope>,
|
||||
expr: M,
|
||||
) -> BlockAnd<Operand<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_call_operand(block, scope, expr)
|
||||
}
|
||||
|
||||
fn expr_as_operand(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
scope: Option<region::Scope>,
|
||||
expr: Expr<'tcx>,
|
||||
) -> BlockAnd<Operand<'tcx>> {
|
||||
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
|
||||
let this = self;
|
||||
|
||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||
let source_info = this.source_info(expr.span);
|
||||
let region_scope = (region_scope, source_info);
|
||||
return this
|
||||
.in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
|
||||
}
|
||||
|
||||
let category = Category::of(&expr.kind).unwrap();
|
||||
debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
|
||||
match category {
|
||||
Category::Constant => {
|
||||
let constant = this.as_constant(expr);
|
||||
block.and(Operand::Constant(box constant))
|
||||
}
|
||||
Category::Place | Category::Rvalue(..) => {
|
||||
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
|
||||
block.and(Operand::Move(Place::from(operand)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_as_call_operand(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
scope: Option<region::Scope>,
|
||||
expr: Expr<'tcx>,
|
||||
) -> BlockAnd<Operand<'tcx>> {
|
||||
debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr);
|
||||
let this = self;
|
||||
|
||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||
let source_info = this.source_info(expr.span);
|
||||
let region_scope = (region_scope, source_info);
|
||||
return this.in_scope(region_scope, lint_level, |this| {
|
||||
this.as_call_operand(block, scope, value)
|
||||
});
|
||||
}
|
||||
|
||||
let tcx = this.hir.tcx();
|
||||
|
||||
if tcx.features().unsized_locals {
|
||||
let ty = expr.ty;
|
||||
let span = expr.span;
|
||||
let param_env = this.hir.param_env;
|
||||
|
||||
if !ty.is_sized(tcx.at(span), param_env) {
|
||||
// !sized means !copy, so this is an unsized move
|
||||
assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
|
||||
|
||||
// As described above, detect the case where we are passing a value of unsized
|
||||
// type, and that value is coming from the deref of a box.
|
||||
if let ExprKind::Deref { ref arg } = expr.kind {
|
||||
let arg = this.hir.mirror(arg.clone());
|
||||
|
||||
// Generate let tmp0 = arg0
|
||||
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
|
||||
|
||||
// Return the operand *tmp0 to be used as the call argument
|
||||
let place = Place {
|
||||
local: operand,
|
||||
projection: tcx.intern_place_elems(&[PlaceElem::Deref]),
|
||||
};
|
||||
|
||||
return block.and(Operand::Move(place));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.expr_as_operand(block, scope, expr)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue