diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 8c1767501d9..41ab4007a67 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -36,6 +36,7 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { .collect(), self.arg_count, self.var_debug_info.iter().map(|info| info.stable(tables)).collect(), + self.spread_arg.stable(tables), ) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 7d8339ab503..7021bdda735 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -57,7 +57,9 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { stable_mir::mir::CoroutineKind::Gen(source.stable(tables)) } CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine, - CoroutineKind::AsyncGen(_) => todo!(), + CoroutineKind::AsyncGen(source) => { + stable_mir::mir::CoroutineKind::AsyncGen(source.stable(tables)) + } } } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 3dfe7096399..5023af9ab79 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -22,6 +22,11 @@ pub struct Body { /// Debug information pertaining to user variables, including captures. pub var_debug_info: Vec, + + /// Mark an argument (which must be a tuple) as getting passed as its individual components. + /// + /// This is used for the "rust-call" ABI such as closures. + pub(super) spread_arg: Option, } pub type BasicBlockIdx = usize; @@ -36,6 +41,7 @@ impl Body { locals: LocalDecls, arg_count: usize, var_debug_info: Vec, + spread_arg: Option, ) -> Self { // If locals doesn't contain enough entries, it can lead to panics in // `ret_local`, `arg_locals`, and `inner_locals`. @@ -43,7 +49,7 @@ impl Body { locals.len() > arg_count, "A Body must contain at least a local for the return value and each of the function's arguments" ); - Self { blocks, locals, arg_count, var_debug_info } + Self { blocks, locals, arg_count, var_debug_info, spread_arg } } /// Return local that holds this function's return value. @@ -75,6 +81,11 @@ impl Body { self.locals.get(local) } + /// Get an iterator for all local declarations. + pub fn local_decls(&self) -> impl Iterator { + self.locals.iter().enumerate() + } + pub fn dump(&self, w: &mut W) -> io::Result<()> { writeln!(w, "{}", function_body(self))?; self.blocks @@ -98,6 +109,10 @@ impl Body { .collect::, _>>()?; Ok(()) } + + pub fn spread_arg(&self) -> Option { + self.spread_arg + } } type LocalDecls = Vec; @@ -248,6 +263,57 @@ pub enum AssertMessage { MisalignedPointerDereference { required: Operand, found: Operand }, } +impl AssertMessage { + pub fn description(&self) -> Result<&'static str, Error> { + match self { + AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"), + AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"), + AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"), + AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"), + AssertMessage::Overflow(BinOp::Rem, _, _) => { + Ok("attempt to calculate the remainder with overflow") + } + AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"), + AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"), + AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"), + AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)), + AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"), + AssertMessage::RemainderByZero(_) => { + Ok("attempt to calculate the remainder with a divisor of zero") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine) => { + Ok("coroutine resumed after completion") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::Async(_)) => { + Ok("`async fn` resumed after completion") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::Gen(_)) => { + Ok("`async gen fn` resumed after completion") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => { + Ok("`gen fn` should just keep returning `AssertMessage::None` after completion") + } + AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine) => { + Ok("coroutine resumed after panicking") + } + AssertMessage::ResumedAfterPanic(CoroutineKind::Async(_)) => { + Ok("`async fn` resumed after panicking") + } + AssertMessage::ResumedAfterPanic(CoroutineKind::Gen(_)) => { + Ok("`async gen fn` resumed after panicking") + } + AssertMessage::ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => { + Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking") + } + + AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"), + AssertMessage::MisalignedPointerDereference { .. } => { + Ok("misaligned pointer dereference") + } + } + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum BinOp { Add, @@ -325,6 +391,7 @@ pub enum CoroutineKind { Async(CoroutineSource), Coroutine, Gen(CoroutineSource), + AsyncGen(CoroutineSource), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 3a0eed521dc..e1cad1fa536 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -243,6 +243,7 @@ pub fn pretty_assert_message(msg: &AssertMessage) -> String { ); pretty } + AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op), AssertMessage::OverflowNeg(op) => { let pretty_op = pretty_operand(op); pretty.push_str( @@ -262,17 +263,15 @@ pub fn pretty_assert_message(msg: &AssertMessage) -> String { ); pretty } - AssertMessage::ResumedAfterReturn(_) => { - format!("attempt to resume a generator after completion") - } - AssertMessage::ResumedAfterPanic(_) => format!("attempt to resume a panicked generator"), AssertMessage::MisalignedPointerDereference { required, found } => { let pretty_required = pretty_operand(required); let pretty_found = pretty_operand(found); pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str()); pretty } - _ => todo!(), + AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { + msg.description().unwrap().to_string() + } } } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index d46caad9a01..98336a72900 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -133,7 +133,7 @@ pub trait MirVisitor { } fn super_body(&mut self, body: &Body) { - let Body { blocks, locals: _, arg_count, var_debug_info } = body; + let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _ } = body; for bb in blocks { self.visit_basic_block(bb); diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index f473fd8dbb7..1fb32621119 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -6,6 +6,7 @@ use super::{ use crate::crate_def::CrateDef; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::target::MachineInfo; +use crate::ty::UintTy::U8; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; @@ -22,9 +23,7 @@ impl Debug for Ty { /// Constructors for `Ty`. impl Ty { /// Create a new type from a given kind. - /// - /// Note that not all types may be supported at this point. - fn from_rigid_kind(kind: RigidTy) -> Ty { + pub fn from_rigid_kind(kind: RigidTy) -> Ty { with(|cx| cx.new_rigid_ty(kind)) } @@ -77,6 +76,11 @@ impl Ty { pub fn bool_ty() -> Ty { Ty::from_rigid_kind(RigidTy::Bool) } + + /// Create a type representing `u8`. + pub fn u8_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Uint(U8)) + } } impl Ty {