Skip to content

Commit

Permalink
Rollup merge of rust-lang#117688 - celinval:smir-kani-reach, r=compil…
Browse files Browse the repository at this point in the history
…er-errors

Misc changes to StableMIR required to Kani use case.

First, I wanted to say that I can split this review into multiple if it makes reviewing easier. I bundled them up, since I've been testing them together (See rust-lang/project-stable-mir#51 for the set of more thorough checks).

So far, this review includes 3 commits:

1. Add more APIs and fix `Instance::body`
    - Add more APIs to retrieve information about types.
    - Add a few more instance resolution options. For the drop shim, we return None if the drop body is empty. Not sure it will be enough.
    - Make `Instance::body()` return an Option<Body>, since not every instance might have an available body. For example, foreign instances, virtual instances, dependencies.
2. Fix a bug on MIRVisitor
    - We were not iterating over all local variables due to a typo.
3. Add more SMIR internal impl and callback return value
    - In cases like Kani, we will invoke the rustc_internal run command directly for now. It would be handly to be able to have a callback that can return a value.
    - We also need extra methods to convert stable constructs into internal ones, so we can break down the transition into finer grain commits.
    - For the internal implementation of Region, we're always returning `ReErased` for now.
  • Loading branch information
matthiaskrgr authored Nov 17, 2023
2 parents 1cabedc + 8e81fc0 commit c188486
Show file tree
Hide file tree
Showing 12 changed files with 583 additions and 72 deletions.
136 changes: 132 additions & 4 deletions compiler/rustc_smir/src/rustc_internal/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@
// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
use crate::rustc_smir::Tables;
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
use stable_mir::DefId;
use rustc_span::Symbol;
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
use stable_mir::ty::{
Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, GenericArgKind,
GenericArgs, Region, TraitRef, Ty,
};
use stable_mir::{AllocId, CrateItem, DefId};

use super::RustcInternal;

impl<'tcx> RustcInternal<'tcx> for CrateItem {
type T = rustc_span::def_id::DefId;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
self.0.internal(tables)
}
}

impl<'tcx> RustcInternal<'tcx> for DefId {
type T = rustc_span::def_id::DefId;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
Expand Down Expand Up @@ -38,8 +50,9 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind {

impl<'tcx> RustcInternal<'tcx> for Region {
type T = rustc_ty::Region<'tcx>;
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
todo!()
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
// Cannot recover region. Use erased instead.
tables.tcx.lifetimes.re_erased
}
}

Expand All @@ -65,3 +78,118 @@ impl<'tcx> RustcInternal<'tcx> for Const {
tables.constants[self.id]
}
}

impl<'tcx> RustcInternal<'tcx> for MonoItem {
type T = rustc_middle::mir::mono::MonoItem<'tcx>;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::mir::mono as rustc_mono;
match self {
MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables)),
MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables)),
MonoItem::GlobalAsm(_) => {
unimplemented!()
}
}
}
}

impl<'tcx> RustcInternal<'tcx> for Instance {
type T = rustc_ty::Instance<'tcx>;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
tables.instances[self.def]
}
}

impl<'tcx> RustcInternal<'tcx> for StaticDef {
type T = rustc_span::def_id::DefId;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
self.0.internal(tables)
}
}

#[allow(rustc::usage_of_qualified_ty)]
impl<'tcx, T> RustcInternal<'tcx> for Binder<T>
where
T: RustcInternal<'tcx>,
T::T: rustc_ty::TypeVisitable<rustc_ty::TyCtxt<'tcx>>,
{
type T = rustc_ty::Binder<'tcx, T::T>;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
rustc_ty::Binder::bind_with_vars(
self.value.internal(tables),
tables.tcx.mk_bound_variable_kinds_from_iter(
self.bound_vars.iter().map(|bound| bound.internal(tables)),
),
)
}
}

impl<'tcx> RustcInternal<'tcx> for BoundVariableKind {
type T = rustc_ty::BoundVariableKind;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
match self {
BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind {
BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon,
BoundTyKind::Param(def, symbol) => {
rustc_ty::BoundTyKind::Param(def.0.internal(tables), Symbol::intern(&symbol))
}
}),
BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind {
BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::BrAnon,
BoundRegionKind::BrNamed(def, symbol) => rustc_ty::BoundRegionKind::BrNamed(
def.0.internal(tables),
Symbol::intern(&symbol),
),
BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::BrEnv,
}),
BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const,
}
}
}

impl<'tcx> RustcInternal<'tcx> for TraitRef {
type T = rustc_ty::TraitRef<'tcx>;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
rustc_ty::TraitRef::new(
tables.tcx,
self.def_id.0.internal(tables),
self.args().internal(tables),
)
}
}

impl<'tcx> RustcInternal<'tcx> for AllocId {
type T = rustc_middle::mir::interpret::AllocId;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
tables.alloc_ids[*self]
}
}

impl<'tcx> RustcInternal<'tcx> for ClosureKind {
type T = rustc_ty::ClosureKind;

fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
match self {
ClosureKind::Fn => rustc_ty::ClosureKind::Fn,
ClosureKind::FnMut => rustc_ty::ClosureKind::FnMut,
ClosureKind::FnOnce => rustc_ty::ClosureKind::FnOnce,
}
}
}

impl<'tcx, T> RustcInternal<'tcx> for &T
where
T: RustcInternal<'tcx>,
{
type T = T::T;

fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
(*self).internal(tables)
}
}
24 changes: 15 additions & 9 deletions compiler/rustc_smir/src/rustc_internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Span;
use scoped_tls::scoped_thread_local;
use stable_mir::ty::IndexedVal;
use stable_mir::Error;
use std::cell::Cell;
use std::cell::RefCell;
use std::fmt::Debug;
Expand All @@ -21,11 +22,11 @@ use std::ops::Index;

mod internal;

pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T {
with_tables(|tables| item.stable(tables))
}

pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T {
with_tables(|tables| item.internal(tables))
}

Expand Down Expand Up @@ -144,12 +145,13 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
// datastructures and stable MIR datastructures
scoped_thread_local! (static TLV: Cell<*const ()>);

pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T
where
F: FnOnce() -> T,
{
assert!(!TLV.is_set());
let ptr = tables as *const _ as *const ();
TLV.set(&Cell::new(ptr), || {
f();
});
TLV.set(&Cell::new(ptr), || f())
}

/// Loads the current context and calls a function with it.
Expand All @@ -165,7 +167,10 @@ pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R
})
}

pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
where
F: FnOnce() -> T,
{
let tables = TablesWrapper(RefCell::new(Tables {
tcx,
def_ids: IndexMap::default(),
Expand All @@ -175,7 +180,7 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
instances: IndexMap::default(),
constants: IndexMap::default(),
}));
stable_mir::run(&tables, || init(&tables, f));
stable_mir::run(&tables, || init(&tables, f))
}

#[macro_export]
Expand Down Expand Up @@ -241,7 +246,8 @@ macro_rules! run {
queries.global_ctxt().unwrap().enter(|tcx| {
rustc_internal::run(tcx, || {
self.result = Some((self.callback)(tcx));
});
})
.unwrap();
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
Compilation::Continue
} else {
Expand Down
23 changes: 21 additions & 2 deletions compiler/rustc_smir/src/rustc_smir/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ impl<'tcx> BodyBuilder<'tcx> {
BodyBuilder { tcx, instance }
}

/// Build a stable monomorphic body for a given instance based on the MIR body.
///
/// Note that we skip instantiation for static and constants. Trying to do so can cause ICE.
///
/// We do monomorphize non-generic functions to eval unevaluated constants.
pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
let mut body = self.tcx.instance_mir(self.instance.def).clone();
let generics = self.tcx.generics_of(self.instance.def_id());
if generics.requires_monomorphization(self.tcx) {
if self.tcx.def_kind(self.instance.def_id()).is_fn_like() || !self.instance.args.is_empty()
{
self.visit_body(&mut body);
}
body.stable(tables)
Expand All @@ -49,6 +54,20 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
*ty = self.monomorphize(*ty);
}

fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
let const_ = self.monomorphize(constant.const_);
let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) {
Ok(v) => v,
Err(mir::interpret::ErrorHandled::Reported(..)) => return,
Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
unreachable!("Failed to evaluate instance constant: {:?}", const_)
}
};
let ty = constant.ty();
constant.const_ = mir::Const::Val(val, ty);
self.super_constant(constant, location);
}

fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
Expand Down
Loading

0 comments on commit c188486

Please sign in to comment.