rust-lang / rust-lang/rustc_public

Panic when calling `Ty::layout` with escaping bound vars

Open
#94 3 comments 0 reactions 1 assignee View on GitHub

@celinval is already working on this.

Since Feb 27, 2025.

Dominant language
Rust
Stars
125
Forks
19
PR merge metrics
No merged PRs in 30d

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.