2019-02-08 06:28:15 +09:00
|
|
|
use crate::build;
|
2019-05-30 13:21:17 -07:00
|
|
|
use crate::build::scope::DropKind;
|
2019-02-08 06:28:15 +09:00
|
|
|
use crate::hair::cx::Cx;
|
2019-09-26 18:42:24 +01:00
|
|
|
use crate::hair::{LintLevel, BindingMode, PatKind};
|
2019-02-08 06:28:15 +09:00
|
|
|
use crate::transform::MirSource;
|
|
|
|
use crate::util as mir_util;
|
2017-05-02 14:56:26 -04:00
|
|
|
use rustc::hir;
|
2019-11-25 12:58:40 +00:00
|
|
|
use rustc::hir::{Node, GeneratorKind};
|
2018-12-22 15:06:14 -08:00
|
|
|
use rustc::hir::def_id::DefId;
|
2019-08-10 14:38:17 +03:00
|
|
|
use rustc::middle::lang_items;
|
2017-08-31 21:37:38 +03:00
|
|
|
use rustc::middle::region;
|
2016-09-19 23:50:00 +03:00
|
|
|
use rustc::mir::*;
|
2017-05-02 14:56:26 -04:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt};
|
2019-08-10 14:38:17 +03:00
|
|
|
use rustc::ty::subst::Subst;
|
2019-03-07 12:18:59 +01:00
|
|
|
use rustc::util::nodemap::HirIdMap;
|
2017-12-08 21:18:21 +02:00
|
|
|
use rustc_target::spec::PanicStrategy;
|
2019-09-26 05:38:33 +00:00
|
|
|
use rustc_index::vec::{IndexVec, Idx};
|
2017-05-02 14:56:26 -04:00
|
|
|
use std::u32;
|
2018-04-25 19:30:39 +03:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2018-02-20 13:49:54 -05:00
|
|
|
use syntax::attr::{self, UnwindAttr};
|
2019-05-11 17:41:37 +03:00
|
|
|
use syntax::symbol::kw;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax_pos::Span;
|
2015-10-05 12:31:48 -04:00
|
|
|
|
2018-09-11 21:35:08 -04:00
|
|
|
use super::lints;
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Construct the MIR for a given `DefId`.
|
2019-06-21 18:51:27 +02:00
|
|
|
pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
|
2019-03-04 09:00:30 +01:00
|
|
|
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
2016-06-07 17:28:36 +03:00
|
|
|
|
2017-05-02 14:56:26 -04:00
|
|
|
// Figure out what primary body this item has.
|
2019-06-20 10:39:19 +02:00
|
|
|
let (body_id, return_ty_span) = match tcx.hir().get(id) {
|
2019-09-26 14:39:48 +01:00
|
|
|
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
|
2019-11-07 12:57:52 +01:00
|
|
|
| Node::Item(
|
|
|
|
hir::Item {
|
2019-11-07 13:06:52 +01:00
|
|
|
kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
|
2019-11-07 12:57:52 +01:00
|
|
|
..
|
|
|
|
}
|
|
|
|
)
|
2018-09-15 15:45:12 +01:00
|
|
|
| Node::ImplItem(
|
|
|
|
hir::ImplItem {
|
2019-11-07 13:06:52 +01:00
|
|
|
kind: hir::ImplItemKind::Method(hir::FnSig { decl, .. }, body_id),
|
2018-09-15 15:45:12 +01:00
|
|
|
..
|
|
|
|
}
|
|
|
|
)
|
|
|
|
| Node::TraitItem(
|
|
|
|
hir::TraitItem {
|
2019-09-26 17:07:54 +01:00
|
|
|
kind: hir::TraitItemKind::Method(
|
2019-11-07 13:06:52 +01:00
|
|
|
hir::FnSig { decl, .. },
|
2018-09-15 15:45:12 +01:00
|
|
|
hir::TraitMethod::Provided(body_id),
|
|
|
|
),
|
|
|
|
..
|
|
|
|
}
|
|
|
|
) => {
|
|
|
|
(*body_id, decl.output.span())
|
|
|
|
}
|
2019-09-26 17:51:36 +01:00
|
|
|
Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. })
|
|
|
|
| Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, body_id), .. })
|
2019-09-26 16:38:13 +01:00
|
|
|
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. })
|
2018-09-15 15:45:12 +01:00
|
|
|
| Node::TraitItem(
|
2019-09-26 17:07:54 +01:00
|
|
|
hir::TraitItem { kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. }
|
2018-09-15 15:45:12 +01:00
|
|
|
) => {
|
|
|
|
(*body_id, ty.span)
|
|
|
|
}
|
2019-02-04 16:35:52 +01:00
|
|
|
Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => {
|
2019-06-14 18:58:55 +02:00
|
|
|
(*body, tcx.hir().span(*hir_id))
|
2018-09-15 15:45:12 +01:00
|
|
|
}
|
|
|
|
|
2019-06-14 18:58:55 +02:00
|
|
|
_ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def_id),
|
2017-05-02 14:56:26 -04:00
|
|
|
};
|
|
|
|
|
2017-06-09 10:55:16 +03:00
|
|
|
tcx.infer_ctxt().enter(|infcx| {
|
2019-03-04 09:00:30 +01:00
|
|
|
let cx = Cx::new(&infcx, id);
|
2019-06-01 13:38:36 +02:00
|
|
|
let body = if cx.tables().tainted_by_errors {
|
2017-05-02 14:56:26 -04:00
|
|
|
build::construct_error(cx, body_id)
|
2018-12-07 18:25:55 +01:00
|
|
|
} else if cx.body_owner_kind.is_fn_or_closure() {
|
2017-05-02 14:56:26 -04:00
|
|
|
// fetch the fully liberated fn signature (that is, all bound
|
|
|
|
// types/lifetimes replaced)
|
2019-03-04 09:00:30 +01:00
|
|
|
let fn_sig = cx.tables().liberated_fn_sigs()[id].clone();
|
2019-06-27 11:28:14 +02:00
|
|
|
let fn_def_id = tcx.hir().local_def_id(id);
|
2017-05-02 14:56:26 -04:00
|
|
|
|
2018-11-03 00:22:12 +01:00
|
|
|
let ty = tcx.type_of(fn_def_id);
|
2017-05-02 14:56:26 -04:00
|
|
|
let mut abi = fn_sig.abi;
|
2019-09-16 19:08:35 +01:00
|
|
|
let implicit_argument = match ty.kind {
|
2018-08-22 01:35:02 +01:00
|
|
|
ty::Closure(..) => {
|
2016-12-26 14:34:03 +01:00
|
|
|
// HACK(eddyb) Avoid having RustCall on closures,
|
|
|
|
// as it adds unnecessary (and wrong) auto-tupling.
|
|
|
|
abi = Abi::Rust;
|
2019-06-02 19:03:17 +01:00
|
|
|
Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None))
|
2016-12-26 14:34:03 +01:00
|
|
|
}
|
2018-08-22 01:35:02 +01:00
|
|
|
ty::Generator(..) => {
|
2019-03-04 09:00:30 +01:00
|
|
|
let gen_ty = tcx.body_tables(body_id).node_type(id);
|
2019-06-02 19:03:17 +01:00
|
|
|
Some(ArgInfo(gen_ty, None, None, None))
|
2016-12-26 14:34:03 +01:00
|
|
|
}
|
|
|
|
_ => None,
|
2017-05-02 14:56:26 -04:00
|
|
|
};
|
|
|
|
|
2017-09-19 16:20:02 +03:00
|
|
|
let safety = match fn_sig.unsafety {
|
|
|
|
hir::Unsafety::Normal => Safety::Safe,
|
|
|
|
hir::Unsafety::Unsafe => Safety::FnUnsafe,
|
|
|
|
};
|
2018-11-30 18:17:50 +01:00
|
|
|
|
2018-12-04 13:45:36 +01:00
|
|
|
let body = tcx.hir().body(body_id);
|
2017-05-02 14:56:26 -04:00
|
|
|
let explicit_arguments =
|
2019-08-27 13:24:32 +02:00
|
|
|
body.params
|
2017-05-02 14:56:26 -04:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, arg)| {
|
2018-12-04 13:45:36 +01:00
|
|
|
let owner_id = tcx.hir().body_owner(body_id);
|
2018-06-07 17:05:58 +02:00
|
|
|
let opt_ty_info;
|
|
|
|
let self_arg;
|
2019-06-14 12:28:47 +02:00
|
|
|
if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) {
|
2019-08-10 14:38:17 +03:00
|
|
|
opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span);
|
2018-10-01 17:46:04 +02:00
|
|
|
self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
|
|
|
|
match fn_decl.implicit_self {
|
|
|
|
hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
|
|
|
|
hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut),
|
|
|
|
hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef),
|
|
|
|
hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef),
|
|
|
|
_ => None,
|
|
|
|
}
|
2018-06-07 17:05:58 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
opt_ty_info = None;
|
|
|
|
self_arg = None;
|
|
|
|
}
|
2019-05-29 19:28:51 +03:00
|
|
|
|
2019-08-10 14:38:17 +03:00
|
|
|
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
|
|
|
|
// (as it's created inside the body itself, not passed in from outside).
|
|
|
|
let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
|
|
|
|
let va_list_did = tcx.require_lang_item(
|
|
|
|
lang_items::VaListTypeLangItem,
|
|
|
|
Some(arg.span),
|
|
|
|
);
|
|
|
|
let region = tcx.mk_region(ty::ReScope(region::Scope {
|
|
|
|
id: body.value.hir_id.local_id,
|
|
|
|
data: region::ScopeData::CallSite
|
|
|
|
}));
|
|
|
|
|
|
|
|
tcx.type_of(va_list_did).subst(tcx, &[region.into()])
|
|
|
|
} else {
|
|
|
|
fn_sig.inputs()[index]
|
|
|
|
};
|
|
|
|
|
|
|
|
ArgInfo(ty, opt_ty_info, Some(&arg), self_arg)
|
2017-05-02 14:56:26 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
|
2017-07-05 14:57:26 -07:00
|
|
|
|
2019-06-18 14:34:51 -07:00
|
|
|
let (yield_ty, return_ty) = if body.generator_kind.is_some() {
|
2019-09-16 19:08:35 +01:00
|
|
|
let gen_sig = match ty.kind {
|
2018-08-22 01:35:02 +01:00
|
|
|
ty::Generator(gen_def_id, gen_substs, ..) =>
|
2019-10-03 21:51:30 +08:00
|
|
|
gen_substs.as_generator().sig(gen_def_id, tcx),
|
2017-11-18 11:16:25 -05:00
|
|
|
_ =>
|
2019-06-14 18:58:55 +02:00
|
|
|
span_bug!(tcx.hir().span(id),
|
2019-03-04 09:00:30 +01:00
|
|
|
"generator w/o generator type: {:?}", ty),
|
2017-11-18 11:16:25 -05:00
|
|
|
};
|
2017-07-11 12:57:05 -07:00
|
|
|
(Some(gen_sig.yield_ty), gen_sig.return_ty)
|
2016-12-26 14:34:03 +01:00
|
|
|
} else {
|
2017-07-11 12:57:05 -07:00
|
|
|
(None, fn_sig.output())
|
2016-12-26 14:34:03 +01:00
|
|
|
};
|
2017-07-05 14:57:26 -07:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
let mut mir = build::construct_fn(
|
|
|
|
cx,
|
|
|
|
id,
|
|
|
|
arguments,
|
|
|
|
safety,
|
|
|
|
abi,
|
|
|
|
return_ty,
|
|
|
|
return_ty_span,
|
|
|
|
body,
|
|
|
|
);
|
|
|
|
mir.yield_ty = yield_ty;
|
|
|
|
mir
|
2017-05-02 14:56:26 -04:00
|
|
|
} else {
|
2019-03-30 13:00:41 +00:00
|
|
|
// Get the revealed type of this const. This is *not* the adjusted
|
|
|
|
// type of its body, which may be a subtype of this type. For
|
|
|
|
// example:
|
|
|
|
//
|
|
|
|
// fn foo(_: &()) {}
|
|
|
|
// static X: fn(&'static ()) = foo;
|
|
|
|
//
|
|
|
|
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
|
|
|
|
// is not the same as the type of X. We need the type of the return
|
|
|
|
// place to be the type of the constant because NLL typeck will
|
|
|
|
// equate them.
|
|
|
|
|
|
|
|
let return_ty = cx.tables().node_type(id);
|
|
|
|
|
|
|
|
build::construct_const(cx, body_id, return_ty, return_ty_span)
|
2017-05-02 14:56:26 -04:00
|
|
|
};
|
|
|
|
|
2017-11-10 19:20:35 +02:00
|
|
|
mir_util::dump_mir(tcx, None, "mir_map", &0,
|
2019-06-03 18:26:48 -04:00
|
|
|
MirSource::item(def_id), &body, |_, _| Ok(()) );
|
2017-05-02 14:56:26 -04:00
|
|
|
|
2019-06-03 18:26:48 -04:00
|
|
|
lints::check(tcx, &body, def_id);
|
2018-09-11 21:35:08 -04:00
|
|
|
|
2019-06-03 18:26:48 -04:00
|
|
|
body
|
2017-05-02 14:56:26 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
|
|
|
|
|
2019-06-21 18:51:27 +02:00
|
|
|
fn liberated_closure_env_ty(
|
|
|
|
tcx: TyCtxt<'_>,
|
2019-06-12 00:11:55 +03:00
|
|
|
closure_expr_id: hir::HirId,
|
|
|
|
body_id: hir::BodyId,
|
2019-06-21 18:51:27 +02:00
|
|
|
) -> Ty<'_> {
|
2019-03-04 09:00:30 +01:00
|
|
|
let closure_ty = tcx.body_tables(body_id).node_type(closure_expr_id);
|
2017-05-02 14:56:26 -04:00
|
|
|
|
2019-09-16 19:08:35 +01:00
|
|
|
let (closure_def_id, closure_substs) = match closure_ty.kind {
|
2018-08-22 01:35:02 +01:00
|
|
|
ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
|
2017-11-08 09:45:48 -05:00
|
|
|
_ => bug!("closure expr does not have closure type: {:?}", closure_ty)
|
|
|
|
};
|
|
|
|
|
2017-11-21 11:18:40 -05:00
|
|
|
let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap();
|
|
|
|
tcx.liberate_late_bound_regions(closure_def_id, &closure_env_ty)
|
2017-05-02 14:56:26 -04:00
|
|
|
}
|
2016-06-07 17:28:36 +03:00
|
|
|
|
2018-09-22 00:51:48 +02:00
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
|
pub enum BlockFrame {
|
|
|
|
/// Evaluation is currently within a statement.
|
|
|
|
///
|
|
|
|
/// Examples include:
|
2019-02-28 22:43:53 +00:00
|
|
|
/// 1. `EXPR;`
|
|
|
|
/// 2. `let _ = EXPR;`
|
|
|
|
/// 3. `let x = EXPR;`
|
2018-09-22 00:51:48 +02:00
|
|
|
Statement {
|
|
|
|
/// If true, then statement discards result from evaluating
|
|
|
|
/// the expression (such as examples 1 and 2 above).
|
|
|
|
ignores_expr_result: bool
|
|
|
|
},
|
|
|
|
|
|
|
|
/// Evaluation is currently within the tail expression of a block.
|
|
|
|
///
|
|
|
|
/// Example: `{ STMT_1; STMT_2; EXPR }`
|
|
|
|
TailExpr {
|
|
|
|
/// If true, then the surrounding context of the block ignores
|
|
|
|
/// the result of evaluating the block's tail expression.
|
|
|
|
///
|
|
|
|
/// Example: `let _ = { STMT_1; EXPR };`
|
|
|
|
tail_result_is_ignored: bool
|
|
|
|
},
|
|
|
|
|
|
|
|
/// Generic mark meaning that the block occurred as a subexpression
|
|
|
|
/// where the result might be used.
|
|
|
|
///
|
|
|
|
/// Examples: `foo(EXPR)`, `match EXPR { ... }`
|
|
|
|
SubExpr,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockFrame {
|
|
|
|
fn is_tail_expr(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
BlockFrame::TailExpr { .. } => true,
|
|
|
|
|
|
|
|
BlockFrame::Statement { .. } |
|
|
|
|
BlockFrame::SubExpr => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn is_statement(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
BlockFrame::Statement { .. } => true,
|
|
|
|
|
|
|
|
BlockFrame::TailExpr { .. } |
|
|
|
|
BlockFrame::SubExpr => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-08 14:31:12 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct BlockContext(Vec<BlockFrame>);
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
struct Builder<'a, 'tcx> {
|
2019-06-01 13:38:36 +02:00
|
|
|
hir: Cx<'a, 'tcx>,
|
2015-10-05 12:31:48 -04:00
|
|
|
cfg: CFG<'tcx>,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2016-03-22 20:41:07 -04:00
|
|
|
fn_span: Span,
|
2016-09-25 01:38:27 +02:00
|
|
|
arg_count: usize,
|
2019-11-25 12:58:40 +00:00
|
|
|
generator_kind: Option<GeneratorKind>,
|
2016-03-22 20:41:07 -04:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// The current set of scopes, updated as we traverse;
|
|
|
|
/// see the `scope` module for more details.
|
2019-06-15 17:37:19 +01:00
|
|
|
scopes: scope::Scopes<'tcx>,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// The block-context: each time we build the code within an hair::Block,
|
2018-09-22 00:51:48 +02:00
|
|
|
/// we push a frame here tracking whether we are building a statement or
|
|
|
|
/// if we are pushing the tail expression of the block. This is used to
|
|
|
|
/// embed information in generated temps about whether they were created
|
|
|
|
/// for a block tail expression or not.
|
|
|
|
///
|
|
|
|
/// It would be great if we could fold this into `self.scopes`
|
2019-02-08 14:53:55 +01:00
|
|
|
/// somehow, but right now I think that is very tightly tied to
|
2018-09-22 00:51:48 +02:00
|
|
|
/// the code generation in ways that we cannot (or should not)
|
|
|
|
/// start just throwing new entries onto that vector in order to
|
|
|
|
/// distinguish the context of EXPR1 from the context of EXPR2 in
|
2019-02-08 14:53:55 +01:00
|
|
|
/// `{ STMTS; EXPR1 } + EXPR2`.
|
2018-11-08 14:31:12 +01:00
|
|
|
block_context: BlockContext,
|
2018-09-22 00:51:48 +02:00
|
|
|
|
2017-09-19 16:20:02 +03:00
|
|
|
/// The current unsafe block in scope, even if it is hidden by
|
2019-02-08 14:53:55 +01:00
|
|
|
/// a `PushUnsafeBlock`.
|
2017-09-19 16:20:02 +03:00
|
|
|
unpushed_unsafe: Safety,
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// The number of `push_unsafe_block` levels in scope.
|
2017-09-19 16:20:02 +03:00
|
|
|
push_unsafe_count: usize,
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// The vector of all scopes that we have created thus far;
|
|
|
|
/// we track this for debuginfo later.
|
2018-05-28 14:16:09 +03:00
|
|
|
source_scopes: IndexVec<SourceScope, SourceScopeData>,
|
2018-05-28 17:37:48 +03:00
|
|
|
source_scope_local_data: IndexVec<SourceScope, SourceScopeLocalData>,
|
2018-05-28 14:16:09 +03:00
|
|
|
source_scope: SourceScope,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// The guard-context: each time we build the guard expression for
|
2018-02-26 15:45:13 +01:00
|
|
|
/// a match arm, we push onto this stack, and then pop when we
|
|
|
|
/// finish building it.
|
|
|
|
guard_context: Vec<GuardFrame>,
|
|
|
|
|
2019-03-10 13:22:00 +01:00
|
|
|
/// Maps `HirId`s of variable bindings to the `Local`s created for them.
|
2018-02-26 15:45:13 +01:00
|
|
|
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
|
2019-03-07 12:18:59 +01:00
|
|
|
var_indices: HirIdMap<LocalsForNode>,
|
2016-09-25 01:38:27 +02:00
|
|
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
2018-11-16 22:56:18 +01:00
|
|
|
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
2018-05-16 15:40:32 +03:00
|
|
|
upvar_mutbls: Vec<Mutability>,
|
2017-12-01 14:31:47 +02:00
|
|
|
unit_temp: Option<Place<'tcx>>,
|
2016-03-23 20:46:38 -04:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Cached block with the `RESUME` terminator; this is created
|
2016-04-20 00:13:30 +03:00
|
|
|
/// when first set of cleanups are built.
|
2016-03-23 20:46:38 -04:00
|
|
|
cached_resume_block: Option<BasicBlock>,
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Cached block with the `RETURN` terminator.
|
2016-04-20 00:13:30 +03:00
|
|
|
cached_return_block: Option<BasicBlock>,
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Cached block with the `UNREACHABLE` terminator.
|
2017-11-13 23:08:12 +00:00
|
|
|
cached_unreachable_block: Option<BasicBlock>,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2019-06-01 13:38:36 +02:00
|
|
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
2019-03-07 12:18:59 +01:00
|
|
|
fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
|
2018-02-26 15:45:13 +01:00
|
|
|
self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
|
|
|
|
}
|
|
|
|
|
2019-03-07 12:18:59 +01:00
|
|
|
fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
|
2018-02-26 15:45:13 +01:00
|
|
|
self.var_indices[&id].local_id(for_guard)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-08 14:31:12 +01:00
|
|
|
impl BlockContext {
|
|
|
|
fn new() -> Self { BlockContext(vec![]) }
|
|
|
|
fn push(&mut self, bf: BlockFrame) { self.0.push(bf); }
|
|
|
|
fn pop(&mut self) -> Option<BlockFrame> { self.0.pop() }
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Traverses the frames on the `BlockContext`, searching for either
|
2018-11-08 14:31:12 +01:00
|
|
|
/// the first block-tail expression frame with no intervening
|
|
|
|
/// statement frame.
|
|
|
|
///
|
|
|
|
/// Notably, this skips over `SubExpr` frames; this method is
|
|
|
|
/// meant to be used in the context of understanding the
|
|
|
|
/// relationship of a temp (created within some complicated
|
|
|
|
/// expression) with its containing expression, and whether the
|
|
|
|
/// value of that *containing expression* (not the temp!) is
|
|
|
|
/// ignored.
|
|
|
|
fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
|
|
|
|
for bf in self.0.iter().rev() {
|
|
|
|
match bf {
|
|
|
|
BlockFrame::SubExpr => continue,
|
|
|
|
BlockFrame::Statement { .. } => break,
|
|
|
|
&BlockFrame::TailExpr { tail_result_is_ignored } =>
|
|
|
|
return Some(BlockTailInfo { tail_result_is_ignored })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Looks at the topmost frame on the BlockContext and reports
|
|
|
|
/// whether its one that would discard a block tail result.
|
|
|
|
///
|
|
|
|
/// Unlike `currently_within_ignored_tail_expression`, this does
|
|
|
|
/// *not* skip over `SubExpr` frames: here, we want to know
|
|
|
|
/// whether the block result itself is discarded.
|
|
|
|
fn currently_ignores_tail_results(&self) -> bool {
|
|
|
|
match self.0.last() {
|
|
|
|
// no context: conservatively assume result is read
|
|
|
|
None => false,
|
|
|
|
|
|
|
|
// sub-expression: block result feeds into some computation
|
|
|
|
Some(BlockFrame::SubExpr) => false,
|
|
|
|
|
|
|
|
// otherwise: use accumulated is_ignored state.
|
|
|
|
Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) |
|
|
|
|
Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 15:45:13 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum LocalsForNode {
|
2019-03-10 13:22:00 +01:00
|
|
|
/// In the usual case, a `HirId` for an identifier maps to at most
|
2019-02-08 14:53:55 +01:00
|
|
|
/// one `Local` declaration.
|
2018-02-26 15:45:13 +01:00
|
|
|
One(Local),
|
2018-07-26 13:14:12 +02:00
|
|
|
|
|
|
|
/// The exceptional case is identifiers in a match arm's pattern
|
|
|
|
/// that are referenced in a guard of that match arm. For these,
|
2019-02-02 16:38:12 +00:00
|
|
|
/// we have `2` Locals.
|
2018-07-26 13:14:12 +02:00
|
|
|
///
|
|
|
|
/// * `for_arm_body` is the Local used in the arm body (which is
|
|
|
|
/// just like the `One` case above),
|
|
|
|
///
|
|
|
|
/// * `ref_for_guard` is the Local used in the arm's guard (which
|
|
|
|
/// is a reference to a temp that is an alias of
|
|
|
|
/// `for_arm_body`).
|
2019-02-02 16:38:12 +00:00
|
|
|
ForGuard { ref_for_guard: Local, for_arm_body: Local },
|
2018-02-26 15:45:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct GuardFrameLocal {
|
2019-03-07 12:18:59 +01:00
|
|
|
id: hir::HirId,
|
2018-02-26 15:45:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GuardFrameLocal {
|
2019-03-07 12:18:59 +01:00
|
|
|
fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
|
2018-02-26 15:45:13 +01:00
|
|
|
GuardFrameLocal {
|
|
|
|
id: id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct GuardFrame {
|
|
|
|
/// These are the id's of names that are bound by patterns of the
|
|
|
|
/// arm of *this* guard.
|
|
|
|
///
|
|
|
|
/// (Frames higher up the stack will have the id's bound in arms
|
|
|
|
/// further out, such as in a case like:
|
|
|
|
///
|
|
|
|
/// match E1 {
|
|
|
|
/// P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1,
|
|
|
|
/// }
|
|
|
|
///
|
2019-02-08 14:53:55 +01:00
|
|
|
/// here, when building for FIXME.
|
2018-02-26 15:45:13 +01:00
|
|
|
locals: Vec<GuardFrameLocal>,
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// `ForGuard` indicates whether we are talking about:
|
2019-02-02 16:38:12 +00:00
|
|
|
/// 1. The variable for use outside of guard expressions, or
|
|
|
|
/// 2. The temp that holds reference to (1.), which is actually what the
|
|
|
|
/// guard expressions see.
|
2018-02-26 15:45:13 +01:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum ForGuard {
|
2018-05-11 23:32:13 +02:00
|
|
|
RefWithinGuard,
|
2018-02-26 15:45:13 +01:00
|
|
|
OutsideGuard,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LocalsForNode {
|
|
|
|
fn local_id(&self, for_guard: ForGuard) -> Local {
|
|
|
|
match (self, for_guard) {
|
|
|
|
(&LocalsForNode::One(local_id), ForGuard::OutsideGuard) |
|
2018-07-26 13:14:12 +02:00
|
|
|
(&LocalsForNode::ForGuard { ref_for_guard: local_id, .. }, ForGuard::RefWithinGuard) |
|
|
|
|
(&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) =>
|
2018-02-26 15:45:13 +01:00
|
|
|
local_id,
|
|
|
|
|
2018-05-11 23:32:13 +02:00
|
|
|
(&LocalsForNode::One(_), ForGuard::RefWithinGuard) =>
|
2018-02-26 15:45:13 +01:00
|
|
|
bug!("anything with one local should never be within a guard."),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-05 12:31:48 -04:00
|
|
|
struct CFG<'tcx> {
|
2016-06-07 17:28:36 +03:00
|
|
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2018-07-25 13:41:32 +03:00
|
|
|
pub struct ScopeId { .. }
|
|
|
|
}
|
2016-05-31 20:27:36 +03:00
|
|
|
|
2015-08-18 17:59:21 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 13:25:07 +01:00
|
|
|
/// The `BlockAnd` "monad" packages up the new basic block along with a
|
|
|
|
/// produced value (sometimes just unit, of course). The `unpack!`
|
|
|
|
/// macro (and methods below) makes working with `BlockAnd` much more
|
|
|
|
/// convenient.
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2018-03-30 23:06:05 -07:00
|
|
|
#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
|
2017-05-01 11:58:05 -04:00
|
|
|
struct BlockAnd<T>(BasicBlock, T);
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2015-11-19 16:37:34 +01:00
|
|
|
trait BlockAndExtension {
|
|
|
|
fn and<T>(self, v: T) -> BlockAnd<T>;
|
|
|
|
fn unit(self) -> BlockAnd<()>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockAndExtension for BasicBlock {
|
2015-08-18 17:59:21 -04:00
|
|
|
fn and<T>(self, v: T) -> BlockAnd<T> {
|
|
|
|
BlockAnd(self, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unit(self) -> BlockAnd<()> {
|
|
|
|
BlockAnd(self, ())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Update a block pointer and return the value.
|
|
|
|
/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
|
|
|
|
macro_rules! unpack {
|
|
|
|
($x:ident = $c:expr) => {
|
|
|
|
{
|
|
|
|
let BlockAnd(b, v) = $c;
|
|
|
|
$x = b;
|
|
|
|
v
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($c:expr) => {
|
|
|
|
{
|
|
|
|
let BlockAnd(b, ()) = $c;
|
|
|
|
b
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-10-12 20:48:19 +02:00
|
|
|
fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, _abi: Abi) -> bool {
|
|
|
|
// Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
|
2019-02-27 09:36:49 +03:00
|
|
|
let attrs = &tcx.get_attrs(fn_def_id);
|
|
|
|
let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs);
|
|
|
|
|
2019-10-12 20:48:19 +02:00
|
|
|
// We never unwind, so it's not relevant to stop an unwind.
|
2017-12-19 01:59:29 +01:00
|
|
|
if tcx.sess.panic_strategy() != PanicStrategy::Unwind { return false; }
|
|
|
|
|
2019-10-12 20:48:19 +02:00
|
|
|
// We cannot add landing pads, so don't add one.
|
2017-12-19 01:59:29 +01:00
|
|
|
if tcx.sess.no_landing_pads() { return false; }
|
|
|
|
|
|
|
|
// This is a special case: some functions have a C abi but are meant to
|
|
|
|
// unwind anyway. Don't stop them.
|
2019-02-27 09:36:49 +03:00
|
|
|
match unwind_attr {
|
2019-10-12 20:48:19 +02:00
|
|
|
None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
|
2018-02-20 13:49:54 -05:00
|
|
|
Some(UnwindAttr::Allowed) => false,
|
|
|
|
Some(UnwindAttr::Aborts) => true,
|
|
|
|
}
|
2017-12-19 01:59:29 +01:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:59:21 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 13:25:07 +01:00
|
|
|
/// the main entry point for building MIR for a function
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2019-08-27 13:24:32 +02:00
|
|
|
struct ArgInfo<'tcx>(Ty<'tcx>, Option<Span>, Option<&'tcx hir::Param>, Option<ImplicitSelfKind>);
|
2018-06-07 16:32:07 +02:00
|
|
|
|
2019-06-01 13:38:36 +02:00
|
|
|
fn construct_fn<'a, 'tcx, A>(
|
|
|
|
hir: Cx<'a, 'tcx>,
|
|
|
|
fn_id: hir::HirId,
|
|
|
|
arguments: A,
|
|
|
|
safety: Safety,
|
|
|
|
abi: Abi,
|
|
|
|
return_ty: Ty<'tcx>,
|
|
|
|
return_ty_span: Span,
|
|
|
|
body: &'tcx hir::Body,
|
|
|
|
) -> Body<'tcx>
|
|
|
|
where
|
|
|
|
A: Iterator<Item=ArgInfo<'tcx>>
|
2016-04-15 17:11:24 +03:00
|
|
|
{
|
2016-09-25 01:38:27 +02:00
|
|
|
let arguments: Vec<_> = arguments.collect();
|
|
|
|
|
2016-03-23 12:26:37 -04:00
|
|
|
let tcx = hir.tcx();
|
2018-12-22 15:06:14 -08:00
|
|
|
let tcx_hir = tcx.hir();
|
2019-06-14 18:58:55 +02:00
|
|
|
let span = tcx_hir.span(fn_id);
|
2018-07-15 15:00:58 +01:00
|
|
|
|
2019-06-27 11:28:14 +02:00
|
|
|
let fn_def_id = tcx_hir.local_def_id(fn_id);
|
2018-07-15 15:00:58 +01:00
|
|
|
|
2018-10-26 03:11:11 +09:00
|
|
|
let mut builder = Builder::new(hir,
|
2016-12-26 14:34:03 +01:00
|
|
|
span,
|
2017-07-11 12:57:05 -07:00
|
|
|
arguments.len(),
|
2017-09-19 16:20:02 +03:00
|
|
|
safety,
|
2018-07-15 15:00:58 +01:00
|
|
|
return_ty,
|
2018-09-15 15:45:12 +01:00
|
|
|
return_ty_span,
|
2019-11-25 12:58:40 +00:00
|
|
|
body.generator_kind);
|
2016-03-18 08:52:13 -04:00
|
|
|
|
2018-09-15 13:10:29 -04:00
|
|
|
let call_site_scope = region::Scope {
|
|
|
|
id: body.value.hir_id.local_id,
|
|
|
|
data: region::ScopeData::CallSite
|
|
|
|
};
|
|
|
|
let arg_scope = region::Scope {
|
|
|
|
id: body.value.hir_id.local_id,
|
|
|
|
data: region::ScopeData::Arguments
|
|
|
|
};
|
2016-04-15 17:11:24 +03:00
|
|
|
let mut block = START_BLOCK;
|
2017-05-26 18:21:03 +02:00
|
|
|
let source_info = builder.source_info(span);
|
2017-09-13 22:33:07 +03:00
|
|
|
let call_site_s = (call_site_scope, source_info);
|
2019-03-30 21:49:52 +00:00
|
|
|
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
|
2018-02-20 13:49:54 -05:00
|
|
|
if should_abort_on_panic(tcx, fn_def_id, abi) {
|
2017-12-19 01:59:29 +01:00
|
|
|
builder.schedule_abort();
|
|
|
|
}
|
|
|
|
|
2017-09-13 22:33:07 +03:00
|
|
|
let arg_scope_s = (arg_scope, source_info);
|
2019-07-04 21:53:46 +01:00
|
|
|
// `return_block` is called when we evaluate a `return` expression, so
|
|
|
|
// we just use `START_BLOCK` here.
|
|
|
|
unpack!(block = builder.in_breakable_scope(
|
|
|
|
None,
|
|
|
|
START_BLOCK,
|
2019-07-30 00:07:28 +02:00
|
|
|
Place::return_place(),
|
2019-07-04 21:53:46 +01:00
|
|
|
|builder| {
|
|
|
|
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
2018-05-16 18:58:54 +03:00
|
|
|
builder.args_and_body(block, fn_def_id, &arguments, arg_scope, &body.value)
|
2019-07-04 21:53:46 +01:00
|
|
|
})
|
|
|
|
},
|
|
|
|
));
|
2016-10-19 00:25:03 -07:00
|
|
|
// Attribute epilogue to function's closing brace
|
2018-03-10 17:45:47 +03:00
|
|
|
let fn_end = span.shrink_to_hi();
|
2016-10-19 00:25:03 -07:00
|
|
|
let source_info = builder.source_info(fn_end);
|
2016-04-20 00:13:30 +03:00
|
|
|
let return_block = builder.return_block();
|
2016-06-07 19:21:56 +03:00
|
|
|
builder.cfg.terminate(block, source_info,
|
2016-04-20 00:13:30 +03:00
|
|
|
TerminatorKind::Goto { target: return_block });
|
2016-06-07 19:21:56 +03:00
|
|
|
builder.cfg.terminate(return_block, source_info,
|
2016-03-23 12:26:37 -04:00
|
|
|
TerminatorKind::Return);
|
2017-11-13 23:08:12 +00:00
|
|
|
// Attribute any unreachable codepaths to the function's closing brace
|
|
|
|
if let Some(unreachable_block) = builder.cached_unreachable_block {
|
|
|
|
builder.cfg.terminate(unreachable_block, source_info,
|
|
|
|
TerminatorKind::Unreachable);
|
|
|
|
}
|
2016-09-25 01:38:27 +02:00
|
|
|
return_block.unit()
|
2016-04-15 17:11:24 +03:00
|
|
|
}));
|
|
|
|
assert_eq!(block, builder.return_block());
|
|
|
|
|
2016-09-26 22:44:01 +02:00
|
|
|
let mut spread_arg = None;
|
2016-11-10 16:49:53 +02:00
|
|
|
if abi == Abi::RustCall {
|
|
|
|
// RustCall pseudo-ABI untuples the last argument.
|
|
|
|
spread_arg = Some(Local::new(arguments.len()));
|
2016-04-15 17:11:24 +03:00
|
|
|
}
|
2019-03-04 09:00:30 +01:00
|
|
|
info!("fn_id {:?} has attrs {:?}", fn_def_id,
|
|
|
|
tcx.get_attrs(fn_def_id));
|
2016-03-22 16:05:28 -04:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
let mut body = builder.finish();
|
2019-06-03 18:26:48 -04:00
|
|
|
body.spread_arg = spread_arg;
|
|
|
|
body
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2019-06-01 13:38:36 +02:00
|
|
|
fn construct_const<'a, 'tcx>(
|
|
|
|
hir: Cx<'a, 'tcx>,
|
2018-09-15 15:45:12 +01:00
|
|
|
body_id: hir::BodyId,
|
2019-03-30 13:00:41 +00:00
|
|
|
const_ty: Ty<'tcx>,
|
|
|
|
const_ty_span: Span,
|
2019-05-17 23:55:04 +02:00
|
|
|
) -> Body<'tcx> {
|
2016-05-02 23:11:19 +03:00
|
|
|
let tcx = hir.tcx();
|
2018-12-04 13:45:36 +01:00
|
|
|
let owner_id = tcx.hir().body_owner(body_id);
|
2019-06-14 18:58:55 +02:00
|
|
|
let span = tcx.hir().span(owner_id);
|
2019-03-30 13:00:41 +00:00
|
|
|
let mut builder = Builder::new(
|
|
|
|
hir,
|
|
|
|
span,
|
|
|
|
0,
|
|
|
|
Safety::Safe,
|
|
|
|
const_ty,
|
|
|
|
const_ty_span,
|
2019-11-25 12:58:40 +00:00
|
|
|
None,
|
2019-03-30 13:00:41 +00:00
|
|
|
);
|
2016-05-02 23:11:19 +03:00
|
|
|
|
|
|
|
let mut block = START_BLOCK;
|
2019-03-30 13:00:41 +00:00
|
|
|
let ast_expr = &tcx.hir().body(body_id).value;
|
2017-05-07 17:30:55 +03:00
|
|
|
let expr = builder.hir.mirror(ast_expr);
|
2019-10-09 20:06:15 +01:00
|
|
|
unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
|
2016-05-02 23:11:19 +03:00
|
|
|
|
2017-05-07 17:30:55 +03:00
|
|
|
let source_info = builder.source_info(span);
|
|
|
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
2016-05-02 23:11:19 +03:00
|
|
|
|
2017-05-07 17:30:55 +03:00
|
|
|
// Constants can't `return` so a return block should not be created.
|
|
|
|
assert_eq!(builder.cached_return_block, None);
|
2016-05-02 23:11:19 +03:00
|
|
|
|
2017-12-20 14:54:50 +02:00
|
|
|
// Constants may be match expressions in which case an unreachable block may
|
|
|
|
// be created, so terminate it properly.
|
|
|
|
if let Some(unreachable_block) = builder.cached_unreachable_block {
|
|
|
|
builder.cfg.terminate(unreachable_block, source_info,
|
|
|
|
TerminatorKind::Unreachable);
|
|
|
|
}
|
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
builder.finish()
|
2016-05-02 23:11:19 +03:00
|
|
|
}
|
|
|
|
|
2019-06-01 13:38:36 +02:00
|
|
|
fn construct_error<'a, 'tcx>(
|
|
|
|
hir: Cx<'a, 'tcx>,
|
|
|
|
body_id: hir::BodyId
|
|
|
|
) -> Body<'tcx> {
|
2018-12-04 13:45:36 +01:00
|
|
|
let owner_id = hir.tcx().hir().body_owner(body_id);
|
2019-06-14 18:58:55 +02:00
|
|
|
let span = hir.tcx().hir().span(owner_id);
|
2017-02-15 15:00:20 +02:00
|
|
|
let ty = hir.tcx().types.err;
|
2019-11-25 12:58:40 +00:00
|
|
|
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None);
|
2017-02-15 15:00:20 +02:00
|
|
|
let source_info = builder.source_info(span);
|
|
|
|
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
2018-05-16 18:58:54 +03:00
|
|
|
builder.finish()
|
2017-02-15 15:00:20 +02:00
|
|
|
}
|
|
|
|
|
2019-06-01 13:38:36 +02:00
|
|
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|
|
|
fn new(hir: Cx<'a, 'tcx>,
|
2016-09-25 01:38:27 +02:00
|
|
|
span: Span,
|
|
|
|
arg_count: usize,
|
2017-09-19 16:20:02 +03:00
|
|
|
safety: Safety,
|
2018-07-15 15:00:58 +01:00
|
|
|
return_ty: Ty<'tcx>,
|
2018-09-15 15:45:12 +01:00
|
|
|
return_span: Span,
|
2019-11-25 12:58:40 +00:00
|
|
|
generator_kind: Option<GeneratorKind>)
|
2019-06-01 13:38:36 +02:00
|
|
|
-> Builder<'a, 'tcx> {
|
2017-09-13 22:33:07 +03:00
|
|
|
let lint_level = LintLevel::Explicit(hir.root_lint_level);
|
2016-04-15 17:11:24 +03:00
|
|
|
let mut builder = Builder {
|
2017-08-06 22:54:09 -07:00
|
|
|
hir,
|
2016-06-07 17:28:36 +03:00
|
|
|
cfg: CFG { basic_blocks: IndexVec::new() },
|
2016-04-15 17:11:24 +03:00
|
|
|
fn_span: span,
|
2017-08-06 22:54:09 -07:00
|
|
|
arg_count,
|
2019-11-25 12:58:40 +00:00
|
|
|
generator_kind,
|
2019-06-15 17:37:19 +01:00
|
|
|
scopes: Default::default(),
|
2018-11-08 14:31:12 +01:00
|
|
|
block_context: BlockContext::new(),
|
2018-05-28 14:16:09 +03:00
|
|
|
source_scopes: IndexVec::new(),
|
|
|
|
source_scope: OUTERMOST_SOURCE_SCOPE,
|
2018-05-28 17:37:48 +03:00
|
|
|
source_scope_local_data: IndexVec::new(),
|
2018-02-26 15:45:13 +01:00
|
|
|
guard_context: vec![],
|
2017-09-19 16:20:02 +03:00
|
|
|
push_unsafe_count: 0,
|
|
|
|
unpushed_unsafe: safety,
|
2018-09-15 15:45:12 +01:00
|
|
|
local_decls: IndexVec::from_elem_n(
|
|
|
|
LocalDecl::new_return_place(return_ty, return_span),
|
|
|
|
1,
|
|
|
|
),
|
2018-11-16 22:56:18 +01:00
|
|
|
canonical_user_type_annotations: IndexVec::new(),
|
2018-05-16 18:58:54 +03:00
|
|
|
upvar_mutbls: vec![],
|
2018-07-21 22:15:11 +03:00
|
|
|
var_indices: Default::default(),
|
2016-04-15 17:11:24 +03:00
|
|
|
unit_temp: None,
|
2018-05-16 18:58:54 +03:00
|
|
|
var_debug_info: vec![],
|
2016-04-15 17:11:24 +03:00
|
|
|
cached_resume_block: None,
|
2017-11-13 23:08:12 +00:00
|
|
|
cached_return_block: None,
|
|
|
|
cached_unreachable_block: None,
|
2016-04-15 17:11:24 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
2017-09-13 22:33:07 +03:00
|
|
|
assert_eq!(
|
2018-05-28 14:16:09 +03:00
|
|
|
builder.new_source_scope(span, lint_level, Some(safety)),
|
|
|
|
OUTERMOST_SOURCE_SCOPE);
|
|
|
|
builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
|
2016-04-15 17:11:24 +03:00
|
|
|
|
|
|
|
builder
|
|
|
|
}
|
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
fn finish(self) -> Body<'tcx> {
|
2016-04-15 17:11:24 +03:00
|
|
|
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
|
|
|
if block.terminator.is_none() {
|
|
|
|
span_bug!(self.fn_span, "no terminator on block {:?}", index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
Body::new(
|
2018-11-24 14:38:31 +01:00
|
|
|
self.cfg.basic_blocks,
|
|
|
|
self.source_scopes,
|
|
|
|
ClearCrossCrate::Set(self.source_scope_local_data),
|
|
|
|
self.local_decls,
|
2018-11-16 22:56:18 +01:00
|
|
|
self.canonical_user_type_annotations,
|
2018-11-24 14:38:31 +01:00
|
|
|
self.arg_count,
|
2018-05-16 18:58:54 +03:00
|
|
|
self.var_debug_info,
|
2018-11-24 14:38:31 +01:00
|
|
|
self.fn_span,
|
2018-11-26 09:35:23 +01:00
|
|
|
self.hir.control_flow_destroyed(),
|
2019-11-25 12:58:40 +00:00
|
|
|
self.generator_kind
|
2016-11-03 14:22:57 +11:00
|
|
|
)
|
2016-04-15 17:11:24 +03:00
|
|
|
}
|
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
fn args_and_body(&mut self,
|
|
|
|
mut block: BasicBlock,
|
2018-05-16 18:58:54 +03:00
|
|
|
fn_def_id: DefId,
|
2019-06-01 13:38:36 +02:00
|
|
|
arguments: &[ArgInfo<'tcx>],
|
2017-08-31 21:37:38 +03:00
|
|
|
argument_scope: region::Scope,
|
2019-06-01 13:38:36 +02:00
|
|
|
ast_body: &'tcx hir::Expr)
|
2016-09-25 01:38:27 +02:00
|
|
|
-> BlockAnd<()>
|
2015-08-18 17:59:21 -04:00
|
|
|
{
|
2016-09-25 01:38:27 +02:00
|
|
|
// Allocate locals for the function arguments
|
2019-07-26 19:52:37 -03:00
|
|
|
for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
|
2018-05-16 18:58:54 +03:00
|
|
|
let source_info = SourceInfo {
|
|
|
|
scope: OUTERMOST_SOURCE_SCOPE,
|
|
|
|
span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span)
|
2018-05-29 12:24:53 +03:00
|
|
|
};
|
2018-05-16 18:58:54 +03:00
|
|
|
let arg_local = self.local_decls.push(LocalDecl {
|
2017-11-30 23:19:06 +00:00
|
|
|
mutability: Mutability::Mut,
|
2017-08-06 22:54:09 -07:00
|
|
|
ty,
|
2018-10-22 14:23:44 +02:00
|
|
|
user_ty: UserTypeProjections::none(),
|
2018-05-29 21:31:33 +03:00
|
|
|
source_info,
|
2017-07-15 22:41:33 +02:00
|
|
|
internal: false,
|
2019-11-18 23:04:06 +00:00
|
|
|
local_info: LocalInfo::Other,
|
2018-09-22 00:51:48 +02:00
|
|
|
is_block_tail: None,
|
2016-09-25 01:38:27 +02:00
|
|
|
});
|
2018-05-16 18:58:54 +03:00
|
|
|
|
|
|
|
// If this is a simple binding pattern, give debuginfo a nice name.
|
|
|
|
if let Some(arg) = arg_opt {
|
|
|
|
if let Some(ident) = arg.pat.simple_ident() {
|
|
|
|
self.var_debug_info.push(VarDebugInfo {
|
|
|
|
name: ident.name,
|
|
|
|
source_info,
|
|
|
|
place: arg_local.into(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let tcx = self.hir.tcx();
|
|
|
|
let tcx_hir = tcx.hir();
|
|
|
|
let hir_tables = self.hir.tables();
|
|
|
|
|
|
|
|
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
|
|
|
|
// closure and we stored in a map called upvar_list in TypeckTables indexed
|
|
|
|
// with the closure's DefId. Here, we run through that vec of UpvarIds for
|
|
|
|
// the given closure and use the necessary information to create upvar
|
|
|
|
// debuginfo and to fill `self.upvar_mutbls`.
|
|
|
|
if let Some(upvars) = hir_tables.upvar_list.get(&fn_def_id) {
|
|
|
|
let closure_env_arg = Local::new(1);
|
|
|
|
let mut closure_env_projs = vec![];
|
|
|
|
let mut closure_ty = self.local_decls[closure_env_arg].ty;
|
|
|
|
if let ty::Ref(_, ty, _) = closure_ty.kind {
|
|
|
|
closure_env_projs.push(ProjectionElem::Deref);
|
|
|
|
closure_ty = ty;
|
|
|
|
}
|
|
|
|
let (def_id, upvar_substs) = match closure_ty.kind {
|
|
|
|
ty::Closure(def_id, substs) => (def_id, ty::UpvarSubsts::Closure(substs)),
|
|
|
|
ty::Generator(def_id, substs, _) => (def_id, ty::UpvarSubsts::Generator(substs)),
|
|
|
|
_ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty)
|
|
|
|
};
|
|
|
|
let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
|
|
|
|
let upvars_with_tys = upvars.iter().zip(upvar_tys);
|
|
|
|
self.upvar_mutbls = upvars_with_tys.enumerate().map(|(i, ((&var_id, &upvar_id), ty))| {
|
|
|
|
let capture = hir_tables.upvar_capture(upvar_id);
|
|
|
|
|
|
|
|
let mut mutability = Mutability::Not;
|
|
|
|
let mut name = kw::Invalid;
|
|
|
|
if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
|
|
|
|
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
|
|
|
|
name = ident.name;
|
|
|
|
|
|
|
|
if let Some(&bm) = hir_tables.pat_binding_modes().get(pat.hir_id) {
|
|
|
|
if bm == ty::BindByValue(hir::Mutability::Mutable) {
|
|
|
|
mutability = Mutability::Mut;
|
|
|
|
} else {
|
|
|
|
mutability = Mutability::Not;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut projs = closure_env_projs.clone();
|
|
|
|
projs.push(ProjectionElem::Field(Field::new(i), ty));
|
|
|
|
match capture {
|
|
|
|
ty::UpvarCapture::ByValue => {}
|
|
|
|
ty::UpvarCapture::ByRef(..) => {
|
|
|
|
projs.push(ProjectionElem::Deref);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.var_debug_info.push(VarDebugInfo {
|
|
|
|
name,
|
|
|
|
source_info: SourceInfo {
|
|
|
|
scope: OUTERMOST_SOURCE_SCOPE,
|
|
|
|
span: tcx_hir.span(var_id),
|
|
|
|
},
|
|
|
|
place: Place {
|
|
|
|
base: closure_env_arg.into(),
|
|
|
|
projection: tcx.intern_place_elems(&projs),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
mutability
|
|
|
|
}).collect();
|
2016-09-25 01:38:27 +02:00
|
|
|
}
|
|
|
|
|
2016-05-31 20:27:36 +03:00
|
|
|
let mut scope = None;
|
2016-09-25 01:38:27 +02:00
|
|
|
// Bind the argument patterns
|
2018-06-07 17:05:58 +02:00
|
|
|
for (index, arg_info) in arguments.iter().enumerate() {
|
2017-12-01 14:39:51 +02:00
|
|
|
// Function arguments always get the first Local indices after the return place
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 20:49:36 +02:00
|
|
|
let local = Local::new(index + 1);
|
2019-06-24 17:46:09 +02:00
|
|
|
let place = Place::from(local);
|
2019-09-29 15:08:57 +01:00
|
|
|
let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info;
|
2016-09-25 01:38:27 +02:00
|
|
|
|
2018-11-18 14:49:24 +00:00
|
|
|
// Make sure we drop (parts of) the argument even when not matched on.
|
|
|
|
self.schedule_drop(
|
2019-07-26 19:52:37 -03:00
|
|
|
arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
|
2019-09-29 15:08:57 +01:00
|
|
|
argument_scope, local, DropKind::Value,
|
2018-11-18 14:49:24 +00:00
|
|
|
);
|
|
|
|
|
2019-07-26 19:52:37 -03:00
|
|
|
if let Some(arg) = arg_opt {
|
|
|
|
let pattern = self.hir.pattern_from_hir(&arg.pat);
|
|
|
|
let original_source_scope = self.source_scope;
|
2018-06-27 22:06:54 +01:00
|
|
|
let span = pattern.span;
|
2019-07-26 19:52:37 -03:00
|
|
|
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 20:49:36 +02:00
|
|
|
match *pattern.kind {
|
|
|
|
// Don't introduce extra copies for simple bindings
|
2019-09-26 18:42:24 +01:00
|
|
|
PatKind::Binding {
|
2019-06-02 19:03:17 +01:00
|
|
|
mutability,
|
|
|
|
var,
|
|
|
|
mode: BindingMode::ByValue,
|
|
|
|
subpattern: None,
|
|
|
|
..
|
|
|
|
} => {
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 20:49:36 +02:00
|
|
|
self.local_decls[local].mutability = mutability;
|
2019-07-26 19:52:37 -03:00
|
|
|
self.local_decls[local].source_info.scope = self.source_scope;
|
2019-11-18 23:04:06 +00:00
|
|
|
self.local_decls[local].local_info =
|
2018-10-01 17:46:04 +02:00
|
|
|
if let Some(kind) = self_binding {
|
2019-11-18 23:04:06 +00:00
|
|
|
LocalInfo::User(ClearCrossCrate::Set(
|
|
|
|
BindingForm::ImplicitSelf(*kind),
|
|
|
|
))
|
2018-06-07 17:05:58 +02:00
|
|
|
} else {
|
|
|
|
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
|
2019-11-18 23:04:06 +00:00
|
|
|
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
|
|
|
VarBindingForm {
|
|
|
|
binding_mode,
|
|
|
|
opt_ty_info,
|
|
|
|
opt_match_place: Some((Some(place.clone()), span)),
|
|
|
|
pat_span: span,
|
|
|
|
},
|
|
|
|
)))
|
2018-06-07 17:05:58 +02:00
|
|
|
};
|
2018-02-26 15:45:13 +01:00
|
|
|
self.var_indices.insert(var, LocalsForNode::One(local));
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 20:49:36 +02:00
|
|
|
}
|
|
|
|
_ => {
|
2019-04-02 22:29:28 +01:00
|
|
|
scope = self.declare_bindings(
|
|
|
|
scope,
|
|
|
|
ast_body.span,
|
|
|
|
&pattern,
|
|
|
|
matches::ArmHasGuard(false),
|
|
|
|
Some((Some(&place), span)),
|
|
|
|
);
|
2018-06-27 22:06:54 +01:00
|
|
|
unpack!(block = self.place_into_pattern(block, pattern, &place, false));
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 20:49:36 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-26 19:52:37 -03:00
|
|
|
self.source_scope = original_source_scope;
|
2016-04-15 17:11:24 +03:00
|
|
|
}
|
2016-09-25 01:38:27 +02:00
|
|
|
}
|
2016-03-23 12:26:37 -04:00
|
|
|
|
2018-05-28 14:16:09 +03:00
|
|
|
// Enter the argument pattern bindings source scope, if it exists.
|
|
|
|
if let Some(source_scope) = scope {
|
|
|
|
self.source_scope = source_scope;
|
2016-05-31 20:27:36 +03:00
|
|
|
}
|
|
|
|
|
2016-10-26 02:27:14 +03:00
|
|
|
let body = self.hir.mirror(ast_body);
|
2019-10-09 20:06:15 +01:00
|
|
|
self.into(&Place::return_place(), block, body)
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
2016-01-16 00:36:32 +02:00
|
|
|
|
2019-07-26 19:52:37 -03:00
|
|
|
fn set_correct_source_scope_for_arg(
|
|
|
|
&mut self,
|
|
|
|
arg_hir_id: hir::HirId,
|
|
|
|
original_source_scope: SourceScope,
|
|
|
|
pattern_span: Span
|
|
|
|
) {
|
|
|
|
let tcx = self.hir.tcx();
|
|
|
|
let current_root = tcx.maybe_lint_level_root_bounded(
|
|
|
|
arg_hir_id,
|
|
|
|
self.hir.root_lint_level
|
|
|
|
);
|
|
|
|
let parent_root = tcx.maybe_lint_level_root_bounded(
|
|
|
|
self.source_scope_local_data[original_source_scope].lint_root,
|
|
|
|
self.hir.root_lint_level,
|
|
|
|
);
|
|
|
|
if current_root != parent_root {
|
|
|
|
self.source_scope = self.new_source_scope(
|
|
|
|
pattern_span,
|
|
|
|
LintLevel::Explicit(current_root),
|
|
|
|
None
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:31:47 +02:00
|
|
|
fn get_unit_temp(&mut self) -> Place<'tcx> {
|
2016-01-16 00:36:32 +02:00
|
|
|
match self.unit_temp {
|
|
|
|
Some(ref tmp) => tmp.clone(),
|
|
|
|
None => {
|
|
|
|
let ty = self.hir.unit_ty();
|
2017-04-11 23:52:51 +03:00
|
|
|
let fn_span = self.fn_span;
|
|
|
|
let tmp = self.temp(ty, fn_span);
|
2016-01-16 00:36:32 +02:00
|
|
|
self.unit_temp = Some(tmp.clone());
|
|
|
|
tmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-20 00:13:30 +03:00
|
|
|
|
|
|
|
fn return_block(&mut self) -> BasicBlock {
|
|
|
|
match self.cached_return_block {
|
|
|
|
Some(rb) => rb,
|
|
|
|
None => {
|
|
|
|
let rb = self.cfg.start_new_block();
|
|
|
|
self.cached_return_block = Some(rb);
|
|
|
|
rb
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Builder methods are broken up into modules, depending on what kind
|
2018-05-08 16:10:16 +03:00
|
|
|
// of thing is being lowered. Note that they use the `unpack` macro
|
2015-08-18 17:59:21 -04:00
|
|
|
// above extensively.
|
|
|
|
|
|
|
|
mod block;
|
|
|
|
mod cfg;
|
|
|
|
mod expr;
|
|
|
|
mod into;
|
|
|
|
mod matches;
|
|
|
|
mod misc;
|
|
|
|
mod scope;
|