mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-31 17:12:53 +00:00
Auto merge of #104975 - JakobDegen:custom_mir_let, r=oli-obk
`#![custom_mir]`: Various improvements This PR makes a bunch of improvements to `#![custom_mir]`. Ideally this would be 4 PRs, one for each commit, but those would take forever to get merged and be a pain to juggle. Should still be reviewed one commit at a time though. ### Commit 1: Support arbitrary `let` Before this change, all locals used in the body need to be declared at the top of the `mir!` invocation, which is rather annoying. We attempt to change that. Unfortunately, we still have the requirement that the output of the `mir!` macro must resolve, typecheck, etc. Because of that, we can't just accept this in the THIR -> MIR parser because something like ```rust { let x = 0; Goto(other) } other = { RET = x; Return() } ``` will fail to resolve. Instead, the implementation does macro shenanigans to find the let declarations and extract them as part of the `mir!` macro. That *works*, but it is fairly complicated and degrades debuginfo by quite a bit. Specifically, the spans for any statements and declarations that are affected by this are completely wrong. My guess is that this is a net improvement though. One way to recover some of the debuginfo would be to not support type annotations in the `let` statements, which would allow us to parse like `let $stmt:stmt`. That seems quite surprising though. ### Commit 2: Parse consts Reuses most of the const parsing from regular Mir building for building custom mir ### Commit 3: Parse statics Statics are slightly weird because the Mir primitive associated with them is a reference/pointer to them, so this is factored out separately. ### Commit 4: Fix some spans A bunch of the spans were non-ideal, so we adjust them to be much more helpful. r? `@oli-obk`
This commit is contained in:
commit
9c0bc3028a
@ -74,7 +74,7 @@ pub(super) fn build_custom_mir<'tcx>(
|
||||
let mut pctxt = ParseCtxt {
|
||||
tcx,
|
||||
thir,
|
||||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
|
||||
source_scope: OUTERMOST_SOURCE_SCOPE,
|
||||
body: &mut body,
|
||||
local_map: FxHashMap::default(),
|
||||
block_map: FxHashMap::default(),
|
||||
@ -128,7 +128,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
|
||||
struct ParseCtxt<'tcx, 'body> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
thir: &'body Thir<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
source_scope: SourceScope,
|
||||
|
||||
body: &'body mut Body<'tcx>,
|
||||
local_map: FxHashMap<LocalVarId, Local>,
|
||||
|
@ -23,6 +23,7 @@ macro_rules! parse_by_kind {
|
||||
(
|
||||
$self:ident,
|
||||
$expr_id:expr,
|
||||
$expr_name:pat,
|
||||
$expected:literal,
|
||||
$(
|
||||
@call($name:literal, $args:ident) => $call_expr:expr,
|
||||
@ -33,6 +34,8 @@ macro_rules! parse_by_kind {
|
||||
) => {{
|
||||
let expr_id = $self.preparse($expr_id);
|
||||
let expr = &$self.thir[expr_id];
|
||||
debug!("Trying to parse {:?} as {}", expr.kind, $expected);
|
||||
let $expr_name = expr;
|
||||
match &expr.kind {
|
||||
$(
|
||||
ExprKind::Call { ty, fun: _, args: $args, .. } if {
|
||||
@ -137,10 +140,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
/// This allows us to easily parse the basic blocks declarations, local declarations, and
|
||||
/// basic block definitions in order.
|
||||
pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
|
||||
let body = parse_by_kind!(self, expr_id, "whole body",
|
||||
let body = parse_by_kind!(self, expr_id, _, "whole body",
|
||||
ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
|
||||
);
|
||||
let (block_decls, rest) = parse_by_kind!(self, body, "body with block decls",
|
||||
let (block_decls, rest) = parse_by_kind!(self, body, _, "body with block decls",
|
||||
ExprKind::Block { block } => {
|
||||
let block = &self.thir[*block];
|
||||
(&block.stmts, block.expr.unwrap())
|
||||
@ -148,7 +151,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
);
|
||||
self.parse_block_decls(block_decls.iter().copied())?;
|
||||
|
||||
let (local_decls, rest) = parse_by_kind!(self, rest, "body with local decls",
|
||||
let (local_decls, rest) = parse_by_kind!(self, rest, _, "body with local decls",
|
||||
ExprKind::Block { block } => {
|
||||
let block = &self.thir[*block];
|
||||
(&block.stmts, block.expr.unwrap())
|
||||
@ -156,7 +159,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
);
|
||||
self.parse_local_decls(local_decls.iter().copied())?;
|
||||
|
||||
let block_defs = parse_by_kind!(self, rest, "body with block defs",
|
||||
let block_defs = parse_by_kind!(self, rest, _, "body with block defs",
|
||||
ExprKind::Block { block } => &self.thir[*block].stmts,
|
||||
);
|
||||
for (i, block_def) in block_defs.iter().enumerate() {
|
||||
@ -223,22 +226,30 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
}
|
||||
|
||||
fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
|
||||
let block = parse_by_kind!(self, expr_id, "basic block",
|
||||
let block = parse_by_kind!(self, expr_id, _, "basic block",
|
||||
ExprKind::Block { block } => &self.thir[*block],
|
||||
);
|
||||
|
||||
let mut data = BasicBlockData::new(None);
|
||||
for stmt_id in &*block.stmts {
|
||||
let stmt = self.statement_as_expr(*stmt_id)?;
|
||||
let span = self.thir[stmt].span;
|
||||
let statement = self.parse_statement(stmt)?;
|
||||
data.statements.push(Statement { source_info: self.source_info, kind: statement });
|
||||
data.statements.push(Statement {
|
||||
source_info: SourceInfo { span, scope: self.source_scope },
|
||||
kind: statement,
|
||||
});
|
||||
}
|
||||
|
||||
let Some(trailing) = block.expr else {
|
||||
return Err(self.expr_error(expr_id, "terminator"))
|
||||
};
|
||||
let span = self.thir[trailing].span;
|
||||
let terminator = self.parse_terminator(trailing)?;
|
||||
data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });
|
||||
data.terminator = Some(Terminator {
|
||||
source_info: SourceInfo { span, scope: self.source_scope },
|
||||
kind: terminator,
|
||||
});
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||
use rustc_middle::{mir::*, thir::*, ty};
|
||||
|
||||
use super::{parse_by_kind, PResult, ParseCtxt};
|
||||
|
||||
impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, "statement",
|
||||
parse_by_kind!(self, expr_id, _, "statement",
|
||||
@call("mir_retag", args) => {
|
||||
Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
|
||||
},
|
||||
@ -20,7 +21,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
}
|
||||
|
||||
pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, "terminator",
|
||||
parse_by_kind!(self, expr_id, _, "terminator",
|
||||
@call("mir_return", _args) => {
|
||||
Ok(TerminatorKind::Return)
|
||||
},
|
||||
@ -31,7 +32,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
}
|
||||
|
||||
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, "rvalue",
|
||||
parse_by_kind!(self, expr_id, _, "rvalue",
|
||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||
),
|
||||
@ -43,14 +44,26 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
}
|
||||
|
||||
fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, "operand",
|
||||
parse_by_kind!(self, expr_id, expr, "operand",
|
||||
@call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
|
||||
@call("mir_static", args) => self.parse_static(args[0]),
|
||||
@call("mir_static_mut", args) => self.parse_static(args[0]),
|
||||
ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ConstBlock { .. } => {
|
||||
Ok(Operand::Constant(Box::new(
|
||||
crate::build::expr::as_constant::as_constant_inner(expr, |_| None, self.tcx)
|
||||
)))
|
||||
},
|
||||
_ => self.parse_place(expr_id).map(Operand::Copy),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, "place",
|
||||
parse_by_kind!(self, expr_id, _, "place",
|
||||
ExprKind::Deref { arg } => Ok(
|
||||
self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
|
||||
),
|
||||
@ -59,14 +72,34 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
}
|
||||
|
||||
fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
|
||||
parse_by_kind!(self, expr_id, "local",
|
||||
parse_by_kind!(self, expr_id, _, "local",
|
||||
ExprKind::VarRef { id } => Ok(self.local_map[id]),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
|
||||
parse_by_kind!(self, expr_id, "basic block",
|
||||
parse_by_kind!(self, expr_id, _, "basic block",
|
||||
ExprKind::VarRef { id } => Ok(self.block_map[id]),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
|
||||
let expr_id = parse_by_kind!(self, expr_id, _, "static",
|
||||
ExprKind::Deref { arg } => *arg,
|
||||
);
|
||||
|
||||
parse_by_kind!(self, expr_id, expr, "static",
|
||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||
let const_val =
|
||||
ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
|
||||
let literal = ConstantKind::Val(const_val, *ty);
|
||||
|
||||
Ok(Operand::Constant(Box::new(Constant {
|
||||
span: expr.span,
|
||||
user_ty: None,
|
||||
literal
|
||||
})))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ use rustc_middle::mir::interpret::{
|
||||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
@ -19,87 +21,90 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let this = self;
|
||||
let tcx = this.tcx;
|
||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||
match *kind {
|
||||
match kind {
|
||||
ExprKind::Scope { region_scope: _, lint_level: _, value } => {
|
||||
this.as_constant(&this.thir[value])
|
||||
this.as_constant(&this.thir[*value])
|
||||
}
|
||||
ExprKind::Literal { lit, neg } => {
|
||||
let literal =
|
||||
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(guar)) => {
|
||||
ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
|
||||
}
|
||||
Err(LitToConstError::TypeError) => {
|
||||
bug!("encountered type error in `lit_to_mir_constant")
|
||||
}
|
||||
};
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
}
|
||||
ExprKind::NonHirLiteral { lit, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(|user_ty| {
|
||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
_ => as_constant_inner(
|
||||
expr,
|
||||
|user_ty| {
|
||||
Some(this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
span,
|
||||
user_ty: user_ty.clone(),
|
||||
inferred_ty: ty,
|
||||
})
|
||||
});
|
||||
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::ZstLiteral { ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(|user_ty| {
|
||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
span,
|
||||
user_ty: user_ty.clone(),
|
||||
inferred_ty: ty,
|
||||
})
|
||||
});
|
||||
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(|user_ty| {
|
||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
span,
|
||||
user_ty: user_ty.clone(),
|
||||
inferred_ty: ty,
|
||||
})
|
||||
});
|
||||
|
||||
let uneval =
|
||||
mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty, span, literal }
|
||||
}
|
||||
ExprKind::ConstParam { param, def_id: _ } => {
|
||||
let const_param = tcx.mk_const(param, expr.ty);
|
||||
let literal = ConstantKind::Ty(const_param);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
}
|
||||
ExprKind::ConstBlock { did: def_id, substs } => {
|
||||
let uneval =
|
||||
mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
}
|
||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||
let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
|
||||
let literal = ConstantKind::Val(const_val, ty);
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
}
|
||||
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
||||
}))
|
||||
},
|
||||
tcx,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_constant_inner<'tcx>(
|
||||
expr: &Expr<'tcx>,
|
||||
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Constant<'tcx> {
|
||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||
match *kind {
|
||||
ExprKind::Literal { lit, neg } => {
|
||||
let literal =
|
||||
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(guar)) => {
|
||||
ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
|
||||
}
|
||||
Err(LitToConstError::TypeError) => {
|
||||
bug!("encountered type error in `lit_to_mir_constant")
|
||||
}
|
||||
};
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
}
|
||||
ExprKind::NonHirLiteral { lit, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(push_cuta).flatten();
|
||||
|
||||
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::ZstLiteral { ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(push_cuta).flatten();
|
||||
|
||||
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().map(push_cuta).flatten();
|
||||
|
||||
let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty, span, literal }
|
||||
}
|
||||
ExprKind::ConstParam { param, def_id: _ } => {
|
||||
let const_param = tcx.mk_const(ty::ConstKind::Param(param), expr.ty);
|
||||
let literal = ConstantKind::Ty(const_param);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
}
|
||||
ExprKind::ConstBlock { did: def_id, substs } => {
|
||||
let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
}
|
||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||
let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
|
||||
let literal = ConstantKind::Val(const_val, ty);
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
}
|
||||
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx, lit_input))]
|
||||
pub(crate) fn lit_to_mir_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -492,7 +492,7 @@ fn construct_fn<'tcx>(
|
||||
arguments,
|
||||
return_ty,
|
||||
return_ty_span,
|
||||
span,
|
||||
span_with_body,
|
||||
custom_mir_attr,
|
||||
);
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
|
||||
define!("mir_retag", fn Retag<T>(place: T));
|
||||
define!("mir_retag_raw", fn RetagRaw<T>(place: T));
|
||||
define!("mir_move", fn Move<T>(place: T) -> T);
|
||||
define!("mir_static", fn Static<T>(s: T) -> &'static T);
|
||||
define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
|
||||
|
||||
/// Convenience macro for generating custom MIR.
|
||||
///
|
||||
@ -90,10 +92,14 @@ pub macro mir {
|
||||
(
|
||||
$(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
|
||||
|
||||
$entry_block:block
|
||||
{
|
||||
$($entry:tt)*
|
||||
}
|
||||
|
||||
$(
|
||||
$block_name:ident = $block:block
|
||||
$block_name:ident = {
|
||||
$($block:tt)*
|
||||
}
|
||||
)*
|
||||
) => {{
|
||||
// First, we declare all basic blocks.
|
||||
@ -109,11 +115,22 @@ pub macro mir {
|
||||
let $local_decl $(: $local_decl_ty)? ;
|
||||
)*
|
||||
|
||||
::core::intrinsics::mir::__internal_extract_let!($($entry)*);
|
||||
$(
|
||||
::core::intrinsics::mir::__internal_extract_let!($($block)*);
|
||||
)*
|
||||
|
||||
{
|
||||
// Finally, the contents of the basic blocks
|
||||
$entry_block;
|
||||
::core::intrinsics::mir::__internal_remove_let!({
|
||||
{}
|
||||
{ $($entry)* }
|
||||
});
|
||||
$(
|
||||
$block;
|
||||
::core::intrinsics::mir::__internal_remove_let!({
|
||||
{}
|
||||
{ $($block)* }
|
||||
});
|
||||
)*
|
||||
|
||||
RET
|
||||
@ -121,3 +138,152 @@ pub macro mir {
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
/// Helper macro that extracts the `let` declarations out of a bunch of statements.
|
||||
///
|
||||
/// This macro is written using the "statement muncher" strategy. Each invocation parses the first
|
||||
/// statement out of the input, does the appropriate thing with it, and then recursively calls the
|
||||
/// same macro on the remainder of the input.
|
||||
#[doc(hidden)]
|
||||
pub macro __internal_extract_let {
|
||||
// If it's a `let` like statement, keep the `let`
|
||||
(
|
||||
let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
|
||||
) => {
|
||||
let $var $(: $ty)?;
|
||||
::core::intrinsics::mir::__internal_extract_let!($($rest)*);
|
||||
},
|
||||
// Due to #86730, we have to handle const blocks separately
|
||||
(
|
||||
let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
|
||||
) => {
|
||||
let $var $(: $ty)?;
|
||||
::core::intrinsics::mir::__internal_extract_let!($($rest)*);
|
||||
},
|
||||
// Otherwise, output nothing
|
||||
(
|
||||
$stmt:stmt; $($rest:tt)*
|
||||
) => {
|
||||
::core::intrinsics::mir::__internal_extract_let!($($rest)*);
|
||||
},
|
||||
(
|
||||
$expr:expr
|
||||
) => {}
|
||||
}
|
||||
|
||||
/// Helper macro that removes the `let` declarations from a bunch of statements.
|
||||
///
|
||||
/// Because expression position macros cannot expand to statements + expressions, we need to be
|
||||
/// slightly creative here. The general strategy is also statement munching as above, but the output
|
||||
/// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
|
||||
/// ```text
|
||||
/// invoke!(
|
||||
/// {
|
||||
/// {
|
||||
/// x = 5;
|
||||
/// }
|
||||
/// {
|
||||
/// let d = e;
|
||||
/// Call()
|
||||
/// }
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
/// becomes
|
||||
/// ```text
|
||||
/// invoke!(
|
||||
/// {
|
||||
/// {
|
||||
/// x = 5;
|
||||
/// d = e;
|
||||
/// }
|
||||
/// {
|
||||
/// Call()
|
||||
/// }
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
#[doc(hidden)]
|
||||
pub macro __internal_remove_let {
|
||||
// If it's a `let` like statement, remove the `let`
|
||||
(
|
||||
{
|
||||
{
|
||||
$($already_parsed:tt)*
|
||||
}
|
||||
{
|
||||
let $var:ident $(: $ty:ty)? = $expr:expr;
|
||||
$($rest:tt)*
|
||||
}
|
||||
}
|
||||
) => { ::core::intrinsics::mir::__internal_remove_let!(
|
||||
{
|
||||
{
|
||||
$($already_parsed)*
|
||||
$var = $expr;
|
||||
}
|
||||
{
|
||||
$($rest)*
|
||||
}
|
||||
}
|
||||
)},
|
||||
// Due to #86730 , we have to handle const blocks separately
|
||||
(
|
||||
{
|
||||
{
|
||||
$($already_parsed:tt)*
|
||||
}
|
||||
{
|
||||
let $var:ident $(: $ty:ty)? = const $block:block;
|
||||
$($rest:tt)*
|
||||
}
|
||||
}
|
||||
) => { ::core::intrinsics::mir::__internal_remove_let!(
|
||||
{
|
||||
{
|
||||
$($already_parsed)*
|
||||
$var = const $block;
|
||||
}
|
||||
{
|
||||
$($rest)*
|
||||
}
|
||||
}
|
||||
)},
|
||||
// Otherwise, keep going
|
||||
(
|
||||
{
|
||||
{
|
||||
$($already_parsed:tt)*
|
||||
}
|
||||
{
|
||||
$stmt:stmt;
|
||||
$($rest:tt)*
|
||||
}
|
||||
}
|
||||
) => { ::core::intrinsics::mir::__internal_remove_let!(
|
||||
{
|
||||
{
|
||||
$($already_parsed)*
|
||||
$stmt;
|
||||
}
|
||||
{
|
||||
$($rest)*
|
||||
}
|
||||
}
|
||||
)},
|
||||
(
|
||||
{
|
||||
{
|
||||
$($already_parsed:tt)*
|
||||
}
|
||||
{
|
||||
$expr:expr
|
||||
}
|
||||
}
|
||||
) => {
|
||||
{
|
||||
$($already_parsed)*
|
||||
$expr
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
// MIR for `arbitrary_let` after built
|
||||
|
||||
fn arbitrary_let(_1: i32) -> i32 {
|
||||
let mut _0: i32; // return place in scope 0 at $DIR/arbitrary_let.rs:+0:29: +0:32
|
||||
let mut _2: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _3: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
goto -> bb2; // scope 0 at $DIR/arbitrary_let.rs:+4:13: +4:25
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = _3; // scope 0 at $DIR/arbitrary_let.rs:+7:13: +7:20
|
||||
return; // scope 0 at $DIR/arbitrary_let.rs:+8:13: +8:21
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_3 = _2; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
goto -> bb1; // scope 0 at $DIR/arbitrary_let.rs:+12:13: +12:24
|
||||
}
|
||||
}
|
28
src/test/mir-opt/building/custom/arbitrary_let.rs
Normal file
28
src/test/mir-opt/building/custom/arbitrary_let.rs
Normal file
@ -0,0 +1,28 @@
|
||||
#![feature(custom_mir, core_intrinsics)]
|
||||
|
||||
extern crate core;
|
||||
use core::intrinsics::mir::*;
|
||||
use core::ptr::{addr_of, addr_of_mut};
|
||||
|
||||
// EMIT_MIR arbitrary_let.arbitrary_let.built.after.mir
|
||||
#[custom_mir(dialect = "built")]
|
||||
fn arbitrary_let(x: i32) -> i32 {
|
||||
mir!(
|
||||
{
|
||||
let y = x;
|
||||
Goto(second)
|
||||
}
|
||||
third = {
|
||||
RET = z;
|
||||
Return()
|
||||
}
|
||||
second = {
|
||||
let z = y;
|
||||
Goto(third)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(arbitrary_let(5), 5);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
// MIR for `consts` after built
|
||||
|
||||
fn consts() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/consts.rs:+0:27: +0:27
|
||||
let mut _1: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _2: i8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _3: u32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _4: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _5: fn() {consts::<10>}; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_1 = const 5_u8; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
_2 = const _; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
_3 = const C; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
_4 = const _; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
_5 = consts::<10>; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
// mir::Constant
|
||||
// + span: $DIR/consts.rs:16:18: 16:30
|
||||
// + literal: Const { ty: fn() {consts::<10>}, val: Value(<ZST>) }
|
||||
return; // scope 0 at $DIR/consts.rs:+7:9: +7:17
|
||||
}
|
||||
}
|
36
src/test/mir-opt/building/custom/consts.rs
Normal file
36
src/test/mir-opt/building/custom/consts.rs
Normal file
@ -0,0 +1,36 @@
|
||||
#![feature(custom_mir, core_intrinsics, inline_const)]
|
||||
|
||||
extern crate core;
|
||||
use core::intrinsics::mir::*;
|
||||
|
||||
const D: i32 = 5;
|
||||
|
||||
// EMIT_MIR consts.consts.built.after.mir
|
||||
#[custom_mir(dialect = "built")]
|
||||
fn consts<const C: u32>() {
|
||||
mir!({
|
||||
let _a = 5_u8;
|
||||
let _b = const { 5_i8 };
|
||||
let _c = C;
|
||||
let _d = D;
|
||||
let _e = consts::<10>;
|
||||
Return()
|
||||
})
|
||||
}
|
||||
|
||||
static S: i32 = 5;
|
||||
static mut T: i32 = 10;
|
||||
// EMIT_MIR consts.statics.built.after.mir
|
||||
#[custom_mir(dialect = "built")]
|
||||
fn statics() {
|
||||
mir!({
|
||||
let _a: &i32 = Static(S);
|
||||
let _b: *mut i32 = StaticMut(T);
|
||||
Return()
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
consts::<5>();
|
||||
statics();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// MIR for `statics` after built
|
||||
|
||||
fn statics() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/consts.rs:+0:14: +0:14
|
||||
let mut _1: &i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
let mut _2: *mut i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_1 = const {alloc1: &i32}; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
// mir::Constant
|
||||
// + span: $DIR/consts.rs:27:31: 27:32
|
||||
// + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) }
|
||||
_2 = const {alloc2: *mut i32}; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
// mir::Constant
|
||||
// + span: $DIR/consts.rs:28:38: 28:39
|
||||
// + literal: Const { ty: *mut i32, val: Value(Scalar(alloc2)) }
|
||||
return; // scope 0 at $DIR/consts.rs:+4:9: +4:17
|
||||
}
|
||||
}
|
||||
|
||||
alloc2 (static: T, size: 4, align: 4) {
|
||||
0a 00 00 00 │ ....
|
||||
}
|
||||
|
||||
alloc1 (static: S, size: 4, align: 4) {
|
||||
05 00 00 00 │ ....
|
||||
}
|
@ -5,10 +5,10 @@ fn immut_ref(_1: &i32) -> &i32 {
|
||||
let mut _2: *const i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_2 = &raw const (*_1); // scope 0 at $DIR/references.rs:+0:1: +0:34
|
||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+0:1: +0:34
|
||||
_0 = &(*_2); // scope 0 at $DIR/references.rs:+0:1: +0:34
|
||||
Retag(_0); // scope 0 at $DIR/references.rs:+0:1: +0:34
|
||||
return; // scope 0 at $DIR/references.rs:+0:1: +0:34
|
||||
_2 = &raw const (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:29
|
||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+6:13: +6:24
|
||||
_0 = &(*_2); // scope 0 at $DIR/references.rs:+7:13: +7:23
|
||||
Retag(_0); // scope 0 at $DIR/references.rs:+8:13: +8:23
|
||||
return; // scope 0 at $DIR/references.rs:+9:13: +9:21
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ fn mut_ref(_1: &mut i32) -> &mut i32 {
|
||||
let mut _2: *mut i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_2 = &raw mut (*_1); // scope 0 at $DIR/references.rs:+0:1: +0:40
|
||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+0:1: +0:40
|
||||
_0 = &mut (*_2); // scope 0 at $DIR/references.rs:+0:1: +0:40
|
||||
Retag(_0); // scope 0 at $DIR/references.rs:+0:1: +0:40
|
||||
return; // scope 0 at $DIR/references.rs:+0:1: +0:40
|
||||
_2 = &raw mut (*_1); // scope 0 at $DIR/references.rs:+5:13: +5:33
|
||||
Retag([raw] _2); // scope 0 at $DIR/references.rs:+6:13: +6:24
|
||||
_0 = &mut (*_2); // scope 0 at $DIR/references.rs:+7:13: +7:26
|
||||
Retag(_0); // scope 0 at $DIR/references.rs:+8:13: +8:23
|
||||
return; // scope 0 at $DIR/references.rs:+9:13: +9:21
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ fn simple(_1: i32) -> i32 {
|
||||
let mut _3: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_2 = _1; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
|
||||
goto -> bb1; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
|
||||
_2 = _1; // scope 0 at $DIR/simple_assign.rs:+6:13: +6:22
|
||||
goto -> bb1; // scope 0 at $DIR/simple_assign.rs:+7:13: +7:23
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_3 = move _2; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
|
||||
_0 = _3; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
|
||||
return; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
|
||||
_3 = move _2; // scope 0 at $DIR/simple_assign.rs:+11:13: +11:32
|
||||
_0 = _3; // scope 0 at $DIR/simple_assign.rs:+12:13: +12:24
|
||||
return; // scope 0 at $DIR/simple_assign.rs:+13:13: +13:21
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ fn simple_ref(_1: &mut i32) -> &mut i32 {
|
||||
let mut _0: &mut i32; // return place in scope 0 at $DIR/simple_assign.rs:+0:35: +0:43
|
||||
|
||||
bb0: {
|
||||
_0 = move _1; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
|
||||
return; // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
|
||||
_0 = move _1; // scope 0 at $DIR/simple_assign.rs:+2:9: +2:22
|
||||
return; // scope 0 at $DIR/simple_assign.rs:+3:9: +3:17
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user