Skip to content

Panic when calling Ty::layout with escaping bound vars #94

@dkcumming

Description

@dkcumming

When attempting to collect all the Layouts for Tys in a program I ran into a panic if there are escaping bound vars, which occurs if there is a dummy binder. Here is a (relatively) minimised example:

#![feature(rustc_private)]
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_smir;
extern crate stable_mir;

use rustc_driver::Compilation;
use rustc_interface::interface::Compiler;
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::mir::{
    mono::{Instance, MonoItem},
    visit::MirVisitor,
};
use std::{collections::HashMap, io::Write, iter::Iterator, vec::Vec};

fn main() {
    let path = "str-to-string.rs";
    generate_input(path).unwrap();
    let args = vec!["panicking-program".to_string(), path.to_string()];

    let mut callbacks = StableMirCallbacks {};
    let _ = rustc_driver::RunCompiler::new(&args, &mut callbacks).run();
}

struct StableMirCallbacks {}

impl rustc_driver::Callbacks for StableMirCallbacks {
    fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
        let _ = rustc_internal::run(tcx, || emit_mono_item_layouts(tcx));

        Compilation::Continue
    }
}

// Removed any emitting since it will panic beforehand
fn emit_mono_item_layouts(tcx: TyCtxt<'_>) {
    let items = mono_collect(tcx);

    // Filtering out the MonoItem "copy_nonoverlappings" that causes the layout to panic
    let erroring_instance: Instance = *items
        .iter()
        .find_map(|item| match item {
            MonoItem::Fn(instance) if instance.name().contains("copy_nonoverlapping") => {
                Some(instance)
            }
            _ => None,
        })
        .unwrap();

    // Call the layout collector
    let mut visited_tys = HashMap::new();
    LayoutCollector {
        visited_tys: &mut visited_tys,
    }
    .visit_body(&erroring_instance.body().unwrap())
}

fn mono_collect(tcx: TyCtxt<'_>) -> Vec<MonoItem> {
    let units = tcx.collect_and_partition_mono_items(()).1;
    units
        .iter()
        .flat_map(|unit| {
            unit.items_in_deterministic_order(tcx)
                .iter()
                .map(|(internal_item, _)| rustc_internal::stable(internal_item))
                .collect::<Vec<_>>()
        })
        .collect()
}

//-Layout Collector-//////////////////////////////
type TyAndLayoutMap = HashMap<u64, Result<stable_mir::abi::Layout, stable_mir::Error>>;

struct LayoutCollector<'local> {
    visited_tys: &'local mut TyAndLayoutMap,
}

fn collect_vec_tys(collector: &mut LayoutCollector, tys: Vec<stable_mir::ty::Ty>) {
    tys.into_iter().for_each(|ty| collect_ty(collector, ty));
}

fn collect_ty(val_collector: &mut LayoutCollector, val: stable_mir::ty::Ty) {
    use stable_mir::ty::{RigidTy::*, TyKind::RigidTy};

    let layout_or_err = val.layout(); // panics

    if val_collector
        .visited_tys
        .insert(hash(val), layout_or_err)
        .is_some()
    {
        if let kind @ RigidTy(FnDef(..)) = val.kind() {
            collect_vec_tys(
                val_collector,
                kind.fn_sig().unwrap().value.inputs_and_output,
            );
        }
    }
}

impl MirVisitor for LayoutCollector<'_> {
    fn visit_ty(&mut self, ty: &stable_mir::ty::Ty, _location: stable_mir::mir::visit::Location) {
        collect_ty(self, *ty);
    }
}

//-Utilities-////////////////////////////////////
fn hash<T: std::hash::Hash>(obj: T) -> u64 {
    use std::hash::Hasher;
    let mut hasher = std::hash::DefaultHasher::new();
    obj.hash(&mut hasher);
    hasher.finish()
}

// The failing code
fn generate_input(path: &str) -> std::io::Result<()> {
    let mut file = std::fs::File::create(path)?;
    write!(
        file,
        r#"
        fn main() {{
            "abcd".to_string();
        }}
        "#
    )?;
    Ok(())
}

With output:

thread 'rustc' panicked at compiler/rustc_middle/src/ty/predicate.rs:533:9:
`<[core::fmt::rt::Argument<'_>] as std::marker::Sized>` has escaping bound vars, so it cannot be wrapped in a dummy binder.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

And back trace:

thread 'rustc' panicked at compiler/rustc_middle/src/ty/predicate.rs:533:9:
`<[core::fmt::rt::Argument<'_>] as std::marker::Sized>` has escaping bound vars, so it cannot be wrapped in a dummy binder.
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rustc_ty_utils::common_traits::is_item_raw
      [... omitted 1 frame ...]
   3: <rustc_middle::ty::Ty>::is_sized
   4: rustc_ty_utils::layout::layout_of_uncached
   5: rustc_ty_utils::layout::layout_of
      [... omitted 1 frame ...]
   6: <core::iter::adapters::GenericShunt<core::iter::adapters::by_ref_sized::ByRefSized<core::iter::adapters::map::Map<core::slice::iter::Iter<rustc_middle::ty::VariantDef>, rustc_ty_utils::layout::layout_of_uncached::{closure#13}>>, core::result::Result<core::convert::Infallible, &rustc_middle::ty::layout::LayoutError>> as core::iter::traits::iterator::Iterator>::next
   7: rustc_ty_utils::layout::layout_of_uncached
   8: rustc_ty_utils::layout::layout_of
      [... omitted 1 frame ...]
   9: rustc_middle::query::plumbing::query_get_at::<rustc_query_system::query::caches::DefaultCache<rustc_middle::ty::PseudoCanonicalInput<rustc_middle::ty::Ty>, rustc_middle::query::erase::Erased<[u8; 16]>>>
  10: <rustc_smir::rustc_smir::context::TablesWrapper as stable_mir::compiler_interface::Context>::ty_layout
  11: <stable_mir::ty::Ty>::layout
  12: ice::collect_ty
             at ./src/main.rs:87:25
  13: ice::collect_vec_tys::{{closure}}
             at ./src/main.rs:81:35
  14: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:797:29
  15: <alloc::vec::into_iter::IntoIter<T,A> as core::iter::traits::iterator::Iterator>::fold
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/into_iter.rs:318:25
  16: core::iter::traits::iterator::Iterator::for_each
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:800:9
  17: ice::collect_vec_tys
             at ./src/main.rs:81:5
  18: ice::collect_ty
             at ./src/main.rs:95:13
  19: <ice::LayoutCollector as stable_mir::mir::visit::MirVisitor>::visit_ty
             at ./src/main.rs:105:9
  20: stable_mir::mir::visit::MirVisitor::super_mir_const
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:381:9
  21: stable_mir::mir::visit::MirVisitor::visit_mir_const
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:116:9
  22: stable_mir::mir::visit::MirVisitor::super_const_operand
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:376:9
  23: stable_mir::mir::visit::MirVisitor::visit_const_operand
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:112:9
  24: stable_mir::mir::visit::MirVisitor::super_operand
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:359:17
  25: stable_mir::mir::visit::MirVisitor::visit_operand
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:99:9
  26: stable_mir::mir::visit::MirVisitor::super_terminator
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:247:17
  27: stable_mir::mir::visit::MirVisitor::visit_terminator
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:68:9
  28: stable_mir::mir::visit::MirVisitor::super_basic_block
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:172:9
  29: stable_mir::mir::visit::MirVisitor::visit_basic_block
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:48:9
  30: stable_mir::mir::visit::MirVisitor::super_body
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:146:13
  31: stable_mir::mir::visit::MirVisitor::visit_body
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/mir/visit.rs:44:9
  32: ice::emit_mono_item_layouts
             at ./src/main.rs:54:5
  33: <ice::StableMirCallbacks as rustc_driver_impl::Callbacks>::after_analysis::{{closure}}
             at ./src/main.rs:31:45
  34: rustc_smir::rustc_internal::init::{{closure}}
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/rustc_smir/src/rustc_internal/mod.rs:192:33
  35: scoped_tls::ScopedKey<T>::set
             at /rust/deps/scoped-tls-1.0.1/src/lib.rs:137:9
  36: rustc_smir::rustc_internal::init
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/rustc_smir/src/rustc_internal/mod.rs:192:5
  37: rustc_smir::rustc_internal::run::{{closure}}
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/rustc_smir/src/rustc_internal/mod.rs:223:53
  38: stable_mir::compiler_interface::run::{{closure}}
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/compiler_interface.rs:265:40
  39: scoped_tls::ScopedKey<T>::set
             at /rust/deps/scoped-tls-1.0.1/src/lib.rs:137:9
  40: stable_mir::compiler_interface::run
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/stable_mir/src/compiler_interface.rs:265:9
  41: rustc_smir::rustc_internal::run
             at /home/daniel/.rustup/toolchains/nightly-2024-11-29-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/compiler/rustc_smir/src/rustc_internal/mod.rs:223:5
  42: <ice::StableMirCallbacks as rustc_driver_impl::Callbacks>::after_analysis
             at ./src/main.rs:31:17
  43: rustc_interface::interface::run_compiler::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions