Auto merge of #82495 - LeSeulArtichaut:eager-thir, r=oli-obk
Eagerly construct bodies of THIR With this PR: - the THIR is no longer constructed lazily, but is entirely built before being passed to the MIR Builder - the THIR is now allocated in arenas instead of `Box`es However, this PR doesn't make any changes to the way patterns are constructed: they are still boxed, and exhaustiveness checking is unchanged. Implements MCP rust-lang/compiler-team#409. Closes rust-lang/project-thir-unsafeck#1. r? `@ghost` cc `@nikomatsakis` `@oli-obk`
This commit is contained in:
commit
61365c0625
24 changed files with 1580 additions and 1770 deletions
|
@ -2,7 +2,6 @@ use crate::build::matches::ArmHasGuard;
|
||||||
use crate::build::ForGuard::OutsideGuard;
|
use crate::build::ForGuard::OutsideGuard;
|
||||||
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
||||||
use crate::thir::*;
|
use crate::thir::*;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
|
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
|
@ -13,7 +12,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
ast_block: &'tcx hir::Block<'tcx>,
|
ast_block: &Block<'_, 'tcx>,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let Block {
|
let Block {
|
||||||
|
@ -24,7 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
expr,
|
expr,
|
||||||
targeted_by_break,
|
targeted_by_break,
|
||||||
safety_mode,
|
safety_mode,
|
||||||
} = self.hir.mirror(ast_block);
|
} = *ast_block;
|
||||||
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
|
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
|
||||||
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
||||||
if targeted_by_break {
|
if targeted_by_break {
|
||||||
|
@ -50,8 +49,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
span: Span,
|
span: Span,
|
||||||
stmts: Vec<StmtRef<'tcx>>,
|
stmts: &[Stmt<'_, 'tcx>],
|
||||||
expr: Option<ExprRef<'tcx>>,
|
expr: Option<&Expr<'_, 'tcx>>,
|
||||||
safety_mode: BlockSafety,
|
safety_mode: BlockSafety,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
@ -79,10 +78,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.update_source_scope_for_safety_mode(span, safety_mode);
|
this.update_source_scope_for_safety_mode(span, safety_mode);
|
||||||
|
|
||||||
let source_info = this.source_info(span);
|
let source_info = this.source_info(span);
|
||||||
for stmt in stmts {
|
for Stmt { kind, opt_destruction_scope } in stmts {
|
||||||
let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
|
|
||||||
match kind {
|
match kind {
|
||||||
StmtKind::Expr { scope, expr } => {
|
&StmtKind::Expr { scope, expr } => {
|
||||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
|
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
|
||||||
unpack!(
|
unpack!(
|
||||||
block = this.in_opt_scope(
|
block = this.in_opt_scope(
|
||||||
|
@ -90,7 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|this| {
|
|this| {
|
||||||
let si = (scope, source_info);
|
let si = (scope, source_info);
|
||||||
this.in_scope(si, LintLevel::Inherited, |this| {
|
this.in_scope(si, LintLevel::Inherited, |this| {
|
||||||
let expr = this.hir.mirror(expr);
|
|
||||||
this.stmt_expr(block, expr, Some(scope))
|
this.stmt_expr(block, expr, Some(scope))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -102,45 +99,44 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
||||||
|
|
||||||
// Enter the remainder scope, i.e., the bindings' destruction scope.
|
// Enter the remainder scope, i.e., the bindings' destruction scope.
|
||||||
this.push_scope((remainder_scope, source_info));
|
this.push_scope((*remainder_scope, source_info));
|
||||||
let_scope_stack.push(remainder_scope);
|
let_scope_stack.push(remainder_scope);
|
||||||
|
|
||||||
// Declare the bindings, which may create a source scope.
|
// Declare the bindings, which may create a source scope.
|
||||||
let remainder_span =
|
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
|
||||||
remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree);
|
|
||||||
|
|
||||||
let visibility_scope =
|
let visibility_scope =
|
||||||
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
||||||
|
|
||||||
// Evaluate the initializer, if present.
|
// Evaluate the initializer, if present.
|
||||||
if let Some(init) = initializer {
|
if let Some(init) = initializer {
|
||||||
let initializer_span = init.span();
|
let initializer_span = init.span;
|
||||||
|
|
||||||
unpack!(
|
unpack!(
|
||||||
block = this.in_opt_scope(
|
block = this.in_opt_scope(
|
||||||
opt_destruction_scope.map(|de| (de, source_info)),
|
opt_destruction_scope.map(|de| (de, source_info)),
|
||||||
|this| {
|
|this| {
|
||||||
let scope = (init_scope, source_info);
|
let scope = (*init_scope, source_info);
|
||||||
this.in_scope(scope, lint_level, |this| {
|
this.in_scope(scope, *lint_level, |this| {
|
||||||
this.declare_bindings(
|
this.declare_bindings(
|
||||||
visibility_scope,
|
visibility_scope,
|
||||||
remainder_span,
|
remainder_span,
|
||||||
&pattern,
|
pattern,
|
||||||
ArmHasGuard(false),
|
ArmHasGuard(false),
|
||||||
Some((None, initializer_span)),
|
Some((None, initializer_span)),
|
||||||
);
|
);
|
||||||
this.expr_into_pattern(block, pattern, init)
|
this.expr_into_pattern(block, pattern.clone(), init)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let scope = (init_scope, source_info);
|
let scope = (*init_scope, source_info);
|
||||||
unpack!(this.in_scope(scope, lint_level, |this| {
|
unpack!(this.in_scope(scope, *lint_level, |this| {
|
||||||
this.declare_bindings(
|
this.declare_bindings(
|
||||||
visibility_scope,
|
visibility_scope,
|
||||||
remainder_span,
|
remainder_span,
|
||||||
&pattern,
|
pattern,
|
||||||
ArmHasGuard(false),
|
ArmHasGuard(false),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -171,18 +167,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// Then, the block may have an optional trailing expression which is a “return” value
|
// Then, the block may have an optional trailing expression which is a “return” value
|
||||||
// of the block, which is stored into `destination`.
|
// of the block, which is stored into `destination`.
|
||||||
let tcx = this.hir.tcx();
|
let tcx = this.tcx;
|
||||||
let destination_ty = destination.ty(&this.local_decls, tcx).ty;
|
let destination_ty = destination.ty(&this.local_decls, tcx).ty;
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
let tail_result_is_ignored =
|
let tail_result_is_ignored =
|
||||||
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
|
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
|
||||||
let span = match expr {
|
this.block_context
|
||||||
ExprRef::Thir(expr) => expr.span,
|
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
|
||||||
ExprRef::Mirror(ref expr) => expr.span,
|
|
||||||
};
|
|
||||||
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
|
|
||||||
|
|
||||||
unpack!(block = this.into(destination, block, expr));
|
unpack!(block = this.expr_into_dest(destination, block, expr));
|
||||||
let popped = this.block_context.pop();
|
let popped = this.block_context.pop();
|
||||||
|
|
||||||
assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
|
assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
|
||||||
|
@ -194,13 +187,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if destination_ty.is_unit() {
|
if destination_ty.is_unit() {
|
||||||
// We only want to assign an implicit `()` as the return value of the block if the
|
// We only want to assign an implicit `()` as the return value of the block if the
|
||||||
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
|
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
|
||||||
this.cfg.push_assign_unit(block, source_info, destination, this.hir.tcx());
|
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Finally, we pop all the let scopes before exiting out from the scope of block
|
// Finally, we pop all the let scopes before exiting out from the scope of block
|
||||||
// itself.
|
// itself.
|
||||||
for scope in let_scope_stack.into_iter().rev() {
|
for scope in let_scope_stack.into_iter().rev() {
|
||||||
unpack!(block = this.pop_scope((scope, source_info), block));
|
unpack!(block = this.pop_scope((*scope, source_info), block));
|
||||||
}
|
}
|
||||||
// Restore the original source scope.
|
// Restore the original source scope.
|
||||||
this.source_scope = outer_source_scope;
|
this.source_scope = outer_source_scope;
|
||||||
|
@ -220,7 +213,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Safety::Safe => {}
|
Safety::Safe => {}
|
||||||
// no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585)
|
// no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585)
|
||||||
Safety::FnUnsafe
|
Safety::FnUnsafe
|
||||||
if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0
|
if self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0
|
||||||
!= Level::Allow => {}
|
!= Level::Allow => {}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,9 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
||||||
/// `expr` is a valid compile-time constant!
|
/// `expr` is a valid compile-time constant!
|
||||||
crate fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
|
crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let expr = self.hir.mirror(expr);
|
|
||||||
self.expr_as_constant(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
|
|
||||||
let this = self;
|
let this = self;
|
||||||
let Expr { ty, temp_lifetime: _, span, kind } = expr;
|
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||||
match kind {
|
match kind {
|
||||||
ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
|
ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
|
||||||
ExprKind::Literal { literal, user_ty, const_id: _ } => {
|
ExprKind::Literal { literal, user_ty, const_id: _ } => {
|
||||||
|
@ -33,7 +25,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Constant { span, user_ty, literal }
|
Constant { span, user_ty, literal }
|
||||||
}
|
}
|
||||||
ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
|
ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
|
||||||
ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value },
|
ExprKind::ConstBlock { value } => {
|
||||||
|
Constant { span: span, user_ty: None, literal: value }
|
||||||
|
}
|
||||||
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// after the current enclosing `ExprKind::Scope` has ended, so
|
/// after the current enclosing `ExprKind::Scope` has ended, so
|
||||||
/// please do *not* return it from functions to avoid bad
|
/// please do *not* return it from functions to avoid bad
|
||||||
/// miscompiles.
|
/// miscompiles.
|
||||||
crate fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
|
crate fn as_local_operand(
|
||||||
where
|
&mut self,
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
block: BasicBlock,
|
||||||
{
|
expr: &Expr<'_, 'tcx>,
|
||||||
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_operand(block, Some(local_scope), expr)
|
self.as_operand(block, Some(local_scope), expr)
|
||||||
}
|
}
|
||||||
|
@ -70,14 +71,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// value to the stack.
|
/// value to the stack.
|
||||||
///
|
///
|
||||||
/// See #68034 for more details.
|
/// See #68034 for more details.
|
||||||
crate fn as_local_call_operand<M>(
|
crate fn as_local_call_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: M,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Operand<'tcx>>
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_call_operand(block, Some(local_scope), expr)
|
self.as_call_operand(block, Some(local_scope), expr)
|
||||||
}
|
}
|
||||||
|
@ -88,41 +86,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// this time.
|
/// this time.
|
||||||
///
|
///
|
||||||
/// The operand is known to be live until the end of `scope`.
|
/// 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
|
/// Like `as_local_call_operand`, except that the argument will
|
||||||
/// not be valid once `scope` ends.
|
/// not be valid once `scope` ends.
|
||||||
fn as_call_operand<M>(
|
crate fn as_operand(
|
||||||
&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 self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
|
debug!("as_operand(block={:?}, expr={:?})", block, expr);
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||||
|
@ -133,7 +106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let category = Category::of(&expr.kind).unwrap();
|
let category = Category::of(&expr.kind).unwrap();
|
||||||
debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
|
debug!("as_operand: category={:?} for={:?}", category, expr.kind);
|
||||||
match category {
|
match category {
|
||||||
Category::Constant => {
|
Category::Constant => {
|
||||||
let constant = this.as_constant(expr);
|
let constant = this.as_constant(expr);
|
||||||
|
@ -146,13 +119,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_as_call_operand(
|
crate fn as_call_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr);
|
debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||||
|
@ -163,12 +136,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = this.hir.tcx();
|
let tcx = this.tcx;
|
||||||
|
|
||||||
if tcx.features().unsized_fn_params {
|
if tcx.features().unsized_fn_params {
|
||||||
let ty = expr.ty;
|
let ty = expr.ty;
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
let param_env = this.hir.param_env;
|
let param_env = this.param_env;
|
||||||
|
|
||||||
if !ty.is_sized(tcx.at(span), param_env) {
|
if !ty.is_sized(tcx.at(span), param_env) {
|
||||||
// !sized means !copy, so this is an unsized move
|
// !sized means !copy, so this is an unsized move
|
||||||
|
@ -176,9 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// As described above, detect the case where we are passing a value of unsized
|
// 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.
|
// type, and that value is coming from the deref of a box.
|
||||||
if let ExprKind::Deref { ref arg } = expr.kind {
|
if let ExprKind::Deref { arg } = expr.kind {
|
||||||
let arg = this.hir.mirror(arg.clone());
|
|
||||||
|
|
||||||
// Generate let tmp0 = arg0
|
// Generate let tmp0 = arg0
|
||||||
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
|
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
|
||||||
|
|
||||||
|
@ -193,6 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.expr_as_operand(block, scope, expr)
|
this.as_operand(block, scope, expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,25 +347,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Extra care is needed if any user code is allowed to run between calling
|
/// Extra care is needed if any user code is allowed to run between calling
|
||||||
/// this method and using it, as is the case for `match` and index
|
/// this method and using it, as is the case for `match` and index
|
||||||
/// expressions.
|
/// expressions.
|
||||||
crate fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
|
crate fn as_place(
|
||||||
where
|
&mut self,
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
mut block: BasicBlock,
|
||||||
{
|
expr: &Expr<'_, 'tcx>,
|
||||||
|
) -> BlockAnd<Place<'tcx>> {
|
||||||
let place_builder = unpack!(block = self.as_place_builder(block, expr));
|
let place_builder = unpack!(block = self.as_place_builder(block, expr));
|
||||||
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
|
block.and(place_builder.into_place(self.tcx, self.typeck_results))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||||
/// intermediate `Place` values until we know the full set of projections.
|
/// intermediate `Place` values until we know the full set of projections.
|
||||||
crate fn as_place_builder<M>(
|
crate fn as_place_builder(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: M,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>>
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let expr = self.hir.mirror(expr);
|
|
||||||
self.expr_as_place(block, expr, Mutability::Mut, None)
|
self.expr_as_place(block, expr, Mutability::Mut, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,16 +371,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// place. The place itself may or may not be mutable:
|
/// place. The place itself may or may not be mutable:
|
||||||
/// * If this expr is a place expr like a.b, then we will return that place.
|
/// * If this expr is a place expr like a.b, then we will return that place.
|
||||||
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
||||||
crate fn as_read_only_place<M>(
|
crate fn as_read_only_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: M,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Place<'tcx>>
|
) -> BlockAnd<Place<'tcx>> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
|
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
|
||||||
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
|
block.and(place_builder.into_place(self.tcx, self.typeck_results))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||||
|
@ -392,22 +386,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// place. The place itself may or may not be mutable:
|
/// place. The place itself may or may not be mutable:
|
||||||
/// * If this expr is a place expr like a.b, then we will return that place.
|
/// * If this expr is a place expr like a.b, then we will return that place.
|
||||||
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
||||||
fn as_read_only_place_builder<M>(
|
fn as_read_only_place_builder(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: M,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>>
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let expr = self.hir.mirror(expr);
|
|
||||||
self.expr_as_place(block, expr, Mutability::Not, None)
|
self.expr_as_place(block, expr, Mutability::Not, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_as_place(
|
fn expr_as_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
fake_borrow_temps: Option<&mut Vec<Local>>,
|
fake_borrow_temps: Option<&mut Vec<Local>>,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
|
@ -419,18 +409,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Scope { region_scope, lint_level, value } => {
|
ExprKind::Scope { region_scope, lint_level, value } => {
|
||||||
this.in_scope((region_scope, source_info), lint_level, |this| {
|
this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||||
let value = this.hir.mirror(value);
|
|
||||||
this.expr_as_place(block, value, mutability, fake_borrow_temps)
|
this.expr_as_place(block, value, mutability, fake_borrow_temps)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Field { lhs, name } => {
|
ExprKind::Field { lhs, name } => {
|
||||||
let lhs = this.hir.mirror(lhs);
|
|
||||||
let place_builder =
|
let place_builder =
|
||||||
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
|
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
|
||||||
block.and(place_builder.field(name, expr.ty))
|
block.and(place_builder.field(name, expr.ty))
|
||||||
}
|
}
|
||||||
ExprKind::Deref { arg } => {
|
ExprKind::Deref { arg } => {
|
||||||
let arg = this.hir.mirror(arg);
|
|
||||||
let place_builder =
|
let place_builder =
|
||||||
unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
|
unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
|
||||||
block.and(place_builder.deref())
|
block.and(place_builder.deref())
|
||||||
|
@ -462,7 +449,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||||
let source = this.hir.mirror(source);
|
|
||||||
let place_builder = unpack!(
|
let place_builder = unpack!(
|
||||||
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
|
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
|
||||||
);
|
);
|
||||||
|
@ -474,8 +460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
inferred_ty: expr.ty,
|
inferred_ty: expr.ty,
|
||||||
});
|
});
|
||||||
|
|
||||||
let place =
|
let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
|
||||||
place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
|
|
||||||
this.cfg.push(
|
this.cfg.push(
|
||||||
block,
|
block,
|
||||||
Statement {
|
Statement {
|
||||||
|
@ -493,7 +478,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(place_builder)
|
block.and(place_builder)
|
||||||
}
|
}
|
||||||
ExprKind::ValueTypeAscription { source, user_ty } => {
|
ExprKind::ValueTypeAscription { source, user_ty } => {
|
||||||
let source = this.hir.mirror(source);
|
|
||||||
let temp =
|
let temp =
|
||||||
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
|
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
|
||||||
if let Some(user_ty) = user_ty {
|
if let Some(user_ty) = user_ty {
|
||||||
|
@ -570,12 +554,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
upvar_id: ty::UpvarId,
|
upvar_id: ty::UpvarId,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
let closure_ty = self
|
let closure_ty = self
|
||||||
.hir
|
.typeck_results
|
||||||
.typeck_results()
|
.node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
|
||||||
.node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
|
|
||||||
|
|
||||||
let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
|
let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
|
||||||
self.hir.infcx().closure_kind(closure_substs).unwrap()
|
self.infcx.closure_kind(closure_substs).unwrap()
|
||||||
} else {
|
} else {
|
||||||
// Generators are considered FnOnce.
|
// Generators are considered FnOnce.
|
||||||
ty::ClosureKind::FnOnce
|
ty::ClosureKind::FnOnce
|
||||||
|
@ -599,22 +582,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn lower_index_expression(
|
fn lower_index_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
base: ExprRef<'tcx>,
|
base: &Expr<'_, 'tcx>,
|
||||||
index: ExprRef<'tcx>,
|
index: &Expr<'_, 'tcx>,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
fake_borrow_temps: Option<&mut Vec<Local>>,
|
fake_borrow_temps: Option<&mut Vec<Local>>,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
let lhs = self.hir.mirror(base);
|
|
||||||
|
|
||||||
let base_fake_borrow_temps = &mut Vec::new();
|
let base_fake_borrow_temps = &mut Vec::new();
|
||||||
let is_outermost_index = fake_borrow_temps.is_none();
|
let is_outermost_index = fake_borrow_temps.is_none();
|
||||||
let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
|
let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
|
||||||
|
|
||||||
let mut base_place =
|
let mut base_place =
|
||||||
unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
|
unpack!(block = self.expr_as_place(block, base, mutability, Some(fake_borrow_temps),));
|
||||||
|
|
||||||
// Making this a *fresh* temporary means we do not have to worry about
|
// Making this a *fresh* temporary means we do not have to worry about
|
||||||
// the index changing later: Nothing will ever change this temporary.
|
// the index changing later: Nothing will ever change this temporary.
|
||||||
|
@ -623,7 +604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
block = self.bounds_check(
|
block = self.bounds_check(
|
||||||
block,
|
block,
|
||||||
base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()),
|
base_place.clone().into_place(self.tcx, self.typeck_results),
|
||||||
idx,
|
idx,
|
||||||
expr_span,
|
expr_span,
|
||||||
source_info,
|
source_info,
|
||||||
|
@ -632,8 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if is_outermost_index {
|
if is_outermost_index {
|
||||||
self.read_fake_borrows(block, fake_borrow_temps, source_info)
|
self.read_fake_borrows(block, fake_borrow_temps, source_info)
|
||||||
} else {
|
} else {
|
||||||
base_place =
|
base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
|
||||||
base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results());
|
|
||||||
self.add_fake_borrows_of_base(
|
self.add_fake_borrows_of_base(
|
||||||
&base_place,
|
&base_place,
|
||||||
block,
|
block,
|
||||||
|
@ -654,8 +634,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> BasicBlock {
|
) -> BasicBlock {
|
||||||
let usize_ty = self.hir.usize_ty();
|
let usize_ty = self.tcx.types.usize;
|
||||||
let bool_ty = self.hir.bool_ty();
|
let bool_ty = self.tcx.types.bool;
|
||||||
// bounds check:
|
// bounds check:
|
||||||
let len = self.temp(usize_ty, expr_span);
|
let len = self.temp(usize_ty, expr_span);
|
||||||
let lt = self.temp(bool_ty, expr_span);
|
let lt = self.temp(bool_ty, expr_span);
|
||||||
|
@ -685,7 +665,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) {
|
) {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let local = match base_place.base {
|
let local = match base_place.base {
|
||||||
PlaceBase::Local(local) => local,
|
PlaceBase::Local(local) => local,
|
||||||
PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"),
|
PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"),
|
||||||
|
|
|
@ -19,33 +19,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// The operand returned from this function will *not be valid* after
|
/// The operand returned from this function will *not be valid* after
|
||||||
/// an ExprKind::Scope is passed, so please do *not* return it from
|
/// an ExprKind::Scope is passed, so please do *not* return it from
|
||||||
/// functions to avoid bad miscompiles.
|
/// functions to avoid bad miscompiles.
|
||||||
crate fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
|
crate fn as_local_rvalue(
|
||||||
where
|
&mut self,
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
block: BasicBlock,
|
||||||
{
|
expr: &Expr<'_, 'tcx>,
|
||||||
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_rvalue(block, Some(local_scope), expr)
|
self.as_rvalue(block, Some(local_scope), expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile `expr`, yielding an rvalue.
|
/// Compile `expr`, yielding an rvalue.
|
||||||
fn as_rvalue<M>(
|
crate fn as_rvalue(
|
||||||
&mut self,
|
|
||||||
block: BasicBlock,
|
|
||||||
scope: Option<region::Scope>,
|
|
||||||
expr: M,
|
|
||||||
) -> BlockAnd<Rvalue<'tcx>>
|
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let expr = self.hir.mirror(expr);
|
|
||||||
self.expr_as_rvalue(block, scope, expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expr_as_rvalue(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Rvalue<'tcx>> {
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
|
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
|
||||||
|
|
||||||
|
@ -71,8 +59,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::Unary { op, arg } => {
|
ExprKind::Unary { op, arg } => {
|
||||||
let arg = unpack!(block = this.as_operand(block, scope, arg));
|
let arg = unpack!(block = this.as_operand(block, scope, arg));
|
||||||
// Check for -MIN on signed integers
|
// Check for -MIN on signed integers
|
||||||
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
|
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
|
||||||
let bool_ty = this.hir.bool_ty();
|
let bool_ty = this.tcx.types.bool;
|
||||||
|
|
||||||
let minval = this.minval_literal(expr_span, expr.ty);
|
let minval = this.minval_literal(expr_span, expr.ty);
|
||||||
let is_min = this.temp(bool_ty, expr_span);
|
let is_min = this.temp(bool_ty, expr_span);
|
||||||
|
@ -95,7 +83,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(Rvalue::UnaryOp(op, arg))
|
block.and(Rvalue::UnaryOp(op, arg))
|
||||||
}
|
}
|
||||||
ExprKind::Box { value } => {
|
ExprKind::Box { value } => {
|
||||||
let value = this.hir.mirror(value);
|
|
||||||
// The `Box<T>` temporary created here is not a part of the HIR,
|
// The `Box<T>` temporary created here is not a part of the HIR,
|
||||||
// and therefore is not considered during generator auto-trait
|
// and therefore is not considered during generator auto-trait
|
||||||
// determination. See the comment about `box` at `yield_in_scope`.
|
// determination. See the comment about `box` at `yield_in_scope`.
|
||||||
|
@ -115,8 +102,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// initialize the box contents:
|
// initialize the box contents:
|
||||||
unpack!(
|
unpack!(
|
||||||
block =
|
block = this.expr_into_dest(
|
||||||
this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
|
this.tcx.mk_place_deref(Place::from(result)),
|
||||||
|
block,
|
||||||
|
value
|
||||||
|
)
|
||||||
);
|
);
|
||||||
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
|
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
|
||||||
}
|
}
|
||||||
|
@ -156,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// to the same MIR as `let x = ();`.
|
// to the same MIR as `let x = ();`.
|
||||||
|
|
||||||
// first process the set of fields
|
// first process the set of fields
|
||||||
let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
|
let el_ty = expr.ty.sequence_element_type(this.tcx);
|
||||||
let fields: Vec<_> = fields
|
let fields: Vec<_> = fields
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
|
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
|
||||||
|
@ -179,7 +169,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let operands: Vec<_> = upvars
|
let operands: Vec<_> = upvars
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|upvar| {
|
.map(|upvar| {
|
||||||
let upvar = this.hir.mirror(upvar);
|
|
||||||
match Category::of(&upvar.kind) {
|
match Category::of(&upvar.kind) {
|
||||||
// Use as_place to avoid creating a temporary when
|
// Use as_place to avoid creating a temporary when
|
||||||
// moving a variable into a closure, so that
|
// moving a variable into a closure, so that
|
||||||
|
@ -230,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(Rvalue::Use(Operand::Constant(box Constant {
|
block.and(Rvalue::Use(Operand::Constant(box Constant {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ty::Const::zero_sized(this.hir.tcx(), this.hir.tcx().types.unit),
|
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
ExprKind::Yield { .. }
|
ExprKind::Yield { .. }
|
||||||
|
@ -282,9 +271,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
rhs: Operand<'tcx>,
|
rhs: Operand<'tcx>,
|
||||||
) -> BlockAnd<Rvalue<'tcx>> {
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
let source_info = self.source_info(span);
|
let source_info = self.source_info(span);
|
||||||
let bool_ty = self.hir.bool_ty();
|
let bool_ty = self.tcx.types.bool;
|
||||||
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
|
if self.check_overflow && op.is_checkable() && ty.is_integral() {
|
||||||
let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
|
let result_tup = self.tcx.intern_tup(&[ty, bool_ty]);
|
||||||
let result_value = self.temp(result_tup, span);
|
let result_value = self.temp(result_tup, span);
|
||||||
|
|
||||||
self.cfg.push_assign(
|
self.cfg.push_assign(
|
||||||
|
@ -296,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let val_fld = Field::new(0);
|
let val_fld = Field::new(0);
|
||||||
let of_fld = Field::new(1);
|
let of_fld = Field::new(1);
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let val = tcx.mk_place_field(result_value, val_fld, ty);
|
let val = tcx.mk_place_field(result_value, val_fld, ty);
|
||||||
let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
|
let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
|
||||||
|
|
||||||
|
@ -377,7 +366,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
upvar_ty: Ty<'tcx>,
|
upvar_ty: Ty<'tcx>,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
arg: ExprRef<'tcx>,
|
arg: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
|
@ -398,7 +387,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// is same as that of the capture in the parent closure.
|
// is same as that of the capture in the parent closure.
|
||||||
PlaceBase::Upvar { .. } => {
|
PlaceBase::Upvar { .. } => {
|
||||||
let enclosing_upvars_resolved =
|
let enclosing_upvars_resolved =
|
||||||
arg_place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
|
arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
|
||||||
|
|
||||||
match enclosing_upvars_resolved.as_ref() {
|
match enclosing_upvars_resolved.as_ref() {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
|
@ -435,13 +424,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
|
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
let arg_place = arg_place_builder.into_place(this.hir.tcx(), this.hir.typeck_results());
|
let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
|
||||||
|
|
||||||
this.cfg.push_assign(
|
this.cfg.push_assign(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
Place::from(temp),
|
Place::from(temp),
|
||||||
Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
|
Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place),
|
||||||
);
|
);
|
||||||
|
|
||||||
// See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
|
// See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
|
||||||
|
@ -456,9 +445,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Helper to get a `-1` value of the appropriate type
|
// Helper to get a `-1` value of the appropriate type
|
||||||
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||||
let param_ty = ty::ParamEnv::empty().and(ty);
|
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||||
let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
|
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
|
||||||
let n = (!0u128) >> (128 - bits);
|
let n = (!0u128) >> (128 - bits);
|
||||||
let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
|
let literal = ty::Const::from_bits(self.tcx, n, param_ty);
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
|
@ -467,9 +456,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||||
assert!(ty.is_signed());
|
assert!(ty.is_signed());
|
||||||
let param_ty = ty::ParamEnv::empty().and(ty);
|
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||||
let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
|
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
|
||||||
let n = 1 << (bits - 1);
|
let n = 1 << (bits - 1);
|
||||||
let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
|
let literal = ty::Const::from_bits(self.tcx, n, param_ty);
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,40 +4,34 @@ use crate::build::scope::DropKind;
|
||||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||||
use crate::thir::*;
|
use crate::thir::*;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Compile `expr` into a fresh temporary. This is used when building
|
/// Compile `expr` into a fresh temporary. This is used when building
|
||||||
/// up rvalues so as to freeze the value that will be consumed.
|
/// up rvalues so as to freeze the value that will be consumed.
|
||||||
crate fn as_temp<M>(
|
crate fn as_temp(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: M,
|
expr: &Expr<'_, 'tcx>,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
) -> BlockAnd<Local>
|
) -> BlockAnd<Local> {
|
||||||
where
|
|
||||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
|
||||||
{
|
|
||||||
let expr = self.hir.mirror(expr);
|
|
||||||
//
|
|
||||||
// this is the only place in mir building that we need to truly need to worry about
|
// this is the only place in mir building that we need to truly need to worry about
|
||||||
// infinite recursion. Everything else does recurse, too, but it always gets broken up
|
// infinite recursion. Everything else does recurse, too, but it always gets broken up
|
||||||
// at some point by inserting an intermediate temporary
|
// at some point by inserting an intermediate temporary
|
||||||
ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability))
|
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_as_temp(
|
fn as_temp_inner(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
) -> BlockAnd<Local> {
|
) -> BlockAnd<Local> {
|
||||||
debug!(
|
debug!(
|
||||||
"expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
|
"as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
|
||||||
block, temp_lifetime, expr, mutability
|
block, temp_lifetime, expr, mutability
|
||||||
);
|
);
|
||||||
let this = self;
|
let this = self;
|
||||||
|
@ -65,13 +59,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::StaticRef { def_id, .. } => {
|
ExprKind::StaticRef { def_id, .. } => {
|
||||||
assert!(!this.hir.tcx().is_thread_local_static(def_id));
|
assert!(!this.tcx.is_thread_local_static(def_id));
|
||||||
local_decl.internal = true;
|
local_decl.internal = true;
|
||||||
local_decl.local_info =
|
local_decl.local_info =
|
||||||
Some(box LocalInfo::StaticRef { def_id, is_thread_local: false });
|
Some(box LocalInfo::StaticRef { def_id, is_thread_local: false });
|
||||||
}
|
}
|
||||||
ExprKind::ThreadLocalRef(def_id) => {
|
ExprKind::ThreadLocalRef(def_id) => {
|
||||||
assert!(this.hir.tcx().is_thread_local_static(def_id));
|
assert!(this.tcx.is_thread_local_static(def_id));
|
||||||
local_decl.internal = true;
|
local_decl.internal = true;
|
||||||
local_decl.local_info =
|
local_decl.local_info =
|
||||||
Some(box LocalInfo::StaticRef { def_id, is_thread_local: true });
|
Some(box LocalInfo::StaticRef { def_id, is_thread_local: true });
|
||||||
|
@ -89,7 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Don't bother with StorageLive and Dead for these temporaries,
|
// Don't bother with StorageLive and Dead for these temporaries,
|
||||||
// they are never assigned.
|
// they are never assigned.
|
||||||
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
|
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
|
||||||
ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } }
|
ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } }
|
||||||
if expr_ty.is_never() => {}
|
if expr_ty.is_never() => {}
|
||||||
_ => {
|
_ => {
|
||||||
this.cfg
|
this.cfg
|
||||||
|
@ -114,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack!(block = this.into(temp_place, block, expr));
|
unpack!(block = this.expr_into_dest(temp_place, block, expr));
|
||||||
|
|
||||||
if let Some(temp_lifetime) = temp_lifetime {
|
if let Some(temp_lifetime) = temp_lifetime {
|
||||||
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
|
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
|
||||||
|
|
|
@ -31,7 +31,7 @@ crate enum RvalueFunc {
|
||||||
/// Determines the category for a given expression. Note that scope
|
/// Determines the category for a given expression. Note that scope
|
||||||
/// and paren expressions have no category.
|
/// and paren expressions have no category.
|
||||||
impl Category {
|
impl Category {
|
||||||
crate fn of(ek: &ExprKind<'_>) -> Option<Category> {
|
crate fn of(ek: &ExprKind<'_, '_>) -> Option<Category> {
|
||||||
match *ek {
|
match *ek {
|
||||||
ExprKind::Scope { .. } => None,
|
ExprKind::Scope { .. } => None,
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,20 @@ use rustc_ast::InlineAsmOptions;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Compile `expr`, storing the result into `destination`, which
|
/// Compile `expr`, storing the result into `destination`, which
|
||||||
/// is assumed to be uninitialized.
|
/// is assumed to be uninitialized.
|
||||||
crate fn into_expr(
|
crate fn expr_into_dest(
|
||||||
&mut self,
|
&mut self,
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
|
debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
|
||||||
|
|
||||||
// since we frequently have to reference `self` from within a
|
// since we frequently have to reference `self` from within a
|
||||||
// closure, where `self` would be shadowed, it's easier to
|
// closure, where `self` would be shadowed, it's easier to
|
||||||
|
@ -40,11 +41,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let region_scope = (region_scope, source_info);
|
let region_scope = (region_scope, source_info);
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
this.in_scope(region_scope, lint_level, |this| {
|
this.in_scope(region_scope, lint_level, |this| {
|
||||||
this.into(destination, block, value)
|
this.expr_into_dest(destination, block, value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Block { body: ast_block } => {
|
ExprKind::Block { body: ref ast_block } => {
|
||||||
this.ast_block(destination, block, ast_block, source_info)
|
this.ast_block(destination, block, ast_block, source_info)
|
||||||
}
|
}
|
||||||
ExprKind::Match { scrutinee, arms } => {
|
ExprKind::Match { scrutinee, arms } => {
|
||||||
|
@ -58,17 +59,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
let mut then_block = this.cfg.start_new_block();
|
let mut then_block = this.cfg.start_new_block();
|
||||||
let mut else_block = this.cfg.start_new_block();
|
let mut else_block = this.cfg.start_new_block();
|
||||||
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
|
let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
|
||||||
this.cfg.terminate(block, source_info, term);
|
this.cfg.terminate(block, source_info, term);
|
||||||
|
|
||||||
unpack!(then_block = this.into(destination, then_block, then));
|
unpack!(then_block = this.expr_into_dest(destination, then_block, then));
|
||||||
else_block = if let Some(else_opt) = else_opt {
|
else_block = if let Some(else_opt) = else_opt {
|
||||||
unpack!(this.into(destination, else_block, else_opt))
|
unpack!(this.expr_into_dest(destination, else_block, else_opt))
|
||||||
} else {
|
} else {
|
||||||
// Body of the `if` expression without an `else` clause must return `()`, thus
|
// Body of the `if` expression without an `else` clause must return `()`, thus
|
||||||
// we implicitly generate a `else {}` if it is not specified.
|
// we implicitly generate a `else {}` if it is not specified.
|
||||||
let correct_si = this.source_info(expr_span.shrink_to_hi());
|
let correct_si = this.source_info(expr_span.shrink_to_hi());
|
||||||
this.cfg.push_assign_unit(else_block, correct_si, destination, this.hir.tcx());
|
this.cfg.push_assign_unit(else_block, correct_si, destination, this.tcx);
|
||||||
else_block
|
else_block
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
join_block.unit()
|
join_block.unit()
|
||||||
}
|
}
|
||||||
ExprKind::NeverToAny { source } => {
|
ExprKind::NeverToAny { source } => {
|
||||||
let source = this.hir.mirror(source);
|
|
||||||
let is_call =
|
let is_call =
|
||||||
matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
|
matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
|
||||||
|
|
||||||
|
@ -132,25 +132,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
LogicalOp::And => (else_block, false_block),
|
LogicalOp::And => (else_block, false_block),
|
||||||
LogicalOp::Or => (true_block, else_block),
|
LogicalOp::Or => (true_block, else_block),
|
||||||
};
|
};
|
||||||
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
|
let term = TerminatorKind::if_(this.tcx, lhs, blocks.0, blocks.1);
|
||||||
this.cfg.terminate(block, source_info, term);
|
this.cfg.terminate(block, source_info, term);
|
||||||
|
|
||||||
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
|
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
|
||||||
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
|
let term = TerminatorKind::if_(this.tcx, rhs, true_block, false_block);
|
||||||
this.cfg.terminate(else_block, source_info, term);
|
this.cfg.terminate(else_block, source_info, term);
|
||||||
|
|
||||||
this.cfg.push_assign_constant(
|
this.cfg.push_assign_constant(
|
||||||
true_block,
|
true_block,
|
||||||
source_info,
|
source_info,
|
||||||
destination,
|
destination,
|
||||||
Constant { span: expr_span, user_ty: None, literal: this.hir.true_literal() },
|
Constant {
|
||||||
|
span: expr_span,
|
||||||
|
user_ty: None,
|
||||||
|
literal: ty::Const::from_bool(this.tcx, true),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.cfg.push_assign_constant(
|
this.cfg.push_assign_constant(
|
||||||
false_block,
|
false_block,
|
||||||
source_info,
|
source_info,
|
||||||
destination,
|
destination,
|
||||||
Constant { span: expr_span, user_ty: None, literal: this.hir.false_literal() },
|
Constant {
|
||||||
|
span: expr_span,
|
||||||
|
user_ty: None,
|
||||||
|
literal: ty::Const::from_bool(this.tcx, false),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Link up both branches:
|
// Link up both branches:
|
||||||
|
@ -188,7 +196,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// introduce a unit temporary as the destination for the loop body.
|
// introduce a unit temporary as the destination for the loop body.
|
||||||
let tmp = this.get_unit_temp();
|
let tmp = this.get_unit_temp();
|
||||||
// Execute the body, branching back to the test.
|
// Execute the body, branching back to the test.
|
||||||
let body_block_end = unpack!(this.into(tmp, body_block, body));
|
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
|
||||||
this.cfg.goto(body_block_end, source_info, loop_block);
|
this.cfg.goto(body_block_end, source_info, loop_block);
|
||||||
|
|
||||||
// Loops are only exited by `break` expressions.
|
// Loops are only exited by `break` expressions.
|
||||||
|
@ -206,7 +214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
this.record_operands_moved(&args);
|
this.record_operands_moved(&args);
|
||||||
|
|
||||||
debug!("into_expr: fn_span={:?}", fn_span);
|
debug!("expr_into_dest: fn_span={:?}", fn_span);
|
||||||
|
|
||||||
this.cfg.terminate(
|
this.cfg.terminate(
|
||||||
block,
|
block,
|
||||||
|
@ -230,7 +238,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.diverge_from(block);
|
this.diverge_from(block);
|
||||||
success.unit()
|
success.unit()
|
||||||
}
|
}
|
||||||
ExprKind::Use { source } => this.into(destination, block, source),
|
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
|
||||||
ExprKind::Borrow { arg, borrow_kind } => {
|
ExprKind::Borrow { arg, borrow_kind } => {
|
||||||
// We don't do this in `as_rvalue` because we use `as_place`
|
// We don't do this in `as_rvalue` because we use `as_place`
|
||||||
// for borrow expressions, so we cannot create an `RValue` that
|
// for borrow expressions, so we cannot create an `RValue` that
|
||||||
|
@ -241,8 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
|
BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
|
||||||
_ => unpack!(block = this.as_place(block, arg)),
|
_ => unpack!(block = this.as_place(block, arg)),
|
||||||
};
|
};
|
||||||
let borrow =
|
let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place);
|
||||||
Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place);
|
|
||||||
this.cfg.push_assign(block, source_info, destination, borrow);
|
this.cfg.push_assign(block, source_info, destination, borrow);
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
@ -255,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.cfg.push_assign(block, source_info, destination, address_of);
|
this.cfg.push_assign(block, source_info, destination, address_of);
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, base } => {
|
ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, ref base } => {
|
||||||
// See the notes for `ExprKind::Array` in `as_rvalue` and for
|
// See the notes for `ExprKind::Array` in `as_rvalue` and for
|
||||||
// `ExprKind::Borrow` above.
|
// `ExprKind::Borrow` above.
|
||||||
let is_union = adt_def.is_union();
|
let is_union = adt_def.is_union();
|
||||||
|
@ -270,7 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
.map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
|
.map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_names = this.hir.all_fields(adt_def, variant_index);
|
let field_names: Vec<_> =
|
||||||
|
(0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
|
||||||
|
|
||||||
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
|
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
|
||||||
let place_builder = unpack!(block = this.as_place_builder(block, base));
|
let place_builder = unpack!(block = this.as_place_builder(block, base));
|
||||||
|
@ -288,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.consume_by_copy_or_move(
|
this.consume_by_copy_or_move(
|
||||||
place_builder
|
place_builder
|
||||||
.field(n, ty)
|
.field(n, ty)
|
||||||
.into_place(this.hir.tcx(), this.hir.typeck_results()),
|
.into_place(this.tcx, this.typeck_results),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -325,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
let operands = operands
|
let operands = operands
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|op| match op {
|
.map(|op| match *op {
|
||||||
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
|
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
|
||||||
reg,
|
reg,
|
||||||
value: unpack!(block = this.as_local_operand(block, expr)),
|
value: unpack!(block = this.as_local_operand(block, expr)),
|
||||||
|
@ -334,7 +342,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
mir::InlineAsmOperand::Out {
|
mir::InlineAsmOperand::Out {
|
||||||
reg,
|
reg,
|
||||||
late,
|
late,
|
||||||
place: expr.map(|expr| unpack!(block = this.as_place(block, expr))),
|
place: expr
|
||||||
|
.as_ref()
|
||||||
|
.map(|expr| unpack!(block = this.as_place(block, expr))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thir::InlineAsmOperand::InOut { reg, late, expr } => {
|
thir::InlineAsmOperand::InOut { reg, late, expr } => {
|
||||||
|
@ -352,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
reg,
|
reg,
|
||||||
late,
|
late,
|
||||||
in_value: unpack!(block = this.as_local_operand(block, in_expr)),
|
in_value: unpack!(block = this.as_local_operand(block, in_expr)),
|
||||||
out_place: out_expr.map(|out_expr| {
|
out_place: out_expr.as_ref().map(|out_expr| {
|
||||||
unpack!(block = this.as_place(block, out_expr))
|
unpack!(block = this.as_place(block, out_expr))
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -394,7 +404,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::AssignOp { .. }
|
| ExprKind::AssignOp { .. }
|
||||||
| ExprKind::LlvmInlineAsm { .. } => {
|
| ExprKind::LlvmInlineAsm { .. } => {
|
||||||
unpack!(block = this.stmt_expr(block, expr, None));
|
unpack!(block = this.stmt_expr(block, expr, None));
|
||||||
this.cfg.push_assign_unit(block, source_info, destination, this.hir.tcx());
|
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//! a type that is not `Copy`, then using any of these functions will
|
//! a type that is not `Copy`, then using any of these functions will
|
||||||
//! "move" the value out of its current home (if any).
|
//! "move" the value out of its current home (if any).
|
||||||
//!
|
//!
|
||||||
//! - `into` -- writes the value into a specific location, which
|
//! - `expr_into_dest` -- writes the value into a specific location, which
|
||||||
//! should be uninitialized
|
//! should be uninitialized
|
||||||
//! - `as_operand` -- evaluates the value and yields an `Operand`,
|
//! - `as_operand` -- evaluates the value and yields an `Operand`,
|
||||||
//! suitable for use as an argument to an `Rvalue`
|
//! suitable for use as an argument to an `Rvalue`
|
||||||
|
|
|
@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
crate fn stmt_expr(
|
crate fn stmt_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
statement_scope: Option<region::Scope>,
|
statement_scope: Option<region::Scope>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
@ -21,29 +21,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let source_info = this.source_info(expr.span);
|
let source_info = this.source_info(expr.span);
|
||||||
// Handle a number of expressions that don't need a destination at all. This
|
// Handle a number of expressions that don't need a destination at all. This
|
||||||
// avoids needing a mountain of temporary `()` variables.
|
// avoids needing a mountain of temporary `()` variables.
|
||||||
let expr2 = expr.clone();
|
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Scope { region_scope, lint_level, value } => {
|
ExprKind::Scope { region_scope, lint_level, value } => {
|
||||||
let value = this.hir.mirror(value);
|
|
||||||
this.in_scope((region_scope, source_info), lint_level, |this| {
|
this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||||
this.stmt_expr(block, value, statement_scope)
|
this.stmt_expr(block, value, statement_scope)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Assign { lhs, rhs } => {
|
ExprKind::Assign { lhs, rhs } => {
|
||||||
let lhs = this.hir.mirror(lhs);
|
|
||||||
let rhs = this.hir.mirror(rhs);
|
|
||||||
let lhs_span = lhs.span;
|
let lhs_span = lhs.span;
|
||||||
|
|
||||||
// Note: we evaluate assignments right-to-left. This
|
// Note: we evaluate assignments right-to-left. This
|
||||||
// is better for borrowck interaction with overloaded
|
// is better for borrowck interaction with overloaded
|
||||||
// operators like x[j] = x[i].
|
// operators like x[j] = x[i].
|
||||||
|
|
||||||
debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2);
|
debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr);
|
||||||
this.block_context.push(BlockFrame::SubExpr);
|
this.block_context.push(BlockFrame::SubExpr);
|
||||||
|
|
||||||
// Generate better code for things that don't need to be
|
// Generate better code for things that don't need to be
|
||||||
// dropped.
|
// dropped.
|
||||||
if this.hir.needs_drop(lhs.ty) {
|
if lhs.ty.needs_drop(this.tcx, this.param_env) {
|
||||||
let rhs = unpack!(block = this.as_local_operand(block, rhs));
|
let rhs = unpack!(block = this.as_local_operand(block, rhs));
|
||||||
let lhs = unpack!(block = this.as_place(block, lhs));
|
let lhs = unpack!(block = this.as_place(block, lhs));
|
||||||
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
|
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
|
||||||
|
@ -65,10 +61,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// only affects weird things like `x += {x += 1; x}`
|
// only affects weird things like `x += {x += 1; x}`
|
||||||
// -- is that equal to `x + (x + 1)` or `2*(x+1)`?
|
// -- is that equal to `x + (x + 1)` or `2*(x+1)`?
|
||||||
|
|
||||||
let lhs = this.hir.mirror(lhs);
|
|
||||||
let lhs_ty = lhs.ty;
|
let lhs_ty = lhs.ty;
|
||||||
|
|
||||||
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
|
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
|
||||||
this.block_context.push(BlockFrame::SubExpr);
|
this.block_context.push(BlockFrame::SubExpr);
|
||||||
|
|
||||||
// As above, RTL.
|
// As above, RTL.
|
||||||
|
@ -90,24 +85,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::Continue { label } => {
|
ExprKind::Continue { label } => {
|
||||||
this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
|
this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
|
||||||
}
|
}
|
||||||
ExprKind::Break { label, value } => {
|
ExprKind::Break { label, value } => this.break_scope(
|
||||||
this.break_scope(block, value, BreakableTarget::Break(label), source_info)
|
block,
|
||||||
}
|
value.as_deref(),
|
||||||
|
BreakableTarget::Break(label),
|
||||||
|
source_info,
|
||||||
|
),
|
||||||
ExprKind::Return { value } => {
|
ExprKind::Return { value } => {
|
||||||
this.break_scope(block, value, BreakableTarget::Return, source_info)
|
this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
|
||||||
}
|
}
|
||||||
ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
|
ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
|
||||||
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2);
|
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
|
||||||
this.block_context.push(BlockFrame::SubExpr);
|
this.block_context.push(BlockFrame::SubExpr);
|
||||||
let outputs = outputs
|
let outputs = outputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|output| unpack!(block = this.as_place(block, output)))
|
.map(|output| unpack!(block = this.as_place(block, &output)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
let inputs = inputs
|
let inputs = inputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|input| {
|
.map(|input| {
|
||||||
(input.span(), unpack!(block = this.as_local_operand(block, input)))
|
(input.span, unpack!(block = this.as_local_operand(block, &input)))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
|
@ -140,15 +138,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// it is usually better to focus on `the_value` rather
|
// it is usually better to focus on `the_value` rather
|
||||||
// than the entirety of block(s) surrounding it.
|
// than the entirety of block(s) surrounding it.
|
||||||
let adjusted_span = (|| {
|
let adjusted_span = (|| {
|
||||||
if let ExprKind::Block { body } = expr.kind {
|
if let ExprKind::Block { body } = &expr.kind {
|
||||||
if let Some(tail_expr) = &body.expr {
|
if let Some(tail_expr) = &body.expr {
|
||||||
let mut expr = tail_expr;
|
let mut expr = &*tail_expr;
|
||||||
while let rustc_hir::ExprKind::Block(subblock, _label) = &expr.kind {
|
while let ExprKind::Block {
|
||||||
if let Some(subtail_expr) = &subblock.expr {
|
body: Block { expr: Some(nested_expr), .. },
|
||||||
expr = subtail_expr
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
| ExprKind::Scope { value: nested_expr, .. } = &expr.kind
|
||||||
|
{
|
||||||
|
expr = nested_expr;
|
||||||
}
|
}
|
||||||
this.block_context.push(BlockFrame::TailExpr {
|
this.block_context.push(BlockFrame::TailExpr {
|
||||||
tail_result_is_ignored: true,
|
tail_result_is_ignored: true,
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
//! In general, there are a number of things for which it's convenient
|
|
||||||
//! to just call `builder.into` and have it emit its result into a
|
|
||||||
//! given location. This is basically for expressions or things that can be
|
|
||||||
//! wrapped up as expressions (e.g., blocks). To make this ergonomic, we use this
|
|
||||||
//! latter `EvalInto` trait.
|
|
||||||
|
|
||||||
use crate::build::{BlockAnd, Builder};
|
|
||||||
use crate::thir::*;
|
|
||||||
use rustc_middle::mir::*;
|
|
||||||
|
|
||||||
pub(in crate::build) trait EvalInto<'tcx> {
|
|
||||||
fn eval_into(
|
|
||||||
self,
|
|
||||||
builder: &mut Builder<'_, 'tcx>,
|
|
||||||
destination: Place<'tcx>,
|
|
||||||
block: BasicBlock,
|
|
||||||
) -> BlockAnd<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|
||||||
crate fn into<E>(
|
|
||||||
&mut self,
|
|
||||||
destination: Place<'tcx>,
|
|
||||||
block: BasicBlock,
|
|
||||||
expr: E,
|
|
||||||
) -> BlockAnd<()>
|
|
||||||
where
|
|
||||||
E: EvalInto<'tcx>,
|
|
||||||
{
|
|
||||||
expr.eval_into(self, destination, block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
|
|
||||||
fn eval_into(
|
|
||||||
self,
|
|
||||||
builder: &mut Builder<'_, 'tcx>,
|
|
||||||
destination: Place<'tcx>,
|
|
||||||
block: BasicBlock,
|
|
||||||
) -> BlockAnd<()> {
|
|
||||||
let expr = builder.hir.mirror(self);
|
|
||||||
builder.into_expr(destination, block, expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
|
|
||||||
fn eval_into(
|
|
||||||
self,
|
|
||||||
builder: &mut Builder<'_, 'tcx>,
|
|
||||||
destination: Place<'tcx>,
|
|
||||||
block: BasicBlock,
|
|
||||||
) -> BlockAnd<()> {
|
|
||||||
builder.into_expr(destination, block, self)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -89,10 +89,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scrutinee: ExprRef<'tcx>,
|
scrutinee: &Expr<'_, 'tcx>,
|
||||||
arms: Vec<Arm<'tcx>>,
|
arms: &[Arm<'_, 'tcx>],
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let scrutinee_span = scrutinee.span();
|
let scrutinee_span = scrutinee.span;
|
||||||
let scrutinee_place =
|
let scrutinee_place =
|
||||||
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
|
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn lower_scrutinee(
|
fn lower_scrutinee(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scrutinee: ExprRef<'tcx>,
|
scrutinee: &Expr<'_, 'tcx>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
) -> BlockAnd<Place<'tcx>> {
|
) -> BlockAnd<Place<'tcx>> {
|
||||||
let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
|
let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
|
||||||
|
@ -149,8 +149,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn create_match_candidates<'pat>(
|
fn create_match_candidates<'pat>(
|
||||||
&mut self,
|
&mut self,
|
||||||
scrutinee: Place<'tcx>,
|
scrutinee: Place<'tcx>,
|
||||||
arms: &'pat [Arm<'tcx>],
|
arms: &'pat [Arm<'pat, 'tcx>],
|
||||||
) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> {
|
) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> {
|
||||||
// Assemble a list of candidates: there is one candidate per pattern,
|
// Assemble a list of candidates: there is one candidate per pattern,
|
||||||
// which means there may be more than one candidate *per arm*.
|
// which means there may be more than one candidate *per arm*.
|
||||||
arms.iter()
|
arms.iter()
|
||||||
|
@ -224,7 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
scrutinee_place: Place<'tcx>,
|
scrutinee_place: Place<'tcx>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
|
arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>,
|
||||||
outer_source_info: SourceInfo,
|
outer_source_info: SourceInfo,
|
||||||
fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
|
fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
|
@ -236,7 +236,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let arm_source_info = self.source_info(arm.span);
|
let arm_source_info = self.source_info(arm.span);
|
||||||
let arm_scope = (arm.scope, arm_source_info);
|
let arm_scope = (arm.scope, arm_source_info);
|
||||||
self.in_scope(arm_scope, arm.lint_level, |this| {
|
self.in_scope(arm_scope, arm.lint_level, |this| {
|
||||||
let body = this.hir.mirror(arm.body.clone());
|
|
||||||
let scope = this.declare_bindings(
|
let scope = this.declare_bindings(
|
||||||
None,
|
None,
|
||||||
arm.span,
|
arm.span,
|
||||||
|
@ -259,7 +258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.source_scope = source_scope;
|
this.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.into(destination, arm_block, body)
|
this.expr_into_dest(destination, arm_block, &arm.body)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -286,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
outer_source_info: SourceInfo,
|
outer_source_info: SourceInfo,
|
||||||
candidate: Candidate<'_, 'tcx>,
|
candidate: Candidate<'_, 'tcx>,
|
||||||
guard: Option<&Guard<'tcx>>,
|
guard: Option<&Guard<'_, 'tcx>>,
|
||||||
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
|
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_span: Option<Span>,
|
arm_span: Option<Span>,
|
||||||
|
@ -362,14 +361,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
irrefutable_pat: Pat<'tcx>,
|
irrefutable_pat: Pat<'tcx>,
|
||||||
initializer: ExprRef<'tcx>,
|
initializer: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
match *irrefutable_pat.kind {
|
match *irrefutable_pat.kind {
|
||||||
// Optimize the case of `let x = ...` to write directly into `x`
|
// Optimize the case of `let x = ...` to write directly into `x`
|
||||||
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
||||||
let place =
|
let place =
|
||||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||||
unpack!(block = self.into(place, block, initializer));
|
unpack!(block = self.expr_into_dest(place, block, initializer));
|
||||||
|
|
||||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||||
let source_info = self.source_info(irrefutable_pat.span);
|
let source_info = self.source_info(irrefutable_pat.span);
|
||||||
|
@ -404,7 +403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
} => {
|
} => {
|
||||||
let place =
|
let place =
|
||||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||||
unpack!(block = self.into(place, block, initializer));
|
unpack!(block = self.expr_into_dest(place, block, initializer));
|
||||||
|
|
||||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||||
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
||||||
|
@ -414,7 +413,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let ty_source_info = self.source_info(user_ty_span);
|
let ty_source_info = self.source_info(user_ty_span);
|
||||||
let user_ty = pat_ascription_ty.user_ty(
|
let user_ty = pat_ascription_ty.user_ty(
|
||||||
&mut self.canonical_user_type_annotations,
|
&mut self.canonical_user_type_annotations,
|
||||||
place.ty(&self.local_decls, self.hir.tcx()).ty,
|
place.ty(&self.local_decls, self.tcx).ty,
|
||||||
ty_source_info.span,
|
ty_source_info.span,
|
||||||
);
|
);
|
||||||
self.cfg.push(
|
self.cfg.push(
|
||||||
|
@ -556,7 +555,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let local_id = self.var_local_id(var, for_guard);
|
let local_id = self.var_local_id(var, for_guard);
|
||||||
let source_info = self.source_info(span);
|
let source_info = self.source_info(span);
|
||||||
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
|
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
|
||||||
let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
|
let region_scope = self.region_scope_tree.var_scope(var.local_id);
|
||||||
if schedule_drop {
|
if schedule_drop {
|
||||||
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
|
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
|
||||||
}
|
}
|
||||||
|
@ -565,7 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
|
crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
|
||||||
let local_id = self.var_local_id(var, for_guard);
|
let local_id = self.var_local_id(var, for_guard);
|
||||||
let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
|
let region_scope = self.region_scope_tree.var_scope(var.local_id);
|
||||||
self.schedule_drop(span, region_scope, local_id, DropKind::Value);
|
self.schedule_drop(span, region_scope, local_id, DropKind::Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,7 +1070,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
fake_borrows.insert(Place {
|
fake_borrows.insert(Place {
|
||||||
local: source.local,
|
local: source.local,
|
||||||
projection: self.hir.tcx().intern_place_elems(proj_base),
|
projection: self.tcx.intern_place_elems(proj_base),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1550,7 +1549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fake_borrows: &'b FxHashSet<Place<'tcx>>,
|
fake_borrows: &'b FxHashSet<Place<'tcx>>,
|
||||||
temp_span: Span,
|
temp_span: Span,
|
||||||
) -> Vec<(Place<'tcx>, Local)> {
|
) -> Vec<(Place<'tcx>, Local)> {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
|
|
||||||
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
|
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
|
||||||
|
|
||||||
|
@ -1613,7 +1612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
candidate: Candidate<'pat, 'tcx>,
|
candidate: Candidate<'pat, 'tcx>,
|
||||||
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
|
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
|
||||||
guard: Option<&Guard<'tcx>>,
|
guard: Option<&Guard<'_, 'tcx>>,
|
||||||
fake_borrows: &Vec<(Place<'tcx>, Local)>,
|
fake_borrows: &Vec<(Place<'tcx>, Local)>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
arm_span: Option<Span>,
|
arm_span: Option<Span>,
|
||||||
|
@ -1727,7 +1726,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// * So we eagerly create the reference for the arm and then take a
|
// * So we eagerly create the reference for the arm and then take a
|
||||||
// reference to that.
|
// reference to that.
|
||||||
if let Some(guard) = guard {
|
if let Some(guard) = guard {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let bindings = parent_bindings
|
let bindings = parent_bindings
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|(bindings, _)| bindings)
|
.flat_map(|(bindings, _)| bindings)
|
||||||
|
@ -1749,15 +1748,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
|
let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
|
||||||
Guard::If(e) => {
|
Guard::If(e) => {
|
||||||
let e = self.hir.mirror(e.clone());
|
|
||||||
let source_info = self.source_info(e.span);
|
let source_info = self.source_info(e.span);
|
||||||
(e.span, self.test_bool(block, e, source_info))
|
(e.span, self.test_bool(block, e, source_info))
|
||||||
}
|
}
|
||||||
Guard::IfLet(pat, scrutinee) => {
|
Guard::IfLet(pat, scrutinee) => {
|
||||||
let scrutinee_span = scrutinee.span();
|
let scrutinee_span = scrutinee.span;
|
||||||
let scrutinee_place = unpack!(
|
let scrutinee_place =
|
||||||
block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)
|
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span));
|
||||||
);
|
|
||||||
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
|
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
|
||||||
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||||
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
|
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
|
||||||
|
@ -1772,14 +1769,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pat.span.to(arm_span.unwrap()),
|
pat.span.to(arm_span.unwrap()),
|
||||||
pat,
|
pat,
|
||||||
ArmHasGuard(false),
|
ArmHasGuard(false),
|
||||||
Some((Some(&scrutinee_place), scrutinee.span())),
|
Some((Some(&scrutinee_place), scrutinee.span)),
|
||||||
);
|
);
|
||||||
let post_guard_block = self.bind_pattern(
|
let post_guard_block = self.bind_pattern(
|
||||||
self.source_info(pat.span),
|
self.source_info(pat.span),
|
||||||
guard_candidate,
|
guard_candidate,
|
||||||
None,
|
None,
|
||||||
&fake_borrow_temps,
|
&fake_borrow_temps,
|
||||||
scrutinee.span(),
|
scrutinee.span,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -1888,7 +1885,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
let user_ty = ascription.user_ty.clone().user_ty(
|
let user_ty = ascription.user_ty.clone().user_ty(
|
||||||
&mut self.canonical_user_type_annotations,
|
&mut self.canonical_user_type_annotations,
|
||||||
ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
|
ascription.source.ty(&self.local_decls, self.tcx).ty,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
);
|
);
|
||||||
self.cfg.push(
|
self.cfg.push(
|
||||||
|
@ -1917,7 +1914,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Assign each of the bindings. Since we are binding for a
|
// Assign each of the bindings. Since we are binding for a
|
||||||
// guard expression, this will never trigger moves out of the
|
// guard expression, this will never trigger moves out of the
|
||||||
// candidate.
|
// candidate.
|
||||||
let re_erased = self.hir.tcx().lifetimes.re_erased;
|
let re_erased = self.tcx.lifetimes.re_erased;
|
||||||
for binding in bindings {
|
for binding in bindings {
|
||||||
debug!("bind_matched_candidate_for_guard(binding={:?})", binding);
|
debug!("bind_matched_candidate_for_guard(binding={:?})", binding);
|
||||||
let source_info = self.source_info(binding.span);
|
let source_info = self.source_info(binding.span);
|
||||||
|
@ -1966,7 +1963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
debug!("bind_matched_candidate_for_arm_body(block={:?})", block);
|
debug!("bind_matched_candidate_for_arm_body(block={:?})", block);
|
||||||
|
|
||||||
let re_erased = self.hir.tcx().lifetimes.re_erased;
|
let re_erased = self.tcx.lifetimes.re_erased;
|
||||||
// Assign each of the bindings. This may trigger moves out of the candidate.
|
// Assign each of the bindings. This may trigger moves out of the candidate.
|
||||||
for binding in bindings {
|
for binding in bindings {
|
||||||
let source_info = self.source_info(binding.span);
|
let source_info = self.source_info(binding.span);
|
||||||
|
@ -2015,7 +2012,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
var_id, name, mode, var_ty, visibility_scope, source_info
|
var_id, name, mode, var_ty, visibility_scope, source_info
|
||||||
);
|
);
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
|
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
|
||||||
let binding_mode = match mode {
|
let binding_mode = match mode {
|
||||||
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
|
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
match_pair: MatchPair<'pat, 'tcx>,
|
match_pair: MatchPair<'pat, 'tcx>,
|
||||||
candidate: &mut Candidate<'pat, 'tcx>,
|
candidate: &mut Candidate<'pat, 'tcx>,
|
||||||
) -> Result<(), MatchPair<'pat, 'tcx>> {
|
) -> Result<(), MatchPair<'pat, 'tcx>> {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
match *match_pair.pattern.kind {
|
match *match_pair.pattern.kind {
|
||||||
PatKind::AscribeUserType {
|
PatKind::AscribeUserType {
|
||||||
ref subpattern,
|
ref subpattern,
|
||||||
|
@ -251,13 +251,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
|
PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
|
||||||
let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
|
let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
|
||||||
i == variant_index || {
|
i == variant_index || {
|
||||||
self.hir.tcx().features().exhaustive_patterns
|
self.tcx.features().exhaustive_patterns
|
||||||
&& !v
|
&& !v
|
||||||
.uninhabited_from(
|
.uninhabited_from(
|
||||||
self.hir.tcx(),
|
self.tcx,
|
||||||
substs,
|
substs,
|
||||||
adt_def.adt_kind(),
|
adt_def.adt_kind(),
|
||||||
self.hir.param_env,
|
self.param_env,
|
||||||
)
|
)
|
||||||
.is_empty()
|
.is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,11 @@ use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_hir::{LangItem, RangeEnd};
|
use rustc_hir::{LangItem, RangeEnd};
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
use rustc_middle::ty::subst::{GenericArg, Subst};
|
||||||
use rustc_middle::ty::util::IntTypeExt;
|
use rustc_middle::ty::util::IntTypeExt;
|
||||||
use rustc_middle::ty::{self, adjustment::PointerCast, Ty};
|
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::def_id::DefId;
|
||||||
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -93,9 +95,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
match *match_pair.pattern.kind {
|
match *match_pair.pattern.kind {
|
||||||
PatKind::Constant { value } => {
|
PatKind::Constant { value } => {
|
||||||
options.entry(value).or_insert_with(|| {
|
options
|
||||||
value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty)
|
.entry(value)
|
||||||
});
|
.or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
PatKind::Variant { .. } => {
|
PatKind::Variant { .. } => {
|
||||||
|
@ -157,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
"perform_test({:?}, {:?}: {:?}, {:?})",
|
"perform_test({:?}, {:?}: {:?}, {:?})",
|
||||||
block,
|
block,
|
||||||
place,
|
place,
|
||||||
place.ty(&self.local_decls, self.hir.tcx()),
|
place.ty(&self.local_decls, self.tcx),
|
||||||
test
|
test
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -169,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let num_enum_variants = adt_def.variants.len();
|
let num_enum_variants = adt_def.variants.len();
|
||||||
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
|
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
|
||||||
let otherwise_block = *target_blocks.last().unwrap();
|
let otherwise_block = *target_blocks.last().unwrap();
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let switch_targets = SwitchTargets::new(
|
let switch_targets = SwitchTargets::new(
|
||||||
adt_def.discriminants(tcx).filter_map(|(idx, discr)| {
|
adt_def.discriminants(tcx).filter_map(|(idx, discr)| {
|
||||||
if variants.contains(idx) {
|
if variants.contains(idx) {
|
||||||
|
@ -217,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
0 => (second_bb, first_bb),
|
0 => (second_bb, first_bb),
|
||||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
|
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
|
||||||
};
|
};
|
||||||
TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place), true_bb, false_bb)
|
TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
|
||||||
} else {
|
} else {
|
||||||
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
|
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
|
||||||
}
|
}
|
||||||
|
@ -292,7 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
TestKind::Len { len, op } => {
|
TestKind::Len { len, op } => {
|
||||||
let target_blocks = make_target_blocks(self);
|
let target_blocks = make_target_blocks(self);
|
||||||
|
|
||||||
let usize_ty = self.hir.usize_ty();
|
let usize_ty = self.tcx.types.usize;
|
||||||
let actual = self.temp(usize_ty, test.span);
|
let actual = self.temp(usize_ty, test.span);
|
||||||
|
|
||||||
// actual = len(place)
|
// actual = len(place)
|
||||||
|
@ -331,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
left: Operand<'tcx>,
|
left: Operand<'tcx>,
|
||||||
right: Operand<'tcx>,
|
right: Operand<'tcx>,
|
||||||
) {
|
) {
|
||||||
let bool_ty = self.hir.bool_ty();
|
let bool_ty = self.tcx.types.bool;
|
||||||
let result = self.temp(bool_ty, source_info.span);
|
let result = self.temp(bool_ty, source_info.span);
|
||||||
|
|
||||||
// result = op(left, right)
|
// result = op(left, right)
|
||||||
|
@ -341,7 +343,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.terminate(
|
self.cfg.terminate(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), success_block, fail_block),
|
TerminatorKind::if_(self.tcx, Operand::Move(result), success_block, fail_block),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// nothing to do, neither is an array
|
// nothing to do, neither is an array
|
||||||
(None, None) => {}
|
(None, None) => {}
|
||||||
(Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
|
(Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
// make both a slice
|
// make both a slice
|
||||||
ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
|
ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
|
||||||
if opt_ref_ty.is_some() {
|
if opt_ref_ty.is_some() {
|
||||||
|
@ -408,10 +410,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
_ => bug!("non_scalar_compare called on non-reference type: {}", ty),
|
_ => bug!("non_scalar_compare called on non-reference type: {}", ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None);
|
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, None);
|
||||||
let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);
|
let method = trait_method(self.tcx, eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);
|
||||||
|
|
||||||
let bool_ty = self.hir.bool_ty();
|
let bool_ty = self.tcx.types.bool;
|
||||||
let eq_result = self.temp(bool_ty, source_info.span);
|
let eq_result = self.temp(bool_ty, source_info.span);
|
||||||
let eq_block = self.cfg.start_new_block();
|
let eq_block = self.cfg.start_new_block();
|
||||||
self.cfg.terminate(
|
self.cfg.terminate(
|
||||||
|
@ -443,12 +445,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.terminate(
|
self.cfg.terminate(
|
||||||
eq_block,
|
eq_block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::if_(
|
TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
|
||||||
self.hir.tcx(),
|
|
||||||
Operand::Move(eq_result),
|
|
||||||
success_block,
|
|
||||||
fail_block,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
bug!("`TestKind::Eq` should have two target blocks")
|
bug!("`TestKind::Eq` should have two target blocks")
|
||||||
|
@ -632,11 +629,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
use rustc_hir::RangeEnd::*;
|
use rustc_hir::RangeEnd::*;
|
||||||
use std::cmp::Ordering::*;
|
use std::cmp::Ordering::*;
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let test_ty = test.lo.ty;
|
let test_ty = test.lo.ty;
|
||||||
let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?;
|
let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
|
||||||
let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?;
|
let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
|
||||||
|
|
||||||
match (test.end, pat.end, lo, hi) {
|
match (test.end, pat.end, lo, hi) {
|
||||||
// pat < test
|
// pat < test
|
||||||
|
@ -731,7 +728,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
candidate: &mut Candidate<'pat, 'tcx>,
|
candidate: &mut Candidate<'pat, 'tcx>,
|
||||||
) {
|
) {
|
||||||
let match_pair = candidate.match_pairs.remove(match_pair_index);
|
let match_pair = candidate.match_pairs.remove(match_pair_index);
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
|
|
||||||
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
|
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
|
||||||
// we want to create a set of derived match-patterns like
|
// we want to create a set of derived match-patterns like
|
||||||
|
@ -762,10 +759,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
) -> Option<bool> {
|
) -> Option<bool> {
|
||||||
use std::cmp::Ordering::*;
|
use std::cmp::Ordering::*;
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?;
|
let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?;
|
||||||
let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?;
|
let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?;
|
||||||
|
|
||||||
match (b, range.end) {
|
match (b, range.end) {
|
||||||
(Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
|
(Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
|
||||||
|
@ -815,3 +812,25 @@ impl Test<'_> {
|
||||||
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
||||||
ty.is_integral() || ty.is_char() || ty.is_bool()
|
ty.is_integral() || ty.is_char() || ty.is_bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trait_method<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
trait_def_id: DefId,
|
||||||
|
method_name: Symbol,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
params: &[GenericArg<'tcx>],
|
||||||
|
) -> &'tcx ty::Const<'tcx> {
|
||||||
|
let substs = tcx.mk_substs_trait(self_ty, params);
|
||||||
|
|
||||||
|
// The unhygienic comparison here is acceptable because this is only
|
||||||
|
// used on known traits.
|
||||||
|
let item = tcx
|
||||||
|
.associated_items(trait_def_id)
|
||||||
|
.filter_by_name_unhygienic(method_name)
|
||||||
|
.find(|item| item.kind == ty::AssocKind::Fn)
|
||||||
|
.expect("trait method not found");
|
||||||
|
|
||||||
|
let method_ty = tcx.type_of(item.def_id);
|
||||||
|
let method_ty = method_ty.subst(tcx, substs);
|
||||||
|
ty::Const::zero_sized(tcx, method_ty)
|
||||||
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
subpatterns
|
subpatterns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fieldpat| {
|
.map(|fieldpat| {
|
||||||
let place =
|
let place = self.tcx.mk_place_field(place, fieldpat.field, fieldpat.pattern.ty);
|
||||||
self.hir.tcx().mk_place_field(place, fieldpat.field, fieldpat.pattern.ty);
|
|
||||||
MatchPair::new(place, &fieldpat.pattern)
|
MatchPair::new(place, &fieldpat.pattern)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -30,9 +29,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
opt_slice: Option<&'pat Pat<'tcx>>,
|
opt_slice: Option<&'pat Pat<'tcx>>,
|
||||||
suffix: &'pat [Pat<'tcx>],
|
suffix: &'pat [Pat<'tcx>],
|
||||||
) {
|
) {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() {
|
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() {
|
||||||
ty::Array(_, length) => (length.eval_usize(tcx, self.hir.param_env), true),
|
ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
|
||||||
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
use crate::build::Builder;
|
use crate::build::Builder;
|
||||||
|
|
||||||
use rustc_middle::ty::{self, Ty};
|
|
||||||
|
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Adds a new temporary value of type `ty` storing the result of
|
/// Adds a new temporary value of type `ty` storing the result of
|
||||||
|
@ -37,7 +37,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Returns a zero literal operand for the appropriate type, works for
|
// Returns a zero literal operand for the appropriate type, works for
|
||||||
// bool, char and integers.
|
// bool, char and integers.
|
||||||
crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||||
let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty));
|
let literal = ty::Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
value: u64,
|
value: u64,
|
||||||
) -> Place<'tcx> {
|
) -> Place<'tcx> {
|
||||||
let usize_ty = self.hir.usize_ty();
|
let usize_ty = self.tcx.types.usize;
|
||||||
let temp = self.temp(usize_ty, source_info.span);
|
let temp = self.temp(usize_ty, source_info.span);
|
||||||
self.cfg.push_assign_constant(
|
self.cfg.push_assign_constant(
|
||||||
block,
|
block,
|
||||||
|
@ -57,16 +57,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Constant {
|
Constant {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: self.hir.usize_literal(value),
|
literal: ty::Const::from_usize(self.tcx, value),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
temp
|
temp
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
|
crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let ty = place.ty(&self.local_decls, tcx).ty;
|
let ty = place.ty(&self.local_decls, tcx).ty;
|
||||||
if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) {
|
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
|
||||||
Operand::Move(place)
|
Operand::Move(place)
|
||||||
} else {
|
} else {
|
||||||
Operand::Copy(place)
|
Operand::Copy(place)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::build;
|
use crate::build;
|
||||||
use crate::build::scope::DropKind;
|
use crate::build::scope::DropKind;
|
||||||
use crate::thir::cx::Cx;
|
use crate::thir::cx::build_thir;
|
||||||
use crate::thir::{BindingMode, LintLevel, PatKind};
|
use crate::thir::{Arena, BindingMode, Expr, LintLevel, Pat, PatKind};
|
||||||
use rustc_attr::{self as attr, UnwindAttr};
|
use rustc_attr::{self as attr, UnwindAttr};
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -9,13 +9,13 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{GeneratorKind, HirIdMap, Node};
|
use rustc_hir::{GeneratorKind, HirIdMap, Node};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
|
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_target::spec::PanicStrategy;
|
use rustc_target::spec::PanicStrategy;
|
||||||
|
@ -42,6 +42,8 @@ crate fn mir_built<'tcx>(
|
||||||
/// Construct the MIR for a given `DefId`.
|
/// Construct the MIR for a given `DefId`.
|
||||||
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
|
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
|
||||||
let id = tcx.hir().local_def_id_to_hir_id(def.did);
|
let id = tcx.hir().local_def_id_to_hir_id(def.did);
|
||||||
|
let body_owner_kind = tcx.hir().body_owner_kind(id);
|
||||||
|
let typeck_results = tcx.typeck_opt_const_arg(def);
|
||||||
|
|
||||||
// Figure out what primary body this item has.
|
// Figure out what primary body this item has.
|
||||||
let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
|
let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
|
||||||
|
@ -86,15 +88,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
// If we don't have a specialized span for the body, just use the
|
// If we don't have a specialized span for the body, just use the
|
||||||
// normal def span.
|
// normal def span.
|
||||||
let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
|
let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
|
||||||
|
let arena = Arena::default();
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
let cx = Cx::new(&infcx, def, id);
|
let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
|
||||||
let body = if let Some(ErrorReported) = cx.typeck_results().tainted_by_errors {
|
build::construct_error(&infcx, def, id, body_id, body_owner_kind)
|
||||||
build::construct_error(cx, body_id)
|
} else if body_owner_kind.is_fn_or_closure() {
|
||||||
} else if cx.body_owner_kind.is_fn_or_closure() {
|
|
||||||
// fetch the fully liberated fn signature (that is, all bound
|
// fetch the fully liberated fn signature (that is, all bound
|
||||||
// types/lifetimes replaced)
|
// types/lifetimes replaced)
|
||||||
let fn_sig = cx.typeck_results().liberated_fn_sigs()[id];
|
let fn_sig = typeck_results.liberated_fn_sigs()[id];
|
||||||
let fn_def_id = tcx.hir().local_def_id(id);
|
let fn_def_id = tcx.hir().local_def_id(id);
|
||||||
|
|
||||||
let safety = match fn_sig.unsafety {
|
let safety = match fn_sig.unsafety {
|
||||||
|
@ -103,6 +105,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = tcx.hir().body(body_id);
|
let body = tcx.hir().body(body_id);
|
||||||
|
let thir = build_thir(tcx, def, &arena, &body.value);
|
||||||
let ty = tcx.type_of(fn_def_id);
|
let ty = tcx.type_of(fn_def_id);
|
||||||
let mut abi = fn_sig.abi;
|
let mut abi = fn_sig.abi;
|
||||||
let implicit_argument = match ty.kind() {
|
let implicit_argument = match ty.kind() {
|
||||||
|
@ -178,7 +181,8 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut mir = build::construct_fn(
|
let mut mir = build::construct_fn(
|
||||||
cx,
|
&infcx,
|
||||||
|
def,
|
||||||
id,
|
id,
|
||||||
arguments,
|
arguments,
|
||||||
safety,
|
safety,
|
||||||
|
@ -186,6 +190,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
return_ty,
|
return_ty,
|
||||||
return_ty_span,
|
return_ty_span,
|
||||||
body,
|
body,
|
||||||
|
thir,
|
||||||
span_with_body,
|
span_with_body,
|
||||||
);
|
);
|
||||||
if yield_ty.is_some() {
|
if yield_ty.is_some() {
|
||||||
|
@ -205,9 +210,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
// place to be the type of the constant because NLL typeck will
|
// place to be the type of the constant because NLL typeck will
|
||||||
// equate them.
|
// equate them.
|
||||||
|
|
||||||
let return_ty = cx.typeck_results().node_type(id);
|
let return_ty = typeck_results.node_type(id);
|
||||||
|
|
||||||
build::construct_const(cx, body_id, return_ty, return_ty_span)
|
let ast_expr = &tcx.hir().body(body_id).value;
|
||||||
|
let thir = build_thir(tcx, def, &arena, ast_expr);
|
||||||
|
|
||||||
|
build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span)
|
||||||
};
|
};
|
||||||
|
|
||||||
lints::check(tcx, &body);
|
lints::check(tcx, &body);
|
||||||
|
@ -304,10 +312,17 @@ impl BlockFrame {
|
||||||
struct BlockContext(Vec<BlockFrame>);
|
struct BlockContext(Vec<BlockFrame>);
|
||||||
|
|
||||||
struct Builder<'a, 'tcx> {
|
struct Builder<'a, 'tcx> {
|
||||||
hir: Cx<'a, 'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
|
region_scope_tree: &'tcx region::ScopeTree,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
cfg: CFG<'tcx>,
|
cfg: CFG<'tcx>,
|
||||||
|
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
hir_id: hir::HirId,
|
||||||
|
check_overflow: bool,
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
generator_kind: Option<GeneratorKind>,
|
generator_kind: Option<GeneratorKind>,
|
||||||
|
@ -607,8 +622,9 @@ struct ArgInfo<'tcx>(
|
||||||
Option<ImplicitSelfKind>,
|
Option<ImplicitSelfKind>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn construct_fn<'a, 'tcx, A>(
|
fn construct_fn<'tcx, A>(
|
||||||
hir: Cx<'a, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
fn_def: ty::WithOptConstParam<LocalDefId>,
|
||||||
fn_id: hir::HirId,
|
fn_id: hir::HirId,
|
||||||
arguments: A,
|
arguments: A,
|
||||||
safety: Safety,
|
safety: Safety,
|
||||||
|
@ -616,6 +632,7 @@ fn construct_fn<'a, 'tcx, A>(
|
||||||
return_ty: Ty<'tcx>,
|
return_ty: Ty<'tcx>,
|
||||||
return_ty_span: Span,
|
return_ty_span: Span,
|
||||||
body: &'tcx hir::Body<'tcx>,
|
body: &'tcx hir::Body<'tcx>,
|
||||||
|
expr: &Expr<'_, 'tcx>,
|
||||||
span_with_body: Span,
|
span_with_body: Span,
|
||||||
) -> Body<'tcx>
|
) -> Body<'tcx>
|
||||||
where
|
where
|
||||||
|
@ -623,15 +640,13 @@ where
|
||||||
{
|
{
|
||||||
let arguments: Vec<_> = arguments.collect();
|
let arguments: Vec<_> = arguments.collect();
|
||||||
|
|
||||||
let tcx = hir.tcx();
|
let tcx = infcx.tcx;
|
||||||
let tcx_hir = tcx.hir();
|
let span = tcx.hir().span(fn_id);
|
||||||
let span = tcx_hir.span(fn_id);
|
|
||||||
|
|
||||||
let fn_def_id = tcx_hir.local_def_id(fn_id);
|
|
||||||
|
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
hir,
|
infcx,
|
||||||
fn_def_id.to_def_id(),
|
fn_def,
|
||||||
|
fn_id,
|
||||||
span_with_body,
|
span_with_body,
|
||||||
arguments.len(),
|
arguments.len(),
|
||||||
safety,
|
safety,
|
||||||
|
@ -655,16 +670,16 @@ where
|
||||||
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
builder.args_and_body(
|
builder.args_and_body(
|
||||||
START_BLOCK,
|
START_BLOCK,
|
||||||
fn_def_id.to_def_id(),
|
fn_def.did.to_def_id(),
|
||||||
&arguments,
|
&arguments,
|
||||||
arg_scope,
|
arg_scope,
|
||||||
&body.value,
|
expr,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
let source_info = builder.source_info(fn_end);
|
let source_info = builder.source_info(fn_end);
|
||||||
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
|
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
|
||||||
let should_abort = should_abort_on_panic(tcx, fn_def_id, abi);
|
let should_abort = should_abort_on_panic(tcx, fn_def.did, abi);
|
||||||
builder.build_drop_trees(should_abort);
|
builder.build_drop_trees(should_abort);
|
||||||
return_block.unit()
|
return_block.unit()
|
||||||
}));
|
}));
|
||||||
|
@ -675,7 +690,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
debug!("fn_id {:?} has attrs {:?}", fn_def_id, tcx.get_attrs(fn_def_id.to_def_id()));
|
debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id()));
|
||||||
|
|
||||||
let mut body = builder.finish();
|
let mut body = builder.finish();
|
||||||
body.spread_arg = spread_arg;
|
body.spread_arg = spread_arg;
|
||||||
|
@ -683,22 +698,20 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_const<'a, 'tcx>(
|
fn construct_const<'a, 'tcx>(
|
||||||
hir: Cx<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
body_id: hir::BodyId,
|
expr: &Expr<'_, 'tcx>,
|
||||||
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
|
hir_id: hir::HirId,
|
||||||
const_ty: Ty<'tcx>,
|
const_ty: Ty<'tcx>,
|
||||||
const_ty_span: Span,
|
const_ty_span: Span,
|
||||||
) -> Body<'tcx> {
|
) -> Body<'tcx> {
|
||||||
let tcx = hir.tcx();
|
let tcx = infcx.tcx;
|
||||||
let owner_id = tcx.hir().body_owner(body_id);
|
let span = tcx.hir().span(hir_id);
|
||||||
let def_id = tcx.hir().local_def_id(owner_id);
|
|
||||||
let span = tcx.hir().span(owner_id);
|
|
||||||
let mut builder =
|
let mut builder =
|
||||||
Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None);
|
Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None);
|
||||||
|
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
let ast_expr = &tcx.hir().body(body_id).value;
|
unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr));
|
||||||
let expr = builder.hir.mirror(ast_expr);
|
|
||||||
unpack!(block = builder.into_expr(Place::return_place(), block, expr));
|
|
||||||
|
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||||
|
@ -712,15 +725,19 @@ fn construct_const<'a, 'tcx>(
|
||||||
///
|
///
|
||||||
/// This is required because we may still want to run MIR passes on an item
|
/// This is required because we may still want to run MIR passes on an item
|
||||||
/// with type errors, but normal MIR construction can't handle that in general.
|
/// with type errors, but normal MIR construction can't handle that in general.
|
||||||
fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> {
|
fn construct_error<'a, 'tcx>(
|
||||||
let tcx = hir.tcx();
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
let owner_id = tcx.hir().body_owner(body_id);
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
let def_id = tcx.hir().local_def_id(owner_id);
|
hir_id: hir::HirId,
|
||||||
let span = tcx.hir().span(owner_id);
|
body_id: hir::BodyId,
|
||||||
|
body_owner_kind: hir::BodyOwnerKind,
|
||||||
|
) -> Body<'tcx> {
|
||||||
|
let tcx = infcx.tcx;
|
||||||
|
let span = tcx.hir().span(hir_id);
|
||||||
let ty = tcx.ty_error();
|
let ty = tcx.ty_error();
|
||||||
let generator_kind = tcx.hir().body(body_id).generator_kind;
|
let generator_kind = tcx.hir().body(body_id).generator_kind;
|
||||||
let num_params = match hir.body_owner_kind {
|
let num_params = match body_owner_kind {
|
||||||
hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(),
|
hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len(),
|
||||||
hir::BodyOwnerKind::Closure => {
|
hir::BodyOwnerKind::Closure => {
|
||||||
if generator_kind.is_some() {
|
if generator_kind.is_some() {
|
||||||
// Generators have an implicit `self` parameter *and* a possibly
|
// Generators have an implicit `self` parameter *and* a possibly
|
||||||
|
@ -728,22 +745,14 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t
|
||||||
2
|
2
|
||||||
} else {
|
} else {
|
||||||
// The implicit self parameter adds another local in MIR.
|
// The implicit self parameter adds another local in MIR.
|
||||||
1 + tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len()
|
1 + tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::BodyOwnerKind::Const => 0,
|
hir::BodyOwnerKind::Const => 0,
|
||||||
hir::BodyOwnerKind::Static(_) => 0,
|
hir::BodyOwnerKind::Static(_) => 0,
|
||||||
};
|
};
|
||||||
let mut builder = Builder::new(
|
let mut builder =
|
||||||
hir,
|
Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind);
|
||||||
def_id.to_def_id(),
|
|
||||||
span,
|
|
||||||
num_params,
|
|
||||||
Safety::Safe,
|
|
||||||
ty,
|
|
||||||
span,
|
|
||||||
generator_kind,
|
|
||||||
);
|
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
// Some MIR passes will expect the number of parameters to match the
|
// Some MIR passes will expect the number of parameters to match the
|
||||||
// function declaration.
|
// function declaration.
|
||||||
|
@ -758,8 +767,9 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn new(
|
fn new(
|
||||||
hir: Cx<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
def_id: DefId,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
|
hir_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
safety: Safety,
|
safety: Safety,
|
||||||
|
@ -767,10 +777,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
return_span: Span,
|
return_span: Span,
|
||||||
generator_kind: Option<GeneratorKind>,
|
generator_kind: Option<GeneratorKind>,
|
||||||
) -> Builder<'a, 'tcx> {
|
) -> Builder<'a, 'tcx> {
|
||||||
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
let tcx = infcx.tcx;
|
||||||
|
let attrs = tcx.hir().attrs(hir_id);
|
||||||
|
// Some functions always have overflow checks enabled,
|
||||||
|
// however, they may not get codegen'd, depending on
|
||||||
|
// the settings for the crate they are codegened in.
|
||||||
|
let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
|
||||||
|
// Respect -C overflow-checks.
|
||||||
|
check_overflow |= tcx.sess.overflow_checks();
|
||||||
|
// Constants always need overflow checks.
|
||||||
|
check_overflow |= matches!(
|
||||||
|
tcx.hir().body_owner_kind(hir_id),
|
||||||
|
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
|
||||||
|
);
|
||||||
|
|
||||||
|
let lint_level = LintLevel::Explicit(hir_id);
|
||||||
let mut builder = Builder {
|
let mut builder = Builder {
|
||||||
hir,
|
tcx,
|
||||||
def_id,
|
infcx,
|
||||||
|
typeck_results: tcx.typeck_opt_const_arg(def),
|
||||||
|
region_scope_tree: tcx.region_scope_tree(def.did),
|
||||||
|
param_env: tcx.param_env(def.did),
|
||||||
|
def_id: def.did.to_def_id(),
|
||||||
|
hir_id,
|
||||||
|
check_overflow,
|
||||||
cfg: CFG { basic_blocks: IndexVec::new() },
|
cfg: CFG { basic_blocks: IndexVec::new() },
|
||||||
fn_span: span,
|
fn_span: span,
|
||||||
arg_count,
|
arg_count,
|
||||||
|
@ -826,7 +856,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn_def_id: DefId,
|
fn_def_id: DefId,
|
||||||
arguments: &[ArgInfo<'tcx>],
|
arguments: &[ArgInfo<'tcx>],
|
||||||
argument_scope: region::Scope,
|
argument_scope: region::Scope,
|
||||||
ast_body: &'tcx hir::Expr<'tcx>,
|
expr: &Expr<'_, 'tcx>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
// Allocate locals for the function arguments
|
// Allocate locals for the function arguments
|
||||||
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
||||||
|
@ -846,9 +876,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let tcx_hir = tcx.hir();
|
let tcx_hir = tcx.hir();
|
||||||
let hir_typeck_results = self.hir.typeck_results();
|
let hir_typeck_results = self.typeck_results;
|
||||||
|
|
||||||
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
|
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
|
||||||
// indexed closure and we stored in a map called closure_captures in TypeckResults
|
// indexed closure and we stored in a map called closure_captures in TypeckResults
|
||||||
|
@ -924,14 +954,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// Make sure we drop (parts of) the argument even when not matched on.
|
// Make sure we drop (parts of) the argument even when not matched on.
|
||||||
self.schedule_drop(
|
self.schedule_drop(
|
||||||
arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
|
arg_opt.as_ref().map_or(expr.span, |arg| arg.pat.span),
|
||||||
argument_scope,
|
argument_scope,
|
||||||
local,
|
local,
|
||||||
DropKind::Value,
|
DropKind::Value,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(arg) = arg_opt {
|
if let Some(arg) = arg_opt {
|
||||||
let pattern = self.hir.pattern_from_hir(&arg.pat);
|
let pat = match tcx.hir().get(arg.pat.hir_id) {
|
||||||
|
Node::Pat(pat) | Node::Binding(pat) => pat,
|
||||||
|
node => bug!("pattern became {:?}", node),
|
||||||
|
};
|
||||||
|
let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat);
|
||||||
let original_source_scope = self.source_scope;
|
let original_source_scope = self.source_scope;
|
||||||
let span = pattern.span;
|
let span = pattern.span;
|
||||||
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
|
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
|
||||||
|
@ -966,7 +1000,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
scope = self.declare_bindings(
|
scope = self.declare_bindings(
|
||||||
scope,
|
scope,
|
||||||
ast_body.span,
|
expr.span,
|
||||||
&pattern,
|
&pattern,
|
||||||
matches::ArmHasGuard(false),
|
matches::ArmHasGuard(false),
|
||||||
Some((Some(&place), span)),
|
Some((Some(&place), span)),
|
||||||
|
@ -983,8 +1017,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.source_scope = source_scope;
|
self.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = self.hir.mirror(ast_body);
|
self.expr_into_dest(Place::return_place(), block, &expr)
|
||||||
self.into(Place::return_place(), block, body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_correct_source_scope_for_arg(
|
fn set_correct_source_scope_for_arg(
|
||||||
|
@ -993,15 +1026,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
original_source_scope: SourceScope,
|
original_source_scope: SourceScope,
|
||||||
pattern_span: Span,
|
pattern_span: Span,
|
||||||
) {
|
) {
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir.root_lint_level);
|
let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id);
|
||||||
let parent_root = tcx.maybe_lint_level_root_bounded(
|
let parent_root = tcx.maybe_lint_level_root_bounded(
|
||||||
self.source_scopes[original_source_scope]
|
self.source_scopes[original_source_scope]
|
||||||
.local_data
|
.local_data
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.assert_crate_local()
|
.assert_crate_local()
|
||||||
.lint_root,
|
.lint_root,
|
||||||
self.hir.root_lint_level,
|
self.hir_id,
|
||||||
);
|
);
|
||||||
if current_root != parent_root {
|
if current_root != parent_root {
|
||||||
self.source_scope =
|
self.source_scope =
|
||||||
|
@ -1013,7 +1046,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
match self.unit_temp {
|
match self.unit_temp {
|
||||||
Some(tmp) => tmp,
|
Some(tmp) => tmp,
|
||||||
None => {
|
None => {
|
||||||
let ty = self.hir.unit_ty();
|
let ty = self.tcx.mk_unit();
|
||||||
let fn_span = self.fn_span;
|
let fn_span = self.fn_span;
|
||||||
let tmp = self.temp(ty, fn_span);
|
let tmp = self.temp(ty, fn_span);
|
||||||
self.unit_temp = Some(tmp);
|
self.unit_temp = Some(tmp);
|
||||||
|
@ -1031,7 +1064,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
mod block;
|
mod block;
|
||||||
mod cfg;
|
mod cfg;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod into;
|
|
||||||
mod matches;
|
mod matches;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod scope;
|
mod scope;
|
||||||
|
|
|
@ -82,7 +82,7 @@ that contains only loops and breakable blocks. It tracks where a `break`,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
|
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
|
||||||
use crate::thir::{Expr, ExprRef, LintLevel};
|
use crate::thir::{Expr, LintLevel};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
|
@ -516,7 +516,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
debug!("in_scope(region_scope={:?})", region_scope);
|
debug!("in_scope(region_scope={:?})", region_scope);
|
||||||
let source_scope = self.source_scope;
|
let source_scope = self.source_scope;
|
||||||
let tcx = self.hir.tcx();
|
let tcx = self.tcx;
|
||||||
if let LintLevel::Explicit(current_hir_id) = lint_level {
|
if let LintLevel::Explicit(current_hir_id) = lint_level {
|
||||||
// Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
|
// Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
|
||||||
// to avoid adding Hir dependences on our parents.
|
// to avoid adding Hir dependences on our parents.
|
||||||
|
@ -524,10 +524,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
let parent_root = tcx.maybe_lint_level_root_bounded(
|
let parent_root = tcx.maybe_lint_level_root_bounded(
|
||||||
self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
|
self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
|
||||||
self.hir.root_lint_level,
|
self.hir_id,
|
||||||
);
|
);
|
||||||
let current_root =
|
let current_root = tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir_id);
|
||||||
tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level);
|
|
||||||
|
|
||||||
if parent_root != current_root {
|
if parent_root != current_root {
|
||||||
self.source_scope = self.new_source_scope(
|
self.source_scope = self.new_source_scope(
|
||||||
|
@ -575,7 +574,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
crate fn break_scope(
|
crate fn break_scope(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
value: Option<ExprRef<'tcx>>,
|
value: Option<&Expr<'_, 'tcx>>,
|
||||||
target: BreakableTarget,
|
target: BreakableTarget,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
|
@ -612,10 +611,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
debug!("stmt_expr Break val block_context.push(SubExpr)");
|
debug!("stmt_expr Break val block_context.push(SubExpr)");
|
||||||
self.block_context.push(BlockFrame::SubExpr);
|
self.block_context.push(BlockFrame::SubExpr);
|
||||||
unpack!(block = self.into(destination, block, value));
|
unpack!(block = self.expr_into_dest(destination, block, value));
|
||||||
self.block_context.pop();
|
self.block_context.pop();
|
||||||
} else {
|
} else {
|
||||||
self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
|
self.cfg.push_assign_unit(block, source_info, destination, self.tcx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert!(value.is_none(), "`return` and `break` should have a destination");
|
assert!(value.is_none(), "`return` and `break` should have a destination");
|
||||||
|
@ -763,7 +762,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
) {
|
) {
|
||||||
let needs_drop = match drop_kind {
|
let needs_drop = match drop_kind {
|
||||||
DropKind::Value => {
|
DropKind::Value => {
|
||||||
if !self.hir.needs_drop(self.local_decls[local].ty) {
|
if !self.local_decls[local].ty.needs_drop(self.tcx, self.param_env) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -834,10 +833,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if scope.region_scope == region_scope {
|
if scope.region_scope == region_scope {
|
||||||
let region_scope_span =
|
let region_scope_span = region_scope.span(self.tcx, &self.region_scope_tree);
|
||||||
region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
|
|
||||||
// Attribute scope exit drops to scope's closing brace.
|
// Attribute scope exit drops to scope's closing brace.
|
||||||
let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
|
let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
|
||||||
|
|
||||||
scope.drops.push(DropData {
|
scope.drops.push(DropData {
|
||||||
source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
|
source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
|
||||||
|
@ -920,13 +918,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
crate fn test_bool(
|
crate fn test_bool(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
condition: Expr<'tcx>,
|
condition: &Expr<'_, 'tcx>,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> (BasicBlock, BasicBlock) {
|
) -> (BasicBlock, BasicBlock) {
|
||||||
let cond = unpack!(block = self.as_local_operand(block, condition));
|
let cond = unpack!(block = self.as_local_operand(block, condition));
|
||||||
let true_block = self.cfg.start_new_block();
|
let true_block = self.cfg.start_new_block();
|
||||||
let false_block = self.cfg.start_new_block();
|
let false_block = self.cfg.start_new_block();
|
||||||
let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block);
|
let term = TerminatorKind::if_(self.tcx, cond.clone(), true_block, false_block);
|
||||||
self.cfg.terminate(block, source_info, term);
|
self.cfg.terminate(block, source_info, term);
|
||||||
|
|
||||||
match cond {
|
match cond {
|
||||||
|
|
98
compiler/rustc_mir_build/src/thir/arena.rs
Normal file
98
compiler/rustc_mir_build/src/thir/arena.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
use crate::thir::*;
|
||||||
|
|
||||||
|
macro_rules! declare_arena {
|
||||||
|
([], [$($a:tt $name:ident: $ty:ty,)*]) => {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Arena<'thir, 'tcx> {
|
||||||
|
pub dropless: rustc_arena::DroplessArena,
|
||||||
|
drop: rustc_arena::DropArena,
|
||||||
|
$($name: rustc_arena::arena_for_type!($a[$ty]),)*
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ArenaAllocatable<'thir, 'tcx, T = Self>: Sized {
|
||||||
|
fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self;
|
||||||
|
fn allocate_from_iter(
|
||||||
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
|
iter: impl ::std::iter::IntoIterator<Item = Self>,
|
||||||
|
) -> &'thir mut [Self];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'thir, 'tcx, T: Copy> ArenaAllocatable<'thir, 'tcx, ()> for T {
|
||||||
|
#[inline]
|
||||||
|
fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
|
||||||
|
arena.dropless.alloc(self)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn allocate_from_iter(
|
||||||
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
|
iter: impl ::std::iter::IntoIterator<Item = Self>,
|
||||||
|
) -> &'thir mut [Self] {
|
||||||
|
arena.dropless.alloc_from_iter(iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
impl<'thir, 'tcx> ArenaAllocatable<'thir, 'tcx, $ty> for $ty {
|
||||||
|
#[inline]
|
||||||
|
fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
|
||||||
|
if !::std::mem::needs_drop::<Self>() {
|
||||||
|
return arena.dropless.alloc(self);
|
||||||
|
}
|
||||||
|
match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
|
||||||
|
::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
|
||||||
|
ty_arena.alloc(self)
|
||||||
|
}
|
||||||
|
::std::option::Option::None => unsafe { arena.drop.alloc(self) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn allocate_from_iter(
|
||||||
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
|
iter: impl ::std::iter::IntoIterator<Item = Self>,
|
||||||
|
) -> &'thir mut [Self] {
|
||||||
|
if !::std::mem::needs_drop::<Self>() {
|
||||||
|
return arena.dropless.alloc_from_iter(iter);
|
||||||
|
}
|
||||||
|
match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
|
||||||
|
::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
|
||||||
|
ty_arena.alloc_from_iter(iter)
|
||||||
|
}
|
||||||
|
::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
impl<'thir, 'tcx> Arena<'thir, 'tcx> {
|
||||||
|
#[inline]
|
||||||
|
pub fn alloc<T: ArenaAllocatable<'thir, 'tcx, U>, U>(&'thir self, value: T) -> &'thir mut T {
|
||||||
|
value.allocate_on(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // function is never used
|
||||||
|
#[inline]
|
||||||
|
pub fn alloc_slice<T: ::std::marker::Copy>(&'thir self, value: &[T]) -> &'thir mut [T] {
|
||||||
|
if value.is_empty() {
|
||||||
|
return &mut [];
|
||||||
|
}
|
||||||
|
self.dropless.alloc_slice(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_from_iter<T: ArenaAllocatable<'thir, 'tcx, U>, U>(
|
||||||
|
&'thir self,
|
||||||
|
iter: impl ::std::iter::IntoIterator<Item = T>,
|
||||||
|
) -> &'thir mut [T] {
|
||||||
|
T::allocate_from_iter(self, iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_arena!([], [
|
||||||
|
[] arm: Arm<'thir, 'tcx>,
|
||||||
|
[] expr: Expr<'thir, 'tcx>,
|
||||||
|
[] field_expr: FieldExpr<'thir, 'tcx>,
|
||||||
|
[few] inline_asm_operand: InlineAsmOperand<'thir, 'tcx>,
|
||||||
|
[] stmt: Stmt<'thir, 'tcx>,
|
||||||
|
]);
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::thir::cx::to_ref::ToRef;
|
|
||||||
use crate::thir::cx::Cx;
|
use crate::thir::cx::Cx;
|
||||||
use crate::thir::{self, *};
|
use crate::thir::{self, *};
|
||||||
|
|
||||||
|
@ -8,53 +7,51 @@ use rustc_middle::ty;
|
||||||
|
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Block<'tcx> {
|
impl<'thir, 'tcx> Cx<'thir, 'tcx> {
|
||||||
type Output = Block<'tcx>;
|
crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, 'tcx> {
|
||||||
|
|
||||||
fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
|
|
||||||
// We have to eagerly lower the "spine" of the statements
|
// We have to eagerly lower the "spine" of the statements
|
||||||
// in order to get the lexical scoping correctly.
|
// in order to get the lexical scoping correctly.
|
||||||
let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts);
|
let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
|
||||||
let opt_destruction_scope =
|
let opt_destruction_scope =
|
||||||
cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id);
|
self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
|
||||||
Block {
|
Block {
|
||||||
targeted_by_break: self.targeted_by_break,
|
targeted_by_break: block.targeted_by_break,
|
||||||
region_scope: region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node },
|
region_scope: region::Scope {
|
||||||
|
id: block.hir_id.local_id,
|
||||||
|
data: region::ScopeData::Node,
|
||||||
|
},
|
||||||
opt_destruction_scope,
|
opt_destruction_scope,
|
||||||
span: self.span,
|
span: block.span,
|
||||||
stmts,
|
stmts,
|
||||||
expr: self.expr.to_ref(),
|
expr: block.expr.map(|expr| self.mirror_expr(expr)),
|
||||||
safety_mode: match self.rules {
|
safety_mode: match block.rules {
|
||||||
hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
|
hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
|
||||||
hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(self.hir_id),
|
hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(block.hir_id),
|
||||||
hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
|
hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
|
||||||
hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
|
hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn mirror_stmts<'a, 'tcx>(
|
fn mirror_stmts(
|
||||||
cx: &mut Cx<'a, 'tcx>,
|
&mut self,
|
||||||
block_id: hir::ItemLocalId,
|
block_id: hir::ItemLocalId,
|
||||||
stmts: &'tcx [hir::Stmt<'tcx>],
|
stmts: &'tcx [hir::Stmt<'tcx>],
|
||||||
) -> Vec<StmtRef<'tcx>> {
|
) -> &'thir [Stmt<'thir, 'tcx>] {
|
||||||
let mut result = vec![];
|
self.arena.alloc_from_iter(stmts.iter().enumerate().filter_map(|(index, stmt)| {
|
||||||
for (index, stmt) in stmts.iter().enumerate() {
|
|
||||||
let hir_id = stmt.hir_id;
|
let hir_id = stmt.hir_id;
|
||||||
let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
|
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => Some(Stmt {
|
||||||
result.push(StmtRef::Mirror(Box::new(Stmt {
|
|
||||||
kind: StmtKind::Expr {
|
kind: StmtKind::Expr {
|
||||||
scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
|
scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
|
||||||
expr: expr.to_ref(),
|
expr: self.mirror_expr(expr),
|
||||||
},
|
},
|
||||||
opt_destruction_scope: opt_dxn_ext,
|
opt_destruction_scope: opt_dxn_ext,
|
||||||
})))
|
}),
|
||||||
}
|
|
||||||
hir::StmtKind::Item(..) => {
|
hir::StmtKind::Item(..) => {
|
||||||
// ignore for purposes of the MIR
|
// ignore for purposes of the MIR
|
||||||
|
None
|
||||||
}
|
}
|
||||||
hir::StmtKind::Local(ref local) => {
|
hir::StmtKind::Local(ref local) => {
|
||||||
let remainder_scope = region::Scope {
|
let remainder_scope = region::Scope {
|
||||||
|
@ -62,10 +59,12 @@ fn mirror_stmts<'a, 'tcx>(
|
||||||
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
|
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pattern = cx.pattern_from_hir(&local.pat);
|
let mut pattern = self.pattern_from_hir(local.pat);
|
||||||
|
|
||||||
if let Some(ty) = &local.ty {
|
if let Some(ty) = &local.ty {
|
||||||
if let Some(&user_ty) = cx.typeck_results.user_provided_types().get(ty.hir_id) {
|
if let Some(&user_ty) =
|
||||||
|
self.typeck_results.user_provided_types().get(ty.hir_id)
|
||||||
|
{
|
||||||
debug!("mirror_stmts: user_ty={:?}", user_ty);
|
debug!("mirror_stmts: user_ty={:?}", user_ty);
|
||||||
pattern = Pat {
|
pattern = Pat {
|
||||||
ty: pattern.ty,
|
ty: pattern.ty,
|
||||||
|
@ -82,7 +81,7 @@ fn mirror_stmts<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push(StmtRef::Mirror(Box::new(Stmt {
|
Some(Stmt {
|
||||||
kind: StmtKind::Let {
|
kind: StmtKind::Let {
|
||||||
remainder_scope,
|
remainder_scope,
|
||||||
init_scope: region::Scope {
|
init_scope: region::Scope {
|
||||||
|
@ -90,28 +89,13 @@ fn mirror_stmts<'a, 'tcx>(
|
||||||
data: region::ScopeData::Node,
|
data: region::ScopeData::Node,
|
||||||
},
|
},
|
||||||
pattern,
|
pattern,
|
||||||
initializer: local.init.to_ref(),
|
initializer: local.init.map(|init| self.mirror_expr(init)),
|
||||||
lint_level: LintLevel::Explicit(local.hir_id),
|
lint_level: LintLevel::Explicit(local.hir_id),
|
||||||
},
|
},
|
||||||
opt_destruction_scope: opt_dxn_ext,
|
opt_destruction_scope: opt_dxn_ext,
|
||||||
})));
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn to_expr_ref<'a, 'tcx>(
|
|
||||||
cx: &mut Cx<'a, 'tcx>,
|
|
||||||
block: &'tcx hir::Block<'tcx>,
|
|
||||||
) -> ExprRef<'tcx> {
|
|
||||||
let block_ty = cx.typeck_results().node_type(block.hir_id);
|
|
||||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
|
|
||||||
let expr = Expr {
|
|
||||||
ty: block_ty,
|
|
||||||
temp_lifetime,
|
|
||||||
span: block.span,
|
|
||||||
kind: ExprKind::Block { body: block },
|
|
||||||
};
|
|
||||||
expr.to_ref()
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@
|
||||||
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
|
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
|
||||||
//! etc., and instead goes through the `Cx` for most of its work.
|
//! etc., and instead goes through the `Cx` for most of its work.
|
||||||
|
|
||||||
|
use crate::thir::arena::Arena;
|
||||||
use crate::thir::util::UserAnnotatedTyHelpers;
|
use crate::thir::util::UserAnnotatedTyHelpers;
|
||||||
use crate::thir::*;
|
use crate::thir::*;
|
||||||
|
|
||||||
|
@ -9,118 +10,48 @@ use rustc_ast as ast;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc_index::vec::Idx;
|
|
||||||
use rustc_infer::infer::InferCtxt;
|
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
|
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
|
||||||
use rustc_middle::ty::subst::Subst;
|
|
||||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
|
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
|
||||||
use rustc_target::abi::VariantIdx;
|
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
crate fn build_thir<'thir, 'tcx>(
|
||||||
crate struct Cx<'a, 'tcx> {
|
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
owner_def: ty::WithOptConstParam<LocalDefId>,
|
||||||
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
) -> &'thir Expr<'thir, 'tcx> {
|
||||||
|
Cx::new(tcx, owner_def, &arena).mirror_expr(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cx<'thir, 'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
|
|
||||||
crate root_lint_level: hir::HirId,
|
|
||||||
crate param_env: ty::ParamEnv<'tcx>,
|
crate param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
/// Identity `InternalSubsts` for use with const-evaluation.
|
|
||||||
crate identity_substs: &'tcx InternalSubsts<'tcx>,
|
|
||||||
|
|
||||||
crate region_scope_tree: &'tcx region::ScopeTree,
|
crate region_scope_tree: &'tcx region::ScopeTree,
|
||||||
crate typeck_results: &'a ty::TypeckResults<'tcx>,
|
crate typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||||
|
|
||||||
/// This is `Constness::Const` if we are compiling a `static`,
|
|
||||||
/// `const`, or the body of a `const fn`.
|
|
||||||
constness: hir::Constness,
|
|
||||||
|
|
||||||
/// The `DefId` of the owner of this body.
|
/// The `DefId` of the owner of this body.
|
||||||
body_owner: DefId,
|
body_owner: DefId,
|
||||||
|
|
||||||
/// What kind of body is being compiled.
|
|
||||||
crate body_owner_kind: hir::BodyOwnerKind,
|
|
||||||
|
|
||||||
/// Whether this constant/function needs overflow checks.
|
|
||||||
check_overflow: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Cx<'a, 'tcx> {
|
impl<'thir, 'tcx> Cx<'thir, 'tcx> {
|
||||||
crate fn new(
|
fn new(
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
src_id: hir::HirId,
|
arena: &'thir Arena<'thir, 'tcx>,
|
||||||
) -> Cx<'a, 'tcx> {
|
) -> Cx<'thir, 'tcx> {
|
||||||
let tcx = infcx.tcx;
|
|
||||||
let typeck_results = tcx.typeck_opt_const_arg(def);
|
let typeck_results = tcx.typeck_opt_const_arg(def);
|
||||||
let body_owner_kind = tcx.hir().body_owner_kind(src_id);
|
|
||||||
|
|
||||||
let constness = match body_owner_kind {
|
|
||||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
|
|
||||||
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
|
|
||||||
};
|
|
||||||
|
|
||||||
let attrs = tcx.hir().attrs(src_id);
|
|
||||||
|
|
||||||
// Some functions always have overflow checks enabled,
|
|
||||||
// however, they may not get codegen'd, depending on
|
|
||||||
// the settings for the crate they are codegened in.
|
|
||||||
let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
|
|
||||||
|
|
||||||
// Respect -C overflow-checks.
|
|
||||||
check_overflow |= tcx.sess.overflow_checks();
|
|
||||||
|
|
||||||
// Constants always need overflow checks.
|
|
||||||
check_overflow |= constness == hir::Constness::Const;
|
|
||||||
|
|
||||||
Cx {
|
Cx {
|
||||||
tcx,
|
tcx,
|
||||||
infcx,
|
arena,
|
||||||
root_lint_level: src_id,
|
|
||||||
param_env: tcx.param_env(def.did),
|
param_env: tcx.param_env(def.did),
|
||||||
identity_substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
|
|
||||||
region_scope_tree: tcx.region_scope_tree(def.did),
|
region_scope_tree: tcx.region_scope_tree(def.did),
|
||||||
typeck_results,
|
typeck_results,
|
||||||
constness,
|
|
||||||
body_owner: def.did.to_def_id(),
|
body_owner: def.did.to_def_id(),
|
||||||
body_owner_kind,
|
|
||||||
check_overflow,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Cx<'a, 'tcx> {
|
|
||||||
/// Normalizes `ast` into the appropriate "mirror" type.
|
|
||||||
crate fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
|
|
||||||
ast.make_mirror(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn usize_ty(&mut self) -> Ty<'tcx> {
|
|
||||||
self.tcx.types.usize
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
|
|
||||||
ty::Const::from_usize(self.tcx, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn bool_ty(&mut self) -> Ty<'tcx> {
|
|
||||||
self.tcx.types.bool
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn unit_ty(&mut self) -> Ty<'tcx> {
|
|
||||||
self.tcx.mk_unit()
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
|
|
||||||
ty::Const::from_bool(self.tcx, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
|
|
||||||
ty::Const::from_bool(self.tcx, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn const_eval_literal(
|
crate fn const_eval_literal(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -154,69 +85,17 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
|
Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn trait_method(
|
|
||||||
&mut self,
|
|
||||||
trait_def_id: DefId,
|
|
||||||
method_name: Symbol,
|
|
||||||
self_ty: Ty<'tcx>,
|
|
||||||
params: &[GenericArg<'tcx>],
|
|
||||||
) -> &'tcx ty::Const<'tcx> {
|
|
||||||
let substs = self.tcx.mk_substs_trait(self_ty, params);
|
|
||||||
|
|
||||||
// The unhygienic comparison here is acceptable because this is only
|
|
||||||
// used on known traits.
|
|
||||||
let item = self
|
|
||||||
.tcx
|
|
||||||
.associated_items(trait_def_id)
|
|
||||||
.filter_by_name_unhygienic(method_name)
|
|
||||||
.find(|item| item.kind == ty::AssocKind::Fn)
|
|
||||||
.expect("trait method not found");
|
|
||||||
|
|
||||||
let method_ty = self.tcx.type_of(item.def_id);
|
|
||||||
let method_ty = method_ty.subst(self.tcx, substs);
|
|
||||||
ty::Const::zero_sized(self.tcx, method_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: VariantIdx) -> Vec<Field> {
|
|
||||||
(0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
|
|
||||||
ty.needs_drop(self.tcx, self.param_env)
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
|
|
||||||
self.infcx
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn tcx(&self) -> TyCtxt<'tcx> {
|
|
||||||
self.tcx
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn typeck_results(&self) -> &'a ty::TypeckResults<'tcx> {
|
|
||||||
self.typeck_results
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn check_overflow(&self) -> bool {
|
|
||||||
self.check_overflow
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
|
||||||
self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
|
impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx()
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
|
fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
|
||||||
self.typeck_results()
|
self.typeck_results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod block;
|
mod block;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod to_ref;
|
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
use crate::thir::*;
|
|
||||||
|
|
||||||
use rustc_hir as hir;
|
|
||||||
|
|
||||||
crate trait ToRef {
|
|
||||||
type Output;
|
|
||||||
fn to_ref(self) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ToRef for &'tcx hir::Expr<'tcx> {
|
|
||||||
type Output = ExprRef<'tcx>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> ExprRef<'tcx> {
|
|
||||||
ExprRef::Thir(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ToRef for &'tcx &'tcx hir::Expr<'tcx> {
|
|
||||||
type Output = ExprRef<'tcx>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> ExprRef<'tcx> {
|
|
||||||
ExprRef::Thir(&**self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ToRef for Expr<'tcx> {
|
|
||||||
type Output = ExprRef<'tcx>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> ExprRef<'tcx> {
|
|
||||||
ExprRef::Mirror(Box::new(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, T, U> ToRef for &'tcx Option<T>
|
|
||||||
where
|
|
||||||
&'tcx T: ToRef<Output = U>,
|
|
||||||
{
|
|
||||||
type Output = Option<U>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> Option<U> {
|
|
||||||
self.as_ref().map(|expr| expr.to_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, T, U> ToRef for &'tcx Vec<T>
|
|
||||||
where
|
|
||||||
&'tcx T: ToRef<Output = U>,
|
|
||||||
{
|
|
||||||
type Output = Vec<U>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> Vec<U> {
|
|
||||||
self.iter().map(|expr| expr.to_ref()).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, T, U> ToRef for &'tcx [T]
|
|
||||||
where
|
|
||||||
&'tcx T: ToRef<Output = U>,
|
|
||||||
{
|
|
||||||
type Output = Vec<U>;
|
|
||||||
|
|
||||||
fn to_ref(self) -> Vec<U> {
|
|
||||||
self.iter().map(|expr| expr.to_ref()).collect()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@
|
||||||
//! unit-tested and separated from the Rust source and compiler data
|
//! unit-tested and separated from the Rust source and compiler data
|
||||||
//! structures.
|
//! structures.
|
||||||
|
|
||||||
use self::cx::Cx;
|
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -25,6 +24,9 @@ crate mod pattern;
|
||||||
crate use self::pattern::PatTyProj;
|
crate use self::pattern::PatTyProj;
|
||||||
crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
|
crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
|
||||||
|
|
||||||
|
mod arena;
|
||||||
|
crate use arena::Arena;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -33,14 +35,14 @@ crate enum LintLevel {
|
||||||
Explicit(hir::HirId),
|
Explicit(hir::HirId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate struct Block<'tcx> {
|
crate struct Block<'thir, 'tcx> {
|
||||||
crate targeted_by_break: bool,
|
crate targeted_by_break: bool,
|
||||||
crate region_scope: region::Scope,
|
crate region_scope: region::Scope,
|
||||||
crate opt_destruction_scope: Option<region::Scope>,
|
crate opt_destruction_scope: Option<region::Scope>,
|
||||||
crate span: Span,
|
crate span: Span,
|
||||||
crate stmts: Vec<StmtRef<'tcx>>,
|
crate stmts: &'thir [Stmt<'thir, 'tcx>],
|
||||||
crate expr: Option<ExprRef<'tcx>>,
|
crate expr: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
crate safety_mode: BlockSafety,
|
crate safety_mode: BlockSafety,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,25 +54,20 @@ crate enum BlockSafety {
|
||||||
PopUnsafe,
|
PopUnsafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate enum StmtRef<'tcx> {
|
crate struct Stmt<'thir, 'tcx> {
|
||||||
Mirror(Box<Stmt<'tcx>>),
|
crate kind: StmtKind<'thir, 'tcx>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
crate struct Stmt<'tcx> {
|
|
||||||
crate kind: StmtKind<'tcx>,
|
|
||||||
crate opt_destruction_scope: Option<region::Scope>,
|
crate opt_destruction_scope: Option<region::Scope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate enum StmtKind<'tcx> {
|
crate enum StmtKind<'thir, 'tcx> {
|
||||||
Expr {
|
Expr {
|
||||||
/// scope for this statement; may be used as lifetime of temporaries
|
/// scope for this statement; may be used as lifetime of temporaries
|
||||||
scope: region::Scope,
|
scope: region::Scope,
|
||||||
|
|
||||||
/// expression being evaluated in this statement
|
/// expression being evaluated in this statement
|
||||||
expr: ExprRef<'tcx>,
|
expr: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Let {
|
Let {
|
||||||
|
@ -88,7 +85,7 @@ crate enum StmtKind<'tcx> {
|
||||||
pattern: Pat<'tcx>,
|
pattern: Pat<'tcx>,
|
||||||
|
|
||||||
/// let pat: ty = <INIT> ...
|
/// let pat: ty = <INIT> ...
|
||||||
initializer: Option<ExprRef<'tcx>>,
|
initializer: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
|
|
||||||
/// the lint level for this let-statement
|
/// the lint level for this let-statement
|
||||||
lint_level: LintLevel,
|
lint_level: LintLevel,
|
||||||
|
@ -97,12 +94,12 @@ crate enum StmtKind<'tcx> {
|
||||||
|
|
||||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
rustc_data_structures::static_assert_size!(Expr<'_>, 168);
|
rustc_data_structures::static_assert_size!(Expr<'_, '_>, 144);
|
||||||
|
|
||||||
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
|
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
|
||||||
/// into instances of this `Expr` enum. This lowering can be done
|
/// into instances of this `Expr` enum. This lowering can be done
|
||||||
/// basically as lazily or as eagerly as desired: every recursive
|
/// basically as lazily or as eagerly as desired: every recursive
|
||||||
/// reference to an expression in this enum is an `ExprRef<'tcx>`, which
|
/// reference to an expression in this enum is an `&'thir Expr<'thir, 'tcx>`, which
|
||||||
/// may in turn be another instance of this enum (boxed), or else an
|
/// may in turn be another instance of this enum (boxed), or else an
|
||||||
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
|
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
|
||||||
/// short-lived. They are created by `Thir::to_expr`, analyzed and
|
/// short-lived. They are created by `Thir::to_expr`, analyzed and
|
||||||
|
@ -113,8 +110,8 @@ rustc_data_structures::static_assert_size!(Expr<'_>, 168);
|
||||||
/// MIR simplifications are already done in the impl of `Thir`. For
|
/// MIR simplifications are already done in the impl of `Thir`. For
|
||||||
/// example, method calls and overloaded operators are absent: they are
|
/// example, method calls and overloaded operators are absent: they are
|
||||||
/// expected to be converted into `Expr::Call` instances.
|
/// expected to be converted into `Expr::Call` instances.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate struct Expr<'tcx> {
|
crate struct Expr<'thir, 'tcx> {
|
||||||
/// type of this expression
|
/// type of this expression
|
||||||
crate ty: Ty<'tcx>,
|
crate ty: Ty<'tcx>,
|
||||||
|
|
||||||
|
@ -126,92 +123,92 @@ crate struct Expr<'tcx> {
|
||||||
crate span: Span,
|
crate span: Span,
|
||||||
|
|
||||||
/// kind of expression
|
/// kind of expression
|
||||||
crate kind: ExprKind<'tcx>,
|
crate kind: ExprKind<'thir, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate enum ExprKind<'tcx> {
|
crate enum ExprKind<'thir, 'tcx> {
|
||||||
Scope {
|
Scope {
|
||||||
region_scope: region::Scope,
|
region_scope: region::Scope,
|
||||||
lint_level: LintLevel,
|
lint_level: LintLevel,
|
||||||
value: ExprRef<'tcx>,
|
value: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Box {
|
Box {
|
||||||
value: ExprRef<'tcx>,
|
value: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
If {
|
If {
|
||||||
cond: ExprRef<'tcx>,
|
cond: &'thir Expr<'thir, 'tcx>,
|
||||||
then: ExprRef<'tcx>,
|
then: &'thir Expr<'thir, 'tcx>,
|
||||||
else_opt: Option<ExprRef<'tcx>>,
|
else_opt: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
fun: ExprRef<'tcx>,
|
fun: &'thir Expr<'thir, 'tcx>,
|
||||||
args: Vec<ExprRef<'tcx>>,
|
args: &'thir [Expr<'thir, 'tcx>],
|
||||||
// Whether this is from a call in HIR, rather than from an overloaded
|
/// Whether this is from a call in HIR, rather than from an overloaded
|
||||||
// operator. True for overloaded function call.
|
/// operator. `true` for overloaded function call.
|
||||||
from_hir_call: bool,
|
from_hir_call: bool,
|
||||||
/// This `Span` is the span of the function, without the dot and receiver
|
/// This `Span` is the span of the function, without the dot and receiver
|
||||||
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
|
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
},
|
},
|
||||||
Deref {
|
Deref {
|
||||||
arg: ExprRef<'tcx>,
|
arg: &'thir Expr<'thir, 'tcx>,
|
||||||
}, // NOT overloaded!
|
}, // NOT overloaded!
|
||||||
Binary {
|
Binary {
|
||||||
op: BinOp,
|
op: BinOp,
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
rhs: ExprRef<'tcx>,
|
rhs: &'thir Expr<'thir, 'tcx>,
|
||||||
}, // NOT overloaded!
|
}, // NOT overloaded!
|
||||||
LogicalOp {
|
LogicalOp {
|
||||||
op: LogicalOp,
|
op: LogicalOp,
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
rhs: ExprRef<'tcx>,
|
rhs: &'thir Expr<'thir, 'tcx>,
|
||||||
}, // NOT overloaded!
|
}, // NOT overloaded!
|
||||||
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
|
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
|
||||||
Unary {
|
Unary {
|
||||||
op: UnOp,
|
op: UnOp,
|
||||||
arg: ExprRef<'tcx>,
|
arg: &'thir Expr<'thir, 'tcx>,
|
||||||
}, // NOT overloaded!
|
}, // NOT overloaded!
|
||||||
Cast {
|
Cast {
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Use {
|
Use {
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
}, // Use a lexpr to get a vexpr.
|
}, // Use a lexpr to get a vexpr.
|
||||||
NeverToAny {
|
NeverToAny {
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Pointer {
|
Pointer {
|
||||||
cast: PointerCast,
|
cast: PointerCast,
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
body: ExprRef<'tcx>,
|
body: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Match {
|
Match {
|
||||||
scrutinee: ExprRef<'tcx>,
|
scrutinee: &'thir Expr<'thir, 'tcx>,
|
||||||
arms: Vec<Arm<'tcx>>,
|
arms: &'thir [Arm<'thir, 'tcx>],
|
||||||
},
|
},
|
||||||
Block {
|
Block {
|
||||||
body: &'tcx hir::Block<'tcx>,
|
body: Block<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Assign {
|
Assign {
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
rhs: ExprRef<'tcx>,
|
rhs: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
AssignOp {
|
AssignOp {
|
||||||
op: BinOp,
|
op: BinOp,
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
rhs: ExprRef<'tcx>,
|
rhs: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Field {
|
Field {
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
name: Field,
|
name: Field,
|
||||||
},
|
},
|
||||||
Index {
|
Index {
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: &'thir Expr<'thir, 'tcx>,
|
||||||
index: ExprRef<'tcx>,
|
index: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
VarRef {
|
VarRef {
|
||||||
id: hir::HirId,
|
id: hir::HirId,
|
||||||
|
@ -226,35 +223,35 @@ crate enum ExprKind<'tcx> {
|
||||||
},
|
},
|
||||||
Borrow {
|
Borrow {
|
||||||
borrow_kind: BorrowKind,
|
borrow_kind: BorrowKind,
|
||||||
arg: ExprRef<'tcx>,
|
arg: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
|
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
|
||||||
AddressOf {
|
AddressOf {
|
||||||
mutability: hir::Mutability,
|
mutability: hir::Mutability,
|
||||||
arg: ExprRef<'tcx>,
|
arg: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Break {
|
Break {
|
||||||
label: region::Scope,
|
label: region::Scope,
|
||||||
value: Option<ExprRef<'tcx>>,
|
value: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
Continue {
|
Continue {
|
||||||
label: region::Scope,
|
label: region::Scope,
|
||||||
},
|
},
|
||||||
Return {
|
Return {
|
||||||
value: Option<ExprRef<'tcx>>,
|
value: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
ConstBlock {
|
ConstBlock {
|
||||||
value: &'tcx Const<'tcx>,
|
value: &'tcx Const<'tcx>,
|
||||||
},
|
},
|
||||||
Repeat {
|
Repeat {
|
||||||
value: ExprRef<'tcx>,
|
value: &'thir Expr<'thir, 'tcx>,
|
||||||
count: &'tcx Const<'tcx>,
|
count: &'tcx Const<'tcx>,
|
||||||
},
|
},
|
||||||
Array {
|
Array {
|
||||||
fields: Vec<ExprRef<'tcx>>,
|
fields: &'thir [Expr<'thir, 'tcx>],
|
||||||
},
|
},
|
||||||
Tuple {
|
Tuple {
|
||||||
fields: Vec<ExprRef<'tcx>>,
|
fields: &'thir [Expr<'thir, 'tcx>],
|
||||||
},
|
},
|
||||||
Adt {
|
Adt {
|
||||||
adt_def: &'tcx AdtDef,
|
adt_def: &'tcx AdtDef,
|
||||||
|
@ -265,23 +262,23 @@ crate enum ExprKind<'tcx> {
|
||||||
/// Bar::<T> { ... }`.
|
/// Bar::<T> { ... }`.
|
||||||
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
||||||
|
|
||||||
fields: Vec<FieldExprRef<'tcx>>,
|
fields: &'thir [FieldExpr<'thir, 'tcx>],
|
||||||
base: Option<FruInfo<'tcx>>,
|
base: Option<FruInfo<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
PlaceTypeAscription {
|
PlaceTypeAscription {
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
/// Type that the user gave to this expression
|
/// Type that the user gave to this expression
|
||||||
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
||||||
},
|
},
|
||||||
ValueTypeAscription {
|
ValueTypeAscription {
|
||||||
source: ExprRef<'tcx>,
|
source: &'thir Expr<'thir, 'tcx>,
|
||||||
/// Type that the user gave to this expression
|
/// Type that the user gave to this expression
|
||||||
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
||||||
},
|
},
|
||||||
Closure {
|
Closure {
|
||||||
closure_id: DefId,
|
closure_id: DefId,
|
||||||
substs: UpvarSubsts<'tcx>,
|
substs: UpvarSubsts<'tcx>,
|
||||||
upvars: Vec<ExprRef<'tcx>>,
|
upvars: &'thir [Expr<'thir, 'tcx>],
|
||||||
movability: Option<hir::Movability>,
|
movability: Option<hir::Movability>,
|
||||||
},
|
},
|
||||||
Literal {
|
Literal {
|
||||||
|
@ -302,7 +299,7 @@ crate enum ExprKind<'tcx> {
|
||||||
},
|
},
|
||||||
InlineAsm {
|
InlineAsm {
|
||||||
template: &'tcx [InlineAsmTemplatePiece],
|
template: &'tcx [InlineAsmTemplatePiece],
|
||||||
operands: Vec<InlineAsmOperand<'tcx>>,
|
operands: &'thir [InlineAsmOperand<'thir, 'tcx>],
|
||||||
options: InlineAsmOptions,
|
options: InlineAsmOptions,
|
||||||
line_spans: &'tcx [Span],
|
line_spans: &'tcx [Span],
|
||||||
},
|
},
|
||||||
|
@ -310,46 +307,40 @@ crate enum ExprKind<'tcx> {
|
||||||
ThreadLocalRef(DefId),
|
ThreadLocalRef(DefId),
|
||||||
LlvmInlineAsm {
|
LlvmInlineAsm {
|
||||||
asm: &'tcx hir::LlvmInlineAsmInner,
|
asm: &'tcx hir::LlvmInlineAsmInner,
|
||||||
outputs: Vec<ExprRef<'tcx>>,
|
outputs: &'thir [Expr<'thir, 'tcx>],
|
||||||
inputs: Vec<ExprRef<'tcx>>,
|
inputs: &'thir [Expr<'thir, 'tcx>],
|
||||||
},
|
},
|
||||||
Yield {
|
Yield {
|
||||||
value: ExprRef<'tcx>,
|
value: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate enum ExprRef<'tcx> {
|
crate struct FieldExpr<'thir, 'tcx> {
|
||||||
Thir(&'tcx hir::Expr<'tcx>),
|
|
||||||
Mirror(Box<Expr<'tcx>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
crate struct FieldExprRef<'tcx> {
|
|
||||||
crate name: Field,
|
crate name: Field,
|
||||||
crate expr: ExprRef<'tcx>,
|
crate expr: &'thir Expr<'thir, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate struct FruInfo<'tcx> {
|
crate struct FruInfo<'thir, 'tcx> {
|
||||||
crate base: ExprRef<'tcx>,
|
crate base: &'thir Expr<'thir, 'tcx>,
|
||||||
crate field_types: Vec<Ty<'tcx>>,
|
crate field_types: &'thir [Ty<'tcx>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate struct Arm<'tcx> {
|
crate struct Arm<'thir, 'tcx> {
|
||||||
crate pattern: Pat<'tcx>,
|
crate pattern: Pat<'tcx>,
|
||||||
crate guard: Option<Guard<'tcx>>,
|
crate guard: Option<Guard<'thir, 'tcx>>,
|
||||||
crate body: ExprRef<'tcx>,
|
crate body: &'thir Expr<'thir, 'tcx>,
|
||||||
crate lint_level: LintLevel,
|
crate lint_level: LintLevel,
|
||||||
crate scope: region::Scope,
|
crate scope: region::Scope,
|
||||||
crate span: Span,
|
crate span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
crate enum Guard<'tcx> {
|
crate enum Guard<'thir, 'tcx> {
|
||||||
If(ExprRef<'tcx>),
|
If(&'thir Expr<'thir, 'tcx>),
|
||||||
IfLet(Pat<'tcx>, ExprRef<'tcx>),
|
IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -358,110 +349,35 @@ crate enum LogicalOp {
|
||||||
Or,
|
Or,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ExprRef<'tcx> {
|
#[derive(Debug)]
|
||||||
crate fn span(&self) -> Span {
|
crate enum InlineAsmOperand<'thir, 'tcx> {
|
||||||
match self {
|
|
||||||
ExprRef::Thir(expr) => expr.span,
|
|
||||||
ExprRef::Mirror(expr) => expr.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
crate enum InlineAsmOperand<'tcx> {
|
|
||||||
In {
|
In {
|
||||||
reg: InlineAsmRegOrRegClass,
|
reg: InlineAsmRegOrRegClass,
|
||||||
expr: ExprRef<'tcx>,
|
expr: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
Out {
|
Out {
|
||||||
reg: InlineAsmRegOrRegClass,
|
reg: InlineAsmRegOrRegClass,
|
||||||
late: bool,
|
late: bool,
|
||||||
expr: Option<ExprRef<'tcx>>,
|
expr: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
InOut {
|
InOut {
|
||||||
reg: InlineAsmRegOrRegClass,
|
reg: InlineAsmRegOrRegClass,
|
||||||
late: bool,
|
late: bool,
|
||||||
expr: ExprRef<'tcx>,
|
expr: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
SplitInOut {
|
SplitInOut {
|
||||||
reg: InlineAsmRegOrRegClass,
|
reg: InlineAsmRegOrRegClass,
|
||||||
late: bool,
|
late: bool,
|
||||||
in_expr: ExprRef<'tcx>,
|
in_expr: &'thir Expr<'thir, 'tcx>,
|
||||||
out_expr: Option<ExprRef<'tcx>>,
|
out_expr: Option<&'thir Expr<'thir, 'tcx>>,
|
||||||
},
|
},
|
||||||
Const {
|
Const {
|
||||||
expr: ExprRef<'tcx>,
|
expr: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
SymFn {
|
SymFn {
|
||||||
expr: ExprRef<'tcx>,
|
expr: &'thir Expr<'thir, 'tcx>,
|
||||||
},
|
},
|
||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// The Mirror trait
|
|
||||||
|
|
||||||
/// "Mirroring" is the process of converting from a HIR type into one
|
|
||||||
/// of the THIR types defined in this file. This is basically a "on
|
|
||||||
/// the fly" desugaring step that hides a lot of the messiness in the
|
|
||||||
/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
|
|
||||||
/// `Expr<'tcx>`.
|
|
||||||
///
|
|
||||||
/// Mirroring is gradual: when you mirror an outer expression like `e1
|
|
||||||
/// + e2`, the references to the inner expressions `e1` and `e2` are
|
|
||||||
/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
|
|
||||||
/// mirrored. This allows a single AST node from the compiler to
|
|
||||||
/// expand into one or more Thir nodes, which lets the Thir nodes be
|
|
||||||
/// simpler.
|
|
||||||
crate trait Mirror<'tcx> {
|
|
||||||
type Output;
|
|
||||||
|
|
||||||
fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
|
|
||||||
type Output = Expr<'tcx>;
|
|
||||||
|
|
||||||
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
|
|
||||||
type Output = Expr<'tcx>;
|
|
||||||
|
|
||||||
fn make_mirror(self, hir: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
|
|
||||||
match self {
|
|
||||||
ExprRef::Thir(h) => h.make_mirror(hir),
|
|
||||||
ExprRef::Mirror(m) => *m,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
|
|
||||||
type Output = Stmt<'tcx>;
|
|
||||||
|
|
||||||
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
|
|
||||||
type Output = Stmt<'tcx>;
|
|
||||||
|
|
||||||
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
|
|
||||||
match self {
|
|
||||||
StmtRef::Mirror(m) => *m,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Mirror<'tcx> for Block<'tcx> {
|
|
||||||
type Output = Block<'tcx>;
|
|
||||||
|
|
||||||
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue