2021-02-19 00:02:07 +00:00
|
|
|
use crate::build::expr::as_place::PlaceBuilder;
|
2019-05-30 20:21:17 +00:00
|
|
|
use crate::build::scope::DropKind;
|
2022-06-03 18:42:35 +00:00
|
|
|
use rustc_apfloat::ieee::{Double, Single};
|
2022-06-07 17:29:13 +00:00
|
|
|
use rustc_apfloat::Float;
|
2023-03-19 17:32:34 +00:00
|
|
|
use rustc_ast::attr;
|
2022-06-07 17:29:13 +00:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2022-08-23 20:22:15 +00:00
|
|
|
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
|
2022-01-23 18:34:26 +00:00
|
|
|
use rustc_errors::ErrorGuaranteed;
|
2020-01-05 01:37:57 +00:00
|
|
|
use rustc_hir as hir;
|
2022-08-22 20:29:25 +00:00
|
|
|
use rustc_hir::def::DefKind;
|
2020-04-09 08:43:00 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
2023-10-19 16:06:43 +00:00
|
|
|
use rustc_hir::{CoroutineKind, Node};
|
2023-07-11 23:55:39 +00:00
|
|
|
use rustc_index::bit_set::GrowableBitSet;
|
2023-04-19 10:57:17 +00:00
|
|
|
use rustc_index::{Idx, IndexSlice, IndexVec};
|
2021-03-03 15:35:54 +00:00
|
|
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
2020-11-26 05:07:41 +00:00
|
|
|
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
|
2020-03-31 19:38:14 +00:00
|
|
|
use rustc_middle::middle::region;
|
2022-06-03 18:42:35 +00:00
|
|
|
use rustc_middle::mir::interpret::Scalar;
|
2020-03-31 19:38:14 +00:00
|
|
|
use rustc_middle::mir::*;
|
2022-08-22 20:29:25 +00:00
|
|
|
use rustc_middle::thir::{
|
|
|
|
self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
|
|
|
|
};
|
2022-10-25 17:59:18 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
2021-05-15 11:01:13 +00:00
|
|
|
use rustc_span::symbol::sym;
|
2019-12-31 17:15:40 +00:00
|
|
|
use rustc_span::Span;
|
2022-02-16 09:56:01 +00:00
|
|
|
use rustc_span::Symbol;
|
2023-03-28 19:32:57 +00:00
|
|
|
use rustc_target::abi::FieldIdx;
|
2019-12-24 22:38:22 +00:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2015-10-05 16:31:48 +00:00
|
|
|
|
2018-09-12 01:35:08 +00:00
|
|
|
use super::lints;
|
|
|
|
|
2022-12-20 21:10:40 +00:00
|
|
|
pub(crate) fn mir_built(
|
|
|
|
tcx: TyCtxt<'_>,
|
2022-05-08 13:53:19 +00:00
|
|
|
def: LocalDefId,
|
2022-12-20 21:10:40 +00:00
|
|
|
) -> &rustc_data_structures::steal::Steal<Body<'_>> {
|
2022-05-08 13:53:19 +00:00
|
|
|
tcx.alloc_steal_mir(mir_build(tcx, def))
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
2023-06-18 07:55:04 +00:00
|
|
|
pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
def_id: LocalDefId,
|
|
|
|
) -> IndexVec<FieldIdx, Symbol> {
|
|
|
|
tcx.closure_captures(def_id)
|
|
|
|
.iter()
|
|
|
|
.map(|captured_place| {
|
|
|
|
let name = captured_place.to_symbol();
|
|
|
|
match captured_place.info.capture_kind {
|
|
|
|
ty::UpvarCapture::ByValue => name,
|
|
|
|
ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// Construct the MIR for a given `DefId`.
|
2023-10-05 14:57:14 +00:00
|
|
|
fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
|
2022-05-08 13:53:19 +00:00
|
|
|
tcx.ensure_with_value().thir_abstract_const(def);
|
2023-04-30 15:31:36 +00:00
|
|
|
if let Err(e) = tcx.check_match(def) {
|
|
|
|
return construct_error(tcx, def, e);
|
|
|
|
}
|
2021-05-13 21:36:19 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
let body = match tcx.thir_body(def) {
|
2022-05-08 13:53:19 +00:00
|
|
|
Err(error_reported) => construct_error(tcx, def, error_reported),
|
2022-08-27 12:40:39 +00:00
|
|
|
Ok((thir, expr)) => {
|
2023-10-05 14:57:14 +00:00
|
|
|
let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
|
|
|
|
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
|
|
|
|
thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
|
|
|
|
};
|
2018-11-30 17:17:50 +00:00
|
|
|
|
2023-02-16 10:06:59 +00:00
|
|
|
// this must run before MIR dump, because
|
|
|
|
// "not all control paths return a value" is reported here.
|
|
|
|
//
|
|
|
|
// maybe move the check to a MIR pass?
|
|
|
|
tcx.ensure().check_liveness(def);
|
|
|
|
|
2023-10-05 14:57:14 +00:00
|
|
|
if tcx.sess.opts.unstable_opts.thir_unsafeck {
|
|
|
|
// Don't steal here if THIR unsafeck is being used. Instead
|
|
|
|
// steal in unsafeck. This is so that pattern inline constants
|
|
|
|
// can be evaluated as part of building the THIR of the parent
|
|
|
|
// function without a cycle.
|
|
|
|
build_mir(&thir.borrow())
|
|
|
|
} else {
|
|
|
|
// We ran all queries that depended on THIR at the beginning
|
|
|
|
// of `mir_build`, so now we can steal it
|
|
|
|
build_mir(&thir.steal())
|
2021-01-17 12:27:05 +00:00
|
|
|
}
|
2022-08-27 12:40:39 +00:00
|
|
|
}
|
|
|
|
};
|
2017-05-02 18:56:26 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
lints::check(tcx, &body);
|
|
|
|
|
|
|
|
// The borrow checker will replace all the regions here with its own
|
|
|
|
// inference variables. There's no point having non-erased regions here.
|
|
|
|
// The exception is `body.user_type_annotations`, which is used unmodified
|
|
|
|
// by borrow checking.
|
|
|
|
debug_assert!(
|
|
|
|
!(body.local_decls.has_free_regions()
|
|
|
|
|| body.basic_blocks.has_free_regions()
|
|
|
|
|| body.var_debug_info.has_free_regions()
|
|
|
|
|| body.yield_ty().has_free_regions()),
|
2023-07-25 21:17:39 +00:00
|
|
|
"Unexpected free regions in MIR: {body:?}",
|
2022-08-27 12:40:39 +00:00
|
|
|
);
|
2020-03-19 11:40:38 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
body
|
2017-05-02 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
|
|
|
|
|
2018-09-21 22:51:48 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
2020-01-05 15:46:44 +00:00
|
|
|
enum BlockFrame {
|
2018-09-21 22:51:48 +00:00
|
|
|
/// 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-21 22:51:48 +00:00
|
|
|
Statement {
|
|
|
|
/// If true, then statement discards result from evaluating
|
|
|
|
/// the expression (such as examples 1 and 2 above).
|
2019-12-24 22:38:22 +00:00
|
|
|
ignores_expr_result: bool,
|
2018-09-21 22:51:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/// 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 };`
|
2019-12-24 22:38:22 +00:00
|
|
|
tail_result_is_ignored: bool,
|
2020-04-16 19:43:40 +00:00
|
|
|
|
|
|
|
/// `Span` of the tail expression.
|
|
|
|
span: Span,
|
2018-09-21 22:51:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
BlockFrame::Statement { .. } | BlockFrame::SubExpr => false,
|
2018-09-21 22:51:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fn is_statement(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
BlockFrame::Statement { .. } => true,
|
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false,
|
2018-09-21 22:51:48 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-24 22:38:22 +00:00
|
|
|
}
|
2018-09-21 22:51:48 +00:00
|
|
|
|
2018-11-08 13:31:12 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct BlockContext(Vec<BlockFrame>);
|
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
struct Builder<'a, 'tcx> {
|
2021-03-03 15:35:54 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-09-09 18:01:06 +00:00
|
|
|
infcx: InferCtxt<'tcx>,
|
2022-05-25 05:52:32 +00:00
|
|
|
region_scope_tree: &'tcx region::ScopeTree,
|
2021-03-03 15:35:54 +00:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
|
2021-04-03 17:58:46 +00:00
|
|
|
thir: &'a Thir<'tcx>,
|
2015-10-05 16:31:48 +00:00
|
|
|
cfg: CFG<'tcx>,
|
2016-03-09 16:04:26 +00:00
|
|
|
|
2022-05-08 13:53:19 +00:00
|
|
|
def_id: LocalDefId,
|
2021-03-03 15:35:54 +00:00
|
|
|
hir_id: hir::HirId,
|
2022-01-25 00:00:00 +00:00
|
|
|
parent_module: DefId,
|
2021-03-03 15:35:54 +00:00
|
|
|
check_overflow: bool,
|
2016-03-23 00:41:07 +00:00
|
|
|
fn_span: Span,
|
2016-09-24 23:38:27 +00:00
|
|
|
arg_count: usize,
|
2023-10-19 21:46:28 +00:00
|
|
|
coroutine_kind: Option<CoroutineKind>,
|
2016-03-23 00:41:07 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// The current set of scopes, updated as we traverse;
|
|
|
|
/// see the `scope` module for more details.
|
2019-06-15 16:37:19 +00:00
|
|
|
scopes: scope::Scopes<'tcx>,
|
2016-03-09 16:04:26 +00:00
|
|
|
|
2020-07-21 09:09:27 +00:00
|
|
|
/// The block-context: each time we build the code within an thir::Block,
|
2018-09-21 22:51:48 +00: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 13:53:55 +00:00
|
|
|
/// somehow, but right now I think that is very tightly tied to
|
2018-09-21 22:51:48 +00: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 13:53:55 +00:00
|
|
|
/// `{ STMTS; EXPR1 } + EXPR2`.
|
2018-11-08 13:31:12 +00:00
|
|
|
block_context: BlockContext,
|
2018-09-21 22:51:48 +00:00
|
|
|
|
2021-05-17 21:19:48 +00:00
|
|
|
/// The current unsafe block in scope
|
|
|
|
in_scope_unsafe: Safety,
|
2017-09-19 13:20:02 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// The vector of all scopes that we have created thus far;
|
|
|
|
/// we track this for debuginfo later.
|
2020-02-08 19:31:09 +00:00
|
|
|
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
|
2018-05-28 11:16:09 +00:00
|
|
|
source_scope: SourceScope,
|
2016-03-09 16:04:26 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// The guard-context: each time we build the guard expression for
|
2018-02-26 14:45:13 +00:00
|
|
|
/// a match arm, we push onto this stack, and then pop when we
|
|
|
|
/// finish building it.
|
|
|
|
guard_context: Vec<GuardFrame>,
|
|
|
|
|
2019-03-10 12:22:00 +00:00
|
|
|
/// Maps `HirId`s of variable bindings to the `Local`s created for them.
|
2018-02-26 14:45:13 +00:00
|
|
|
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
|
2022-06-08 12:23:07 +00:00
|
|
|
var_indices: FxHashMap<LocalVarId, LocalsForNode>,
|
2016-09-24 23:38:27 +00:00
|
|
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
2018-11-16 21:56:18 +00:00
|
|
|
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
2022-08-23 20:22:15 +00:00
|
|
|
upvars: CaptureMap<'tcx>,
|
2017-12-01 12:31:47 +00:00
|
|
|
unit_temp: Option<Place<'tcx>>,
|
2016-03-24 00:46:38 +00:00
|
|
|
|
2018-05-16 15:58:54 +00:00
|
|
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
2023-07-11 23:55:39 +00:00
|
|
|
|
|
|
|
// A cache for `maybe_lint_level_roots_bounded`. That function is called
|
|
|
|
// repeatedly, and each time it effectively traces a path through a tree
|
|
|
|
// structure from a node towards the root, doing an attribute check on each
|
|
|
|
// node along the way. This cache records which nodes trace all the way to
|
|
|
|
// the root (most of them do) and saves us from retracing many sub-paths
|
|
|
|
// many times, and rechecking many nodes.
|
|
|
|
lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2022-08-23 20:22:15 +00:00
|
|
|
type CaptureMap<'tcx> = SortedIndexMultiMap<usize, hir::HirId, Capture<'tcx>>;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Capture<'tcx> {
|
|
|
|
captured_place: &'tcx ty::CapturedPlace<'tcx>,
|
|
|
|
use_place: Place<'tcx>,
|
|
|
|
mutability: Mutability,
|
|
|
|
}
|
|
|
|
|
2019-06-01 11:38:36 +00:00
|
|
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
2022-06-08 12:23:07 +00:00
|
|
|
fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
|
2018-02-26 14:45:13 +00:00
|
|
|
self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
|
|
|
|
}
|
|
|
|
|
2022-06-08 12:23:07 +00:00
|
|
|
fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local {
|
2018-02-26 14:45:13 +00:00
|
|
|
self.var_indices[&id].local_id(for_guard)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-08 13:31:12 +00:00
|
|
|
impl BlockContext {
|
2019-12-24 22:38:22 +00:00
|
|
|
fn new() -> Self {
|
|
|
|
BlockContext(vec![])
|
|
|
|
}
|
|
|
|
fn push(&mut self, bf: BlockFrame) {
|
|
|
|
self.0.push(bf);
|
|
|
|
}
|
|
|
|
fn pop(&mut self) -> Option<BlockFrame> {
|
|
|
|
self.0.pop()
|
|
|
|
}
|
2018-11-08 13:31:12 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// Traverses the frames on the `BlockContext`, searching for either
|
2018-11-08 13:31:12 +00: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,
|
2020-04-16 19:43:40 +00:00
|
|
|
&BlockFrame::TailExpr { tail_result_is_ignored, span } => {
|
|
|
|
return Some(BlockTailInfo { tail_result_is_ignored, span });
|
2019-12-24 22:38:22 +00:00
|
|
|
}
|
2018-11-08 13:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 14:03:11 +00:00
|
|
|
None
|
2018-11-08 13:31:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2020-04-17 00:38:52 +00:00
|
|
|
Some(
|
2020-04-16 19:43:40 +00:00
|
|
|
BlockFrame::TailExpr { tail_result_is_ignored: ignored, .. }
|
2020-04-17 00:38:52 +00:00
|
|
|
| BlockFrame::Statement { ignores_expr_result: ignored },
|
|
|
|
) => *ignored,
|
2018-11-08 13:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 14:45:13 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum LocalsForNode {
|
2019-03-10 12:22:00 +00:00
|
|
|
/// In the usual case, a `HirId` for an identifier maps to at most
|
2019-02-08 13:53:55 +00:00
|
|
|
/// one `Local` declaration.
|
2018-02-26 14:45:13 +00:00
|
|
|
One(Local),
|
2018-07-26 11:14:12 +00: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 11:14:12 +00: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 14:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct GuardFrameLocal {
|
2022-06-08 12:23:07 +00:00
|
|
|
id: LocalVarId,
|
2018-02-26 14:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GuardFrameLocal {
|
2022-06-08 12:23:07 +00:00
|
|
|
fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
|
2020-03-06 18:28:44 +00:00
|
|
|
GuardFrameLocal { id }
|
2018-02-26 14:45:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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 13:53:55 +00:00
|
|
|
/// here, when building for FIXME.
|
2018-02-26 14:45:13 +00:00
|
|
|
locals: Vec<GuardFrameLocal>,
|
|
|
|
}
|
|
|
|
|
2019-02-08 13:53:55 +00: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 14:45:13 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum ForGuard {
|
2018-05-11 21:32:13 +00:00
|
|
|
RefWithinGuard,
|
2018-02-26 14:45:13 +00:00
|
|
|
OutsideGuard,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LocalsForNode {
|
|
|
|
fn local_id(&self, for_guard: ForGuard) -> Local {
|
|
|
|
match (self, for_guard) {
|
2019-12-24 22:38:22 +00:00
|
|
|
(&LocalsForNode::One(local_id), ForGuard::OutsideGuard)
|
|
|
|
| (
|
|
|
|
&LocalsForNode::ForGuard { ref_for_guard: local_id, .. },
|
|
|
|
ForGuard::RefWithinGuard,
|
|
|
|
)
|
|
|
|
| (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => {
|
|
|
|
local_id
|
|
|
|
}
|
2018-02-26 14:45:13 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
(&LocalsForNode::One(_), ForGuard::RefWithinGuard) => {
|
|
|
|
bug!("anything with one local should never be within a guard.")
|
|
|
|
}
|
2018-02-26 14:45:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:31:48 +00:00
|
|
|
struct CFG<'tcx> {
|
2016-06-07 14:28:36 +00:00
|
|
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2022-12-18 20:47:28 +00:00
|
|
|
struct ScopeId {}
|
2018-07-25 10:41:32 +00:00
|
|
|
}
|
2016-05-31 17:27:36 +00:00
|
|
|
|
2022-03-09 17:10:48 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum NeedsTemporary {
|
|
|
|
/// Use this variant when whatever you are converting with `as_operand`
|
|
|
|
/// is the last thing you are converting. This means that if we introduced
|
|
|
|
/// an intermediate temporary, we'd only read it immediately after, so we can
|
|
|
|
/// also avoid it.
|
|
|
|
No,
|
|
|
|
/// For all cases where you aren't sure or that are too expensive to compute
|
|
|
|
/// for now. It is always safe to fall back to this.
|
|
|
|
Maybe,
|
|
|
|
}
|
|
|
|
|
2015-08-18 21:59:21 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 12:25:07 +00: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 21:59:21 +00:00
|
|
|
|
2018-03-31 06:06:05 +00:00
|
|
|
#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
|
2017-05-01 15:58:05 +00:00
|
|
|
struct BlockAnd<T>(BasicBlock, T);
|
2015-08-18 21:59:21 +00:00
|
|
|
|
2015-11-19 15:37:34 +00:00
|
|
|
trait BlockAndExtension {
|
|
|
|
fn and<T>(self, v: T) -> BlockAnd<T>;
|
|
|
|
fn unit(self) -> BlockAnd<()>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockAndExtension for BasicBlock {
|
2015-08-18 21:59:21 +00: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 {
|
2019-12-24 22:38:22 +00:00
|
|
|
($x:ident = $c:expr) => {{
|
|
|
|
let BlockAnd(b, v) = $c;
|
|
|
|
$x = b;
|
|
|
|
v
|
|
|
|
}};
|
|
|
|
|
|
|
|
($c:expr) => {{
|
|
|
|
let BlockAnd(b, ()) = $c;
|
|
|
|
b
|
|
|
|
}};
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2016-02-03 12:25:07 +00:00
|
|
|
/// the main entry point for building MIR for a function
|
2015-08-18 21:59:21 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
fn construct_fn<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-05-08 13:53:19 +00:00
|
|
|
fn_def: LocalDefId,
|
2022-08-27 12:40:39 +00:00
|
|
|
thir: &Thir<'tcx>,
|
2021-04-03 17:58:46 +00:00
|
|
|
expr: ExprId,
|
2023-01-22 14:37:16 +00:00
|
|
|
fn_sig: ty::FnSig<'tcx>,
|
2022-08-27 12:40:39 +00:00
|
|
|
) -> Body<'tcx> {
|
2022-05-08 13:53:19 +00:00
|
|
|
let span = tcx.def_span(fn_def);
|
|
|
|
let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def);
|
2023-10-19 21:46:28 +00:00
|
|
|
let coroutine_kind = tcx.coroutine_kind(fn_def);
|
2022-08-27 12:40:39 +00:00
|
|
|
|
2023-01-17 20:13:33 +00:00
|
|
|
// The representation of thir for `-Zunpretty=thir-tree` relies on
|
|
|
|
// the entry expression being the last element of `thir.exprs`.
|
|
|
|
assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
|
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
// Figure out what primary body this item has.
|
2022-05-08 13:53:19 +00:00
|
|
|
let body_id = tcx.hir().body_owned_by(fn_def);
|
2022-08-27 12:40:39 +00:00
|
|
|
let span_with_body = tcx.hir().span_with_body(fn_id);
|
|
|
|
let return_ty_span = tcx
|
|
|
|
.hir()
|
|
|
|
.fn_decl_by_hir_id(fn_id)
|
2022-05-08 13:53:19 +00:00
|
|
|
.unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def))
|
2022-08-27 12:40:39 +00:00
|
|
|
.output
|
|
|
|
.span();
|
|
|
|
|
|
|
|
let safety = match fn_sig.unsafety {
|
|
|
|
hir::Unsafety::Normal => Safety::Safe,
|
|
|
|
hir::Unsafety::Unsafe => Safety::FnUnsafe,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut abi = fn_sig.abi;
|
2022-05-08 13:53:19 +00:00
|
|
|
if let DefKind::Closure = tcx.def_kind(fn_def) {
|
2022-08-22 20:29:25 +00:00
|
|
|
// HACK(eddyb) Avoid having RustCall on closures,
|
|
|
|
// as it adds unnecessary (and wrong) auto-tupling.
|
|
|
|
abi = Abi::Rust;
|
|
|
|
}
|
2022-08-27 12:40:39 +00:00
|
|
|
|
2022-08-22 20:29:25 +00:00
|
|
|
let arguments = &thir.params;
|
2022-08-27 12:40:39 +00:00
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
let (yield_ty, return_ty) = if coroutine_kind.is_some() {
|
2023-10-30 23:35:35 +00:00
|
|
|
let coroutine_ty = arguments[thir::UPVAR_ENV_PARAM].ty;
|
|
|
|
let coroutine_sig = match coroutine_ty.kind() {
|
2023-10-19 21:46:28 +00:00
|
|
|
ty::Coroutine(_, gen_args, ..) => gen_args.as_coroutine().sig(),
|
2022-08-27 12:40:39 +00:00
|
|
|
_ => {
|
2023-10-30 23:35:35 +00:00
|
|
|
span_bug!(span, "coroutine w/o coroutine type: {:?}", coroutine_ty)
|
2022-08-27 12:40:39 +00:00
|
|
|
}
|
|
|
|
};
|
2023-10-30 23:35:35 +00:00
|
|
|
(Some(coroutine_sig.yield_ty), coroutine_sig.return_ty)
|
2022-08-27 12:40:39 +00:00
|
|
|
} else {
|
|
|
|
(None, fn_sig.output())
|
|
|
|
};
|
|
|
|
|
2022-08-03 11:30:13 +00:00
|
|
|
if let Some(custom_mir_attr) =
|
|
|
|
tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
|
|
|
|
{
|
|
|
|
return custom::build_custom_mir(
|
|
|
|
tcx,
|
2022-05-08 13:53:19 +00:00
|
|
|
fn_def.to_def_id(),
|
2022-12-01 23:41:45 +00:00
|
|
|
fn_id,
|
2022-08-03 11:30:13 +00:00
|
|
|
thir,
|
|
|
|
expr,
|
|
|
|
arguments,
|
|
|
|
return_ty,
|
|
|
|
return_ty_span,
|
2022-11-28 05:23:39 +00:00
|
|
|
span_with_body,
|
2022-08-03 11:30:13 +00:00
|
|
|
custom_mir_attr,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
let infcx = tcx.infer_ctxt().build();
|
|
|
|
let mut builder = Builder::new(
|
|
|
|
thir,
|
|
|
|
infcx,
|
|
|
|
fn_def,
|
|
|
|
fn_id,
|
|
|
|
span_with_body,
|
|
|
|
arguments.len(),
|
|
|
|
safety,
|
|
|
|
return_ty,
|
|
|
|
return_ty_span,
|
2023-10-19 21:46:28 +00:00
|
|
|
coroutine_kind,
|
2022-08-27 12:40:39 +00:00
|
|
|
);
|
2022-09-20 03:03:59 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
let call_site_scope =
|
2022-08-22 20:29:25 +00:00
|
|
|
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
|
2022-08-27 12:40:39 +00:00
|
|
|
let arg_scope =
|
2022-08-22 20:29:25 +00:00
|
|
|
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
|
2022-08-27 12:40:39 +00:00
|
|
|
let source_info = builder.source_info(span);
|
|
|
|
let call_site_s = (call_site_scope, source_info);
|
|
|
|
unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
|
|
|
|
let arg_scope_s = (arg_scope, source_info);
|
|
|
|
// Attribute epilogue to function's closing brace
|
|
|
|
let fn_end = span_with_body.shrink_to_hi();
|
|
|
|
let return_block =
|
|
|
|
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
|
|
|
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
2022-10-25 17:59:18 +00:00
|
|
|
builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr])
|
2022-08-27 12:40:39 +00:00
|
|
|
}))
|
|
|
|
}));
|
|
|
|
let source_info = builder.source_info(fn_end);
|
|
|
|
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
|
|
|
|
builder.build_drop_trees();
|
|
|
|
return_block.unit()
|
|
|
|
}));
|
|
|
|
|
|
|
|
let mut body = builder.finish();
|
2016-04-15 14:11:24 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
body.spread_arg = if abi == Abi::RustCall {
|
2016-11-10 14:49:53 +00:00
|
|
|
// RustCall pseudo-ABI untuples the last argument.
|
2020-03-21 13:44:17 +00:00
|
|
|
Some(Local::new(arguments.len()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2022-08-27 12:40:39 +00:00
|
|
|
if yield_ty.is_some() {
|
2023-10-19 21:46:28 +00:00
|
|
|
body.coroutine.as_mut().unwrap().yield_ty = yield_ty;
|
2022-08-27 12:40:39 +00:00
|
|
|
}
|
2019-06-03 22:26:48 +00:00
|
|
|
body
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 11:38:36 +00:00
|
|
|
fn construct_const<'a, 'tcx>(
|
2022-08-27 12:40:39 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-05-08 13:53:19 +00:00
|
|
|
def: LocalDefId,
|
2021-04-03 17:58:46 +00:00
|
|
|
thir: &'a Thir<'tcx>,
|
|
|
|
expr: ExprId,
|
2023-01-22 14:37:16 +00:00
|
|
|
const_ty: Ty<'tcx>,
|
2019-05-17 21:55:04 +00:00
|
|
|
) -> Body<'tcx> {
|
2022-05-08 13:53:19 +00:00
|
|
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def);
|
2022-08-27 12:40:39 +00:00
|
|
|
|
|
|
|
// Figure out what primary body this item has.
|
|
|
|
let (span, const_ty_span) = match tcx.hir().get(hir_id) {
|
|
|
|
Node::Item(hir::Item {
|
2023-05-04 14:40:57 +00:00
|
|
|
kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _),
|
2022-08-27 12:40:39 +00:00
|
|
|
span,
|
|
|
|
..
|
|
|
|
})
|
|
|
|
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. })
|
|
|
|
| Node::TraitItem(hir::TraitItem {
|
|
|
|
kind: hir::TraitItemKind::Const(ty, Some(_)),
|
|
|
|
span,
|
|
|
|
..
|
|
|
|
}) => (*span, ty.span),
|
2023-02-25 19:53:37 +00:00
|
|
|
Node::AnonConst(_) | Node::ConstBlock(_) => {
|
2022-05-08 13:53:19 +00:00
|
|
|
let span = tcx.def_span(def);
|
2022-08-27 12:40:39 +00:00
|
|
|
(span, span)
|
|
|
|
}
|
2022-05-08 13:53:19 +00:00
|
|
|
_ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
|
2022-08-27 12:40:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let infcx = tcx.infer_ctxt().build();
|
|
|
|
let mut builder = Builder::new(
|
|
|
|
thir,
|
|
|
|
infcx,
|
|
|
|
def,
|
|
|
|
hir_id,
|
|
|
|
span,
|
|
|
|
0,
|
|
|
|
Safety::Safe,
|
|
|
|
const_ty,
|
|
|
|
const_ty_span,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut block = START_BLOCK;
|
|
|
|
unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
|
2016-05-02 20:11:19 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
let source_info = builder.source_info(span);
|
|
|
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
2016-05-02 20:11:19 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
builder.build_drop_trees();
|
2016-05-02 20:11:19 +00:00
|
|
|
|
2022-08-27 12:40:39 +00:00
|
|
|
builder.finish()
|
2016-05-02 20:11:19 +00:00
|
|
|
}
|
|
|
|
|
2021-08-22 12:46:15 +00:00
|
|
|
/// Construct MIR for an item that has had errors in type checking.
|
2019-12-26 17:51:39 +00:00
|
|
|
///
|
|
|
|
/// 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.
|
2023-10-30 23:27:33 +00:00
|
|
|
fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> {
|
|
|
|
let span = tcx.def_span(def_id);
|
|
|
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
|
|
|
let coroutine_kind = tcx.coroutine_kind(def_id);
|
|
|
|
|
|
|
|
let (inputs, output, yield_ty) = match tcx.def_kind(def_id) {
|
|
|
|
DefKind::Const
|
|
|
|
| DefKind::AssocConst
|
|
|
|
| DefKind::AnonConst
|
|
|
|
| DefKind::InlineConst
|
|
|
|
| DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
|
|
|
|
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => {
|
|
|
|
let sig = tcx.liberate_late_bound_regions(
|
|
|
|
def_id.to_def_id(),
|
|
|
|
tcx.fn_sig(def_id).instantiate_identity(),
|
|
|
|
);
|
|
|
|
(sig.inputs().to_vec(), sig.output(), None)
|
|
|
|
}
|
|
|
|
DefKind::Closure => {
|
|
|
|
let closure_ty = tcx.type_of(def_id).instantiate_identity();
|
|
|
|
let ty::Closure(_, args) = closure_ty.kind() else { bug!() };
|
|
|
|
let args = args.as_closure();
|
|
|
|
let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig());
|
|
|
|
let self_ty = match args.kind() {
|
|
|
|
ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty),
|
|
|
|
ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty),
|
|
|
|
ty::ClosureKind::FnOnce => closure_ty,
|
|
|
|
};
|
|
|
|
([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None)
|
|
|
|
}
|
|
|
|
DefKind::Coroutine => {
|
|
|
|
let coroutine_ty = tcx.type_of(def_id).instantiate_identity();
|
|
|
|
let ty::Coroutine(_, args, _) = coroutine_ty.kind() else { bug!() };
|
|
|
|
let args = args.as_coroutine();
|
|
|
|
let yield_ty = args.yield_ty();
|
|
|
|
let return_ty = args.return_ty();
|
|
|
|
let self_ty = Ty::new_adt(
|
|
|
|
tcx,
|
|
|
|
tcx.adt_def(tcx.lang_items().pin_type().unwrap()),
|
|
|
|
tcx.mk_args(&[Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty).into()]),
|
|
|
|
);
|
|
|
|
let coroutine_state = Ty::new_adt(
|
|
|
|
tcx,
|
|
|
|
tcx.adt_def(tcx.lang_items().coroutine_state().unwrap()),
|
|
|
|
tcx.mk_args(&[yield_ty.into(), return_ty.into()]),
|
|
|
|
);
|
|
|
|
(vec![self_ty, args.resume_ty()], coroutine_state, Some(yield_ty))
|
2019-12-26 17:51:39 +00:00
|
|
|
}
|
2023-10-30 23:27:33 +00:00
|
|
|
dk => bug!("{:?} is not a body: {:?}", def_id, dk),
|
2019-12-26 17:51:39 +00:00
|
|
|
};
|
2023-10-30 23:27:33 +00:00
|
|
|
|
|
|
|
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
|
|
|
|
let local_decls = IndexVec::from_iter(
|
|
|
|
[output].iter().chain(&inputs).map(|ty| LocalDecl::with_source_info(*ty, source_info)),
|
|
|
|
);
|
2021-04-03 17:58:46 +00:00
|
|
|
let mut cfg = CFG { basic_blocks: IndexVec::new() };
|
|
|
|
let mut source_scopes = IndexVec::new();
|
|
|
|
|
|
|
|
cfg.start_new_block();
|
|
|
|
source_scopes.push(SourceScopeData {
|
|
|
|
span,
|
|
|
|
parent_scope: None,
|
|
|
|
inlined: None,
|
|
|
|
inlined_parent_scope: None,
|
|
|
|
local_data: ClearCrossCrate::Set(SourceScopeLocalData {
|
|
|
|
lint_root: hir_id,
|
|
|
|
safety: Safety::Safe,
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
|
|
|
|
|
|
|
|
let mut body = Body::new(
|
2023-10-30 23:27:33 +00:00
|
|
|
MirSource::item(def_id.to_def_id()),
|
2021-04-03 17:58:46 +00:00
|
|
|
cfg.basic_blocks,
|
|
|
|
source_scopes,
|
|
|
|
local_decls,
|
|
|
|
IndexVec::new(),
|
2023-10-30 23:27:33 +00:00
|
|
|
inputs.len(),
|
2021-04-03 17:58:46 +00:00
|
|
|
vec![],
|
|
|
|
span,
|
2023-10-19 21:46:28 +00:00
|
|
|
coroutine_kind,
|
2023-10-30 23:27:33 +00:00
|
|
|
Some(guar),
|
2021-04-03 17:58:46 +00:00
|
|
|
);
|
2023-10-30 23:27:33 +00:00
|
|
|
|
|
|
|
body.coroutine.as_mut().map(|gen| gen.yield_ty = yield_ty);
|
|
|
|
|
2019-12-26 17:51:39 +00:00
|
|
|
body
|
2017-02-15 13:00:20 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 11:38:36 +00:00
|
|
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
2019-12-24 22:38:22 +00:00
|
|
|
fn new(
|
2021-04-03 17:58:46 +00:00
|
|
|
thir: &'a Thir<'tcx>,
|
2022-09-09 18:01:06 +00:00
|
|
|
infcx: InferCtxt<'tcx>,
|
2022-05-08 13:53:19 +00:00
|
|
|
def: LocalDefId,
|
2021-03-03 15:35:54 +00:00
|
|
|
hir_id: hir::HirId,
|
2019-12-24 22:38:22 +00:00
|
|
|
span: Span,
|
|
|
|
arg_count: usize,
|
|
|
|
safety: Safety,
|
|
|
|
return_ty: Ty<'tcx>,
|
|
|
|
return_span: Span,
|
2023-10-19 21:46:28 +00:00
|
|
|
coroutine_kind: Option<CoroutineKind>,
|
2019-12-24 22:38:22 +00:00
|
|
|
) -> Builder<'a, 'tcx> {
|
2021-03-03 15:35:54 +00:00
|
|
|
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.
|
2023-03-19 17:32:34 +00:00
|
|
|
let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
|
2021-03-03 15:35:54 +00:00
|
|
|
// Respect -C overflow-checks.
|
|
|
|
check_overflow |= tcx.sess.overflow_checks();
|
|
|
|
// Constants always need overflow checks.
|
|
|
|
check_overflow |= matches!(
|
2022-05-08 13:53:19 +00:00
|
|
|
tcx.hir().body_owner_kind(def),
|
2023-09-18 15:30:07 +00:00
|
|
|
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
|
2021-03-03 15:35:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let lint_level = LintLevel::Explicit(hir_id);
|
2022-05-08 13:53:19 +00:00
|
|
|
let param_env = tcx.param_env(def);
|
2016-04-15 14:11:24 +00:00
|
|
|
let mut builder = Builder {
|
2021-04-03 17:58:46 +00:00
|
|
|
thir,
|
2021-03-03 15:35:54 +00:00
|
|
|
tcx,
|
|
|
|
infcx,
|
2022-05-08 13:53:19 +00:00
|
|
|
region_scope_tree: tcx.region_scope_tree(def),
|
2022-01-25 00:00:00 +00:00
|
|
|
param_env,
|
2022-05-08 13:53:19 +00:00
|
|
|
def_id: def,
|
2021-03-03 15:35:54 +00:00
|
|
|
hir_id,
|
2022-01-25 00:00:00 +00:00
|
|
|
parent_module: tcx.parent_module(hir_id).to_def_id(),
|
2021-03-03 15:35:54 +00:00
|
|
|
check_overflow,
|
2016-06-07 14:28:36 +00:00
|
|
|
cfg: CFG { basic_blocks: IndexVec::new() },
|
2016-04-15 14:11:24 +00:00
|
|
|
fn_span: span,
|
2017-08-07 05:54:09 +00:00
|
|
|
arg_count,
|
2023-10-19 21:46:28 +00:00
|
|
|
coroutine_kind,
|
2019-11-16 13:23:31 +00:00
|
|
|
scopes: scope::Scopes::new(),
|
2018-11-08 13:31:12 +00:00
|
|
|
block_context: BlockContext::new(),
|
2018-05-28 11:16:09 +00:00
|
|
|
source_scopes: IndexVec::new(),
|
|
|
|
source_scope: OUTERMOST_SOURCE_SCOPE,
|
2018-02-26 14:45:13 +00:00
|
|
|
guard_context: vec![],
|
2021-05-17 21:19:48 +00:00
|
|
|
in_scope_unsafe: safety,
|
2020-05-06 00:17:38 +00:00
|
|
|
local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
|
2018-11-16 21:56:18 +00:00
|
|
|
canonical_user_type_annotations: IndexVec::new(),
|
2022-08-23 20:22:15 +00:00
|
|
|
upvars: CaptureMap::new(),
|
2018-07-21 19:15:11 +00:00
|
|
|
var_indices: Default::default(),
|
2016-04-15 14:11:24 +00:00
|
|
|
unit_temp: None,
|
2018-05-16 15:58:54 +00:00
|
|
|
var_debug_info: vec![],
|
2023-07-11 23:55:39 +00:00
|
|
|
lint_level_roots_cache: GrowableBitSet::new_empty(),
|
2016-04-15 14:11:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
2017-09-13 19:33:07 +00:00
|
|
|
assert_eq!(
|
2018-05-28 11:16:09 +00:00
|
|
|
builder.new_source_scope(span, lint_level, Some(safety)),
|
2019-12-24 22:38:22 +00:00
|
|
|
OUTERMOST_SOURCE_SCOPE
|
|
|
|
);
|
2018-05-28 11:16:09 +00:00
|
|
|
builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
|
2016-04-15 14:11:24 +00:00
|
|
|
|
|
|
|
builder
|
|
|
|
}
|
|
|
|
|
2018-05-16 15:58:54 +00:00
|
|
|
fn finish(self) -> Body<'tcx> {
|
2016-04-15 14:11:24 +00:00
|
|
|
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
2019-10-04 04:55:28 +00:00
|
|
|
if block.terminator.is_none() {
|
2016-04-15 14:11:24 +00:00
|
|
|
span_bug!(self.fn_span, "no terminator on block {:?}", index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 21:55:04 +00:00
|
|
|
Body::new(
|
2022-05-08 13:53:19 +00:00
|
|
|
MirSource::item(self.def_id.to_def_id()),
|
2018-11-24 13:38:31 +00:00
|
|
|
self.cfg.basic_blocks,
|
|
|
|
self.source_scopes,
|
|
|
|
self.local_decls,
|
2018-11-16 21:56:18 +00:00
|
|
|
self.canonical_user_type_annotations,
|
2018-11-24 13:38:31 +00:00
|
|
|
self.arg_count,
|
2018-05-16 15:58:54 +00:00
|
|
|
self.var_debug_info,
|
2018-11-24 13:38:31 +00:00
|
|
|
self.fn_span,
|
2023-10-19 21:46:28 +00:00
|
|
|
self.coroutine_kind,
|
2022-10-25 17:59:18 +00:00
|
|
|
None,
|
2016-11-03 03:22:57 +00:00
|
|
|
)
|
2016-04-15 14:11:24 +00:00
|
|
|
}
|
|
|
|
|
2022-10-25 17:59:18 +00:00
|
|
|
fn insert_upvar_arg(&mut self) {
|
|
|
|
let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return };
|
|
|
|
|
|
|
|
let mut closure_ty = closure_arg.ty;
|
|
|
|
let mut closure_env_projs = vec![];
|
|
|
|
if let ty::Ref(_, ty, _) = closure_ty.kind() {
|
|
|
|
closure_env_projs.push(ProjectionElem::Deref);
|
|
|
|
closure_ty = *ty;
|
|
|
|
}
|
|
|
|
|
2023-07-11 21:35:29 +00:00
|
|
|
let upvar_args = match closure_ty.kind() {
|
|
|
|
ty::Closure(_, args) => ty::UpvarArgs::Closure(args),
|
2023-10-19 16:06:43 +00:00
|
|
|
ty::Coroutine(_, args, _) => ty::UpvarArgs::Coroutine(args),
|
2022-10-25 17:59:18 +00:00
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
|
|
|
|
// In analyze_closure() in upvar.rs we gathered a list of upvars used by an
|
|
|
|
// indexed closure and we stored in a map called closure_min_captures in TypeckResults
|
|
|
|
// 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.upvars`.
|
2023-07-11 21:35:29 +00:00
|
|
|
let capture_tys = upvar_args.upvar_tys();
|
2022-10-25 17:59:18 +00:00
|
|
|
|
|
|
|
let tcx = self.tcx;
|
|
|
|
self.upvars = tcx
|
2022-05-08 13:53:19 +00:00
|
|
|
.closure_captures(self.def_id)
|
2022-10-25 17:59:18 +00:00
|
|
|
.iter()
|
|
|
|
.zip(capture_tys)
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, (captured_place, ty))| {
|
|
|
|
let name = captured_place.to_symbol();
|
|
|
|
|
|
|
|
let capture = captured_place.info.capture_kind;
|
|
|
|
let var_id = match captured_place.place.base {
|
|
|
|
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
|
|
|
_ => bug!("Expected an upvar"),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mutability = captured_place.mutability;
|
|
|
|
|
|
|
|
let mut projs = closure_env_projs.clone();
|
2023-03-28 19:32:57 +00:00
|
|
|
projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
|
2022-10-25 17:59:18 +00:00
|
|
|
match capture {
|
|
|
|
ty::UpvarCapture::ByValue => {}
|
|
|
|
ty::UpvarCapture::ByRef(..) => {
|
|
|
|
projs.push(ProjectionElem::Deref);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let use_place = Place {
|
|
|
|
local: ty::CAPTURE_STRUCT_LOCAL,
|
|
|
|
projection: tcx.mk_place_elems(&projs),
|
|
|
|
};
|
|
|
|
self.var_debug_info.push(VarDebugInfo {
|
|
|
|
name,
|
|
|
|
source_info: SourceInfo::outermost(captured_place.var_ident.span),
|
|
|
|
value: VarDebugInfoContents::Place(use_place),
|
2023-08-26 16:58:42 +00:00
|
|
|
composite: None,
|
2023-03-21 10:48:03 +00:00
|
|
|
argument_index: None,
|
2022-10-25 17:59:18 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let capture = Capture { captured_place, use_place, mutability };
|
|
|
|
(var_id, capture)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
}
|
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
fn args_and_body(
|
|
|
|
&mut self,
|
|
|
|
mut block: BasicBlock,
|
2023-03-31 07:32:44 +00:00
|
|
|
arguments: &IndexSlice<ParamId, Param<'tcx>>,
|
2019-12-24 22:38:22 +00:00
|
|
|
argument_scope: region::Scope,
|
2021-04-03 17:58:46 +00:00
|
|
|
expr: &Expr<'tcx>,
|
2019-12-24 22:38:22 +00:00
|
|
|
) -> BlockAnd<()> {
|
2016-09-24 23:38:27 +00:00
|
|
|
// Allocate locals for the function arguments
|
2023-03-21 10:48:03 +00:00
|
|
|
for (argument_index, param) in arguments.iter().enumerate() {
|
2020-05-06 00:30:11 +00:00
|
|
|
let source_info =
|
2022-08-22 20:29:25 +00:00
|
|
|
SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span));
|
|
|
|
let arg_local =
|
|
|
|
self.local_decls.push(LocalDecl::with_source_info(param.ty, source_info));
|
2018-05-16 15:58:54 +00:00
|
|
|
|
|
|
|
// If this is a simple binding pattern, give debuginfo a nice name.
|
2022-08-22 20:29:25 +00:00
|
|
|
if let Some(ref pat) = param.pat
|
|
|
|
&& let Some(name) = pat.simple_ident()
|
|
|
|
{
|
2022-03-01 00:12:52 +00:00
|
|
|
self.var_debug_info.push(VarDebugInfo {
|
2022-08-27 10:21:02 +00:00
|
|
|
name,
|
2022-03-01 00:12:52 +00:00
|
|
|
source_info,
|
|
|
|
value: VarDebugInfoContents::Place(arg_local.into()),
|
2023-08-26 16:58:42 +00:00
|
|
|
composite: None,
|
2023-03-21 10:48:03 +00:00
|
|
|
argument_index: Some(argument_index as u16 + 1),
|
2022-03-01 00:12:52 +00:00
|
|
|
});
|
2018-05-16 15:58:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 17:59:18 +00:00
|
|
|
self.insert_upvar_arg();
|
2016-09-24 23:38:27 +00:00
|
|
|
|
2016-05-31 17:27:36 +00:00
|
|
|
let mut scope = None;
|
2016-09-24 23:38:27 +00:00
|
|
|
// Bind the argument patterns
|
2022-08-22 20:29:25 +00:00
|
|
|
for (index, param) in arguments.iter().enumerate() {
|
2017-12-01 12:39:51 +00: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 18:49:36 +00:00
|
|
|
let local = Local::new(index + 1);
|
2019-06-24 15:46:09 +00:00
|
|
|
let place = Place::from(local);
|
2016-09-24 23:38:27 +00: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(
|
2022-08-22 20:29:25 +00:00
|
|
|
param.pat.as_ref().map_or(expr.span, |pat| pat.span),
|
2019-12-24 22:38:22 +00:00
|
|
|
argument_scope,
|
|
|
|
local,
|
|
|
|
DropKind::Value,
|
2018-11-18 14:49:24 +00:00
|
|
|
);
|
|
|
|
|
2022-08-22 20:29:25 +00:00
|
|
|
let Some(ref pat) = param.pat else {
|
2021-11-18 16:21:21 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let original_source_scope = self.source_scope;
|
2022-08-22 20:29:25 +00:00
|
|
|
let span = pat.span;
|
|
|
|
if let Some(arg_hir_id) = param.hir_id {
|
|
|
|
self.set_correct_source_scope_for_arg(arg_hir_id, original_source_scope, span);
|
|
|
|
}
|
|
|
|
match pat.kind {
|
2021-11-18 16:21:21 +00:00
|
|
|
// Don't introduce extra copies for simple bindings
|
|
|
|
PatKind::Binding {
|
|
|
|
mutability,
|
|
|
|
var,
|
|
|
|
mode: BindingMode::ByValue,
|
|
|
|
subpattern: None,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
self.local_decls[local].mutability = mutability;
|
|
|
|
self.local_decls[local].source_info.scope = self.source_scope;
|
2023-03-18 05:29:53 +00:00
|
|
|
**self.local_decls[local].local_info.as_mut().assert_crate_local() =
|
|
|
|
if let Some(kind) = param.self_kind {
|
|
|
|
LocalInfo::User(BindingForm::ImplicitSelf(kind))
|
|
|
|
} else {
|
|
|
|
let binding_mode = ty::BindingMode::BindByValue(mutability);
|
|
|
|
LocalInfo::User(BindingForm::Var(VarBindingForm {
|
2021-11-18 16:21:21 +00:00
|
|
|
binding_mode,
|
2022-08-22 20:29:25 +00:00
|
|
|
opt_ty_info: param.ty_span,
|
2022-09-03 22:55:53 +00:00
|
|
|
opt_match_place: Some((None, span)),
|
2021-11-18 16:21:21 +00:00
|
|
|
pat_span: span,
|
2023-03-18 05:29:53 +00:00
|
|
|
}))
|
|
|
|
};
|
2021-11-18 16:21:21 +00:00
|
|
|
self.var_indices.insert(var, LocalsForNode::One(local));
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
scope = self.declare_bindings(
|
|
|
|
scope,
|
|
|
|
expr.span,
|
2022-08-22 20:29:25 +00:00
|
|
|
&pat,
|
2022-11-21 11:45:29 +00:00
|
|
|
None,
|
2021-11-18 16:21:21 +00:00
|
|
|
Some((Some(&place), span)),
|
|
|
|
);
|
|
|
|
let place_builder = PlaceBuilder::from(local);
|
2022-08-22 20:29:25 +00:00
|
|
|
unpack!(block = self.place_into_pattern(block, &pat, place_builder, 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 18:49:36 +00:00
|
|
|
}
|
2016-04-15 14:11:24 +00:00
|
|
|
}
|
2021-11-18 16:21:21 +00:00
|
|
|
self.source_scope = original_source_scope;
|
2016-09-24 23:38:27 +00:00
|
|
|
}
|
2016-03-23 16:26:37 +00:00
|
|
|
|
2018-05-28 11:16:09 +00: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 17:27:36 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 15:35:54 +00:00
|
|
|
self.expr_into_dest(Place::return_place(), block, &expr)
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
2016-01-15 22:36:32 +00:00
|
|
|
|
2019-07-26 22:52:37 +00:00
|
|
|
fn set_correct_source_scope_for_arg(
|
|
|
|
&mut self,
|
|
|
|
arg_hir_id: hir::HirId,
|
|
|
|
original_source_scope: SourceScope,
|
2019-12-24 22:38:22 +00:00
|
|
|
pattern_span: Span,
|
2019-07-26 22:52:37 +00:00
|
|
|
) {
|
2022-12-05 19:22:35 +00:00
|
|
|
let parent_id = self.source_scopes[original_source_scope]
|
|
|
|
.local_data
|
|
|
|
.as_ref()
|
|
|
|
.assert_crate_local()
|
|
|
|
.lint_root;
|
|
|
|
self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id);
|
2019-07-26 22:52:37 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 12:31:47 +00:00
|
|
|
fn get_unit_temp(&mut self) -> Place<'tcx> {
|
2016-01-15 22:36:32 +00:00
|
|
|
match self.unit_temp {
|
2020-01-22 15:30:15 +00:00
|
|
|
Some(tmp) => tmp,
|
2016-01-15 22:36:32 +00:00
|
|
|
None => {
|
2023-07-05 19:13:26 +00:00
|
|
|
let ty = Ty::new_unit(self.tcx);
|
2017-04-11 20:52:51 +00:00
|
|
|
let fn_span = self.fn_span;
|
|
|
|
let tmp = self.temp(ty, fn_span);
|
2020-01-22 15:30:15 +00:00
|
|
|
self.unit_temp = Some(tmp);
|
2016-01-15 22:36:32 +00:00
|
|
|
tmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-18 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2022-02-16 09:56:01 +00:00
|
|
|
fn parse_float_into_constval<'tcx>(
|
|
|
|
num: Symbol,
|
|
|
|
float_ty: ty::FloatTy,
|
|
|
|
neg: bool,
|
|
|
|
) -> Option<ConstValue<'tcx>> {
|
|
|
|
parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar)
|
|
|
|
}
|
|
|
|
|
2022-06-03 18:42:35 +00:00
|
|
|
pub(crate) fn parse_float_into_scalar(
|
|
|
|
num: Symbol,
|
|
|
|
float_ty: ty::FloatTy,
|
|
|
|
neg: bool,
|
|
|
|
) -> Option<Scalar> {
|
|
|
|
let num = num.as_str();
|
|
|
|
match float_ty {
|
|
|
|
ty::FloatTy::F32 => {
|
|
|
|
let Ok(rust_f) = num.parse::<f32>() else { return None };
|
2023-07-25 21:17:39 +00:00
|
|
|
let mut f = num
|
|
|
|
.parse::<Single>()
|
|
|
|
.unwrap_or_else(|e| panic!("apfloat::ieee::Single failed to parse `{num}`: {e:?}"));
|
2022-06-03 18:42:35 +00:00
|
|
|
|
|
|
|
assert!(
|
|
|
|
u128::from(rust_f.to_bits()) == f.to_bits(),
|
|
|
|
"apfloat::ieee::Single gave different result for `{}`: \
|
|
|
|
{}({:#x}) vs Rust's {}({:#x})",
|
|
|
|
rust_f,
|
|
|
|
f,
|
|
|
|
f.to_bits(),
|
|
|
|
Single::from_bits(rust_f.to_bits().into()),
|
|
|
|
rust_f.to_bits()
|
|
|
|
);
|
|
|
|
|
|
|
|
if neg {
|
|
|
|
f = -f;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(Scalar::from_f32(f))
|
|
|
|
}
|
|
|
|
ty::FloatTy::F64 => {
|
|
|
|
let Ok(rust_f) = num.parse::<f64>() else { return None };
|
2023-07-25 21:17:39 +00:00
|
|
|
let mut f = num
|
|
|
|
.parse::<Double>()
|
|
|
|
.unwrap_or_else(|e| panic!("apfloat::ieee::Double failed to parse `{num}`: {e:?}"));
|
2022-06-03 18:42:35 +00:00
|
|
|
|
|
|
|
assert!(
|
|
|
|
u128::from(rust_f.to_bits()) == f.to_bits(),
|
|
|
|
"apfloat::ieee::Double gave different result for `{}`: \
|
|
|
|
{}({:#x}) vs Rust's {}({:#x})",
|
|
|
|
rust_f,
|
|
|
|
f,
|
|
|
|
f.to_bits(),
|
|
|
|
Double::from_bits(rust_f.to_bits().into()),
|
|
|
|
rust_f.to_bits()
|
|
|
|
);
|
|
|
|
|
|
|
|
if neg {
|
|
|
|
f = -f;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(Scalar::from_f64(f))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 21:59:21 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Builder methods are broken up into modules, depending on what kind
|
2018-05-08 13:10:16 +00:00
|
|
|
// of thing is being lowered. Note that they use the `unpack` macro
|
2015-08-18 21:59:21 +00:00
|
|
|
// above extensively.
|
|
|
|
|
|
|
|
mod block;
|
|
|
|
mod cfg;
|
2022-08-03 11:30:13 +00:00
|
|
|
mod custom;
|
2015-08-18 21:59:21 +00:00
|
|
|
mod expr;
|
|
|
|
mod matches;
|
|
|
|
mod misc;
|
|
|
|
mod scope;
|
2021-06-27 12:59:38 +00:00
|
|
|
|
|
|
|
pub(crate) use expr::category::Category as ExprCategory;
|