Skip to content

Commit b88325c

Browse files
committed
Isolate rustc internal API usage behind a compat module
Concentrate all rustc-internal API calls into src/compat/ so that toolchain upgrades touch one module (plus driver.rs) instead of the whole codebase. New module layout: src/compat/mod.rs - centralized extern crate + re-exports src/compat/bridge.rs - OpaqueInstanceKind, internal conversions src/compat/mono_collect.rs - mono item collection and symbol naming src/compat/spans.rs - span-to-source-location resolution src/compat/types.rs - type queries (generics, fn sigs, attrs) src/compat/output.rs - output filename resolution Key change: replace middle::ty::InstanceKind<'tcx> with an owned OpaqueInstanceKind { debug_repr, is_reify_shim }, eliminating the 'tcx lifetime parameter from SmirJson, LinkMapKey, FnSymInfo, LinkMap, DerivedInfo, and SmirJsonDebugInfo. After this, printer.rs has zero extern crate rustc_* declarations and zero direct tcx.query() calls.
1 parent d699451 commit b88325c

File tree

12 files changed

+451
-258
lines changed

12 files changed

+451
-258
lines changed

src/compat/bridge.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! Stable<->internal conversions and OpaqueInstanceKind.
2+
//!
3+
//! This module wraps rustc-internal instance kind queries behind an owned,
4+
//! lifetime-free representation so that the rest of the codebase doesn't
5+
//! need to carry `'tcx` lifetimes for link map keys.
6+
7+
use std::hash::{Hash, Hasher};
8+
9+
use super::middle;
10+
use super::rustc_internal;
11+
use super::stable_mir;
12+
use super::TyCtxt;
13+
use stable_mir::mir::mono::Instance;
14+
15+
/// Owned, lifetime-free replacement for `middle::ty::InstanceKind<'tcx>`.
16+
///
17+
/// The actual `InstanceKind` usage is narrow:
18+
/// 1. Serialized as `format!("{:?}", kind)` (a Debug string)
19+
/// 2. Checked via `is_reify_shim()` (a single pattern match)
20+
/// 3. Used for `Hash`/`Eq` in `LinkMapKey` (map keying)
21+
///
22+
/// This struct captures all three via owned data, eliminating the need
23+
/// to propagate the `'tcx` lifetime through `LinkMapKey`, `FnSymInfo`,
24+
/// `SmirJson`, and `SmirJsonDebugInfo`.
25+
#[derive(Clone, Debug)]
26+
pub struct OpaqueInstanceKind {
27+
debug_repr: String,
28+
pub is_reify_shim: bool,
29+
}
30+
31+
impl PartialEq for OpaqueInstanceKind {
32+
fn eq(&self, other: &Self) -> bool {
33+
self.debug_repr == other.debug_repr
34+
}
35+
}
36+
37+
impl Eq for OpaqueInstanceKind {}
38+
39+
impl Hash for OpaqueInstanceKind {
40+
fn hash<H: Hasher>(&self, state: &mut H) {
41+
self.debug_repr.hash(state);
42+
}
43+
}
44+
45+
impl std::fmt::Display for OpaqueInstanceKind {
46+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47+
write!(f, "{}", self.debug_repr)
48+
}
49+
}
50+
51+
/// Create a monomorphized Instance from a stable DefId (wraps `Instance::mono`).
52+
pub fn mono_instance(tcx: TyCtxt<'_>, id: stable_mir::DefId) -> Instance {
53+
let internal_id = rustc_internal::internal(tcx, id);
54+
let internal_inst = middle::ty::Instance::mono(tcx, internal_id);
55+
rustc_internal::stable(internal_inst)
56+
}
57+
58+
/// Resolve an unevaluated constant into a (MonoItem, symbol_name) pair.
59+
///
60+
/// This wraps `middle::ty::Instance::try_resolve` and the internal mono item
61+
/// symbol name resolution, keeping those internal APIs out of printer.rs.
62+
pub fn resolve_unevaluated_const(
63+
tcx: TyCtxt<'_>,
64+
def_id: stable_mir::DefId,
65+
args: stable_mir::ty::GenericArgs,
66+
) -> (stable_mir::mir::mono::MonoItem, String) {
67+
use super::middle::ty::TypingEnv;
68+
let internal_def = rustc_internal::internal(tcx, def_id);
69+
let internal_args = rustc_internal::internal(tcx, args);
70+
let maybe_inst = middle::ty::Instance::try_resolve(
71+
tcx,
72+
TypingEnv::post_analysis(tcx, internal_def),
73+
internal_def,
74+
internal_args,
75+
);
76+
let inst = maybe_inst
77+
.ok()
78+
.flatten()
79+
.unwrap_or_else(|| panic!("Failed to resolve mono item for def {:?}", def_id));
80+
let internal_mono_item = middle::mir::mono::MonoItem::Fn(inst);
81+
let item_name = crate::compat::mono_collect::mono_item_name_int(tcx, &internal_mono_item);
82+
(rustc_internal::stable(internal_mono_item), item_name)
83+
}
84+
85+
/// Extract an `OpaqueInstanceKind` from a stable MIR `Instance` by
86+
/// converting to the internal representation and capturing the debug
87+
/// string and reify-shim flag.
88+
pub fn instance_kind(tcx: TyCtxt<'_>, inst: &Instance) -> OpaqueInstanceKind {
89+
let internal_inst = rustc_internal::internal(tcx, inst);
90+
let kind = internal_inst.def;
91+
OpaqueInstanceKind {
92+
debug_repr: format!("{:?}", kind),
93+
is_reify_shim: matches!(kind, middle::ty::InstanceKind::ReifyShim(..)),
94+
}
95+
}

src/compat/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//! Compatibility layer for rustc internal APIs.
2+
//!
3+
//! All `extern crate rustc_*` declarations and direct `TyCtxt` queries live
4+
//! here so that toolchain upgrades only need to touch this module (plus
5+
//! `driver.rs`).
6+
7+
pub extern crate rustc_middle;
8+
pub extern crate rustc_monomorphize;
9+
pub extern crate rustc_session;
10+
pub extern crate rustc_smir;
11+
pub extern crate rustc_span;
12+
pub extern crate stable_mir;
13+
14+
// HACK: typically, we would source serde/serde_json separately from the compiler.
15+
// However, due to issues matching crate versions when we have our own serde
16+
// in addition to the rustc serde, we force ourselves to use rustc serde.
17+
pub extern crate serde;
18+
pub extern crate serde_json;
19+
20+
pub use rustc_middle as middle;
21+
pub use rustc_middle::ty::TyCtxt;
22+
pub use rustc_smir::rustc_internal;
23+
pub use rustc_smir::rustc_internal::internal;
24+
25+
pub mod bridge;
26+
pub mod mono_collect;
27+
pub mod output;
28+
pub mod spans;
29+
pub mod types;

src/compat/mono_collect.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! Mono item collection and symbol naming.
2+
//!
3+
//! Wraps `tcx.collect_and_partition_mono_items()`, `item.symbol_name()`,
4+
//! and the `rustc_internal` stable/internal conversions needed for naming.
5+
6+
use super::middle;
7+
use super::rustc_internal;
8+
use super::stable_mir;
9+
use super::TyCtxt;
10+
use stable_mir::mir::mono::MonoItem;
11+
12+
/// Collect all monomorphized items from the compiler.
13+
pub fn mono_collect(tcx: TyCtxt<'_>) -> Vec<MonoItem> {
14+
let units = tcx.collect_and_partition_mono_items(()).1;
15+
units
16+
.iter()
17+
.flat_map(|unit| {
18+
unit.items_in_deterministic_order(tcx)
19+
.iter()
20+
.map(|(internal_item, _)| rustc_internal::stable(internal_item))
21+
.collect::<Vec<_>>()
22+
})
23+
.collect()
24+
}
25+
26+
/// Get the symbol name for a mono item (the mangled linker name).
27+
pub fn mono_item_name(tcx: TyCtxt<'_>, item: &MonoItem) -> String {
28+
if let MonoItem::GlobalAsm(data) = item {
29+
crate::printer::hash(data).to_string()
30+
} else {
31+
mono_item_name_int(tcx, &rustc_internal::internal(tcx, item))
32+
}
33+
}
34+
35+
/// Get the symbol name for an internal (non-stable) mono item.
36+
pub fn mono_item_name_int<'a>(tcx: TyCtxt<'a>, item: &middle::mir::mono::MonoItem<'a>) -> String {
37+
item.symbol_name(tcx).name.into()
38+
}

src/compat/output.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! Output filename resolution.
2+
//!
3+
//! Wraps `tcx.output_filenames().path(OutputType::Mir)` so that callers
4+
//! don't need to import `rustc_session` directly.
5+
6+
use std::path::PathBuf;
7+
8+
use super::rustc_session::config::{OutFileName, OutputType};
9+
use super::TyCtxt;
10+
11+
/// Resolved output destination for MIR-derived files.
12+
pub enum OutputDest {
13+
Stdout,
14+
File(PathBuf),
15+
}
16+
17+
/// Resolve the MIR output path from the compiler session, replacing
18+
/// the extension with the given one.
19+
pub fn mir_output_path(tcx: TyCtxt<'_>, extension: &str) -> OutputDest {
20+
match tcx.output_filenames(()).path(OutputType::Mir) {
21+
OutFileName::Stdout => OutputDest::Stdout,
22+
OutFileName::Real(path) => OutputDest::File(path.with_extension(extension)),
23+
}
24+
}

src/compat/spans.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Span-to-source-location resolution.
2+
//!
3+
//! Wraps the `source_map().span_to_location_info()` internal API
4+
//! so that callers don't need to touch `rustc_span` directly.
5+
6+
use super::internal;
7+
use super::rustc_span;
8+
use super::stable_mir;
9+
use super::TyCtxt;
10+
use stable_mir::ty::Span;
11+
12+
pub type SourceData = (String, usize, usize, usize, usize);
13+
14+
/// Resolve a stable MIR span to a (file, lo_line, lo_col, hi_line, hi_col) tuple.
15+
pub fn resolve_span(tcx: TyCtxt<'_>, span: &Span) -> SourceData {
16+
let span_internal = internal(tcx, span);
17+
let (source_file, lo_line, lo_col, hi_line, hi_col) =
18+
tcx.sess.source_map().span_to_location_info(span_internal);
19+
let file_name = match source_file {
20+
Some(sf) => sf
21+
.name
22+
.display(rustc_span::FileNameDisplayPreference::Remapped)
23+
.to_string(),
24+
None => "no-location".to_string(),
25+
};
26+
(file_name, lo_line, lo_col, hi_line, hi_col)
27+
}

src/compat/types.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//! Type queries (generics, fn sigs, discriminants, attrs).
2+
//!
3+
//! Wraps `tcx.generics_of()`, `tcx.predicates_of()`, `tcx.fn_sig()`,
4+
//! `tcx.optimized_mir()`, `tcx.def_kind()`, `tcx.type_of()`,
5+
//! `tcx.has_attr()`, `adt.discriminants(tcx)`, and `tcx.fn_abi_of_fn_ptr()`.
6+
7+
use super::middle;
8+
use super::middle::ty::{EarlyBinder, FnSig, GenericArgs, List, Ty, TypeFoldable, TypingEnv};
9+
use super::rustc_internal::{self, internal};
10+
use super::rustc_span;
11+
use super::stable_mir;
12+
use super::TyCtxt;
13+
use rustc_span::def_id::DefId;
14+
15+
/// Collect generics/predicates chain for a DefId, walking parent scopes.
16+
pub fn generic_data(tcx: TyCtxt<'_>, id: DefId) -> Vec<(String, String)> {
17+
let mut v = Vec::new();
18+
let mut next_id = Some(id);
19+
while let Some(curr_id) = next_id {
20+
let params = tcx.generics_of(curr_id);
21+
let preds = tcx.predicates_of(curr_id);
22+
if params.parent != preds.parent {
23+
panic!("Generics and predicates parent ids are distinct");
24+
}
25+
v.push((format!("{:#?}", params), format!("{:#?}", preds)));
26+
next_id = params.parent;
27+
}
28+
v.reverse();
29+
v
30+
}
31+
32+
/// Unwrap an `EarlyBinder` in a default manner; panic on error.
33+
pub fn default_unwrap_early_binder<'tcx, T>(
34+
tcx: TyCtxt<'tcx>,
35+
id: DefId,
36+
v: EarlyBinder<'tcx, T>,
37+
) -> T
38+
where
39+
T: TypeFoldable<TyCtxt<'tcx>>,
40+
{
41+
let v_copy = v.clone();
42+
let body = tcx.optimized_mir(id);
43+
match tcx.try_instantiate_and_normalize_erasing_regions(
44+
GenericArgs::identity_for_item(tcx, id),
45+
body.typing_env(tcx),
46+
v,
47+
) {
48+
Ok(res) => res,
49+
Err(err) => {
50+
println!("{:?}", err);
51+
v_copy.skip_binder()
52+
}
53+
}
54+
}
55+
56+
/// Pretty-print a type, resolving FnDef signatures via `tcx.fn_sig()`.
57+
pub fn print_type<'tcx>(tcx: TyCtxt<'tcx>, id: DefId, ty: EarlyBinder<'tcx, Ty<'tcx>>) -> String {
58+
let kind: &middle::ty::TyKind = ty.skip_binder().kind();
59+
if let middle::ty::TyKind::FnDef(fun_id, args) = kind {
60+
let sig0 = tcx.fn_sig(fun_id);
61+
let body = tcx.optimized_mir(id);
62+
let sig1 = match tcx.try_instantiate_and_normalize_erasing_regions(
63+
args,
64+
body.typing_env(tcx),
65+
sig0,
66+
) {
67+
Ok(res) => res,
68+
Err(err) => {
69+
println!("{:?}", err);
70+
sig0.skip_binder()
71+
}
72+
};
73+
let sig2: FnSig<'_> = tcx.instantiate_bound_regions_with_erased(sig1);
74+
format!("\nTyKind(FnDef): {:#?}", sig2)
75+
} else {
76+
let kind = default_unwrap_early_binder(tcx, id, ty);
77+
format!("\nTyKind: {:#?}", kind)
78+
}
79+
}
80+
81+
/// Query the def_kind, def_path, and type_of for a DefId (debug info).
82+
pub fn get_def_info(tcx: TyCtxt<'_>, id: DefId) -> (String, String, String) {
83+
(
84+
format!("{:#?}", tcx.def_kind(id)),
85+
tcx.def_path_str(id),
86+
print_type(tcx, id, tcx.type_of(id)),
87+
)
88+
}
89+
90+
/// Check whether a CrateItem has a given attribute.
91+
pub fn has_attr(
92+
tcx: TyCtxt<'_>,
93+
item: &stable_mir::CrateItem,
94+
attr: rustc_span::symbol::Symbol,
95+
) -> bool {
96+
tcx.has_attr(rustc_internal::internal(tcx, item), attr)
97+
}
98+
99+
/// Collect discriminant values for an ADT (enum) by going through internals.
100+
pub fn adt_discriminants(tcx: TyCtxt<'_>, adt_def: stable_mir::ty::AdtDef) -> Vec<u128> {
101+
let adt_internal = rustc_internal::internal(tcx, adt_def);
102+
adt_internal
103+
.discriminants(tcx)
104+
.map(|(_, discr)| discr.val)
105+
.collect()
106+
}
107+
108+
/// Resolve the ABI of a function pointer type (via `tcx.fn_abi_of_fn_ptr`).
109+
pub fn fn_ptr_abi(
110+
tcx: TyCtxt<'_>,
111+
binder_stable: stable_mir::ty::PolyFnSig,
112+
) -> stable_mir::abi::FnAbi {
113+
let binder_internal = internal(tcx, binder_stable);
114+
rustc_internal::stable(
115+
tcx.fn_abi_of_fn_ptr(
116+
TypingEnv::fully_monomorphized().as_query_input((binder_internal, List::empty())),
117+
)
118+
.unwrap(),
119+
)
120+
}
121+
122+
/// Convert a stable DefId to an internal DefId.
123+
pub fn internal_def_id(tcx: TyCtxt<'_>, id: stable_mir::DefId) -> DefId {
124+
rustc_internal::internal(tcx, id)
125+
}
126+
127+
/// Get the stable crate ID for the local crate.
128+
pub fn local_crate_id(tcx: TyCtxt<'_>) -> u64 {
129+
tcx.stable_crate_id(rustc_span::def_id::LOCAL_CRATE)
130+
.as_u64()
131+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(rustc_private)]
2+
pub mod compat;
23
pub mod driver;
34
pub mod mk_graph;
45
pub mod printer;

src/main.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
#![feature(rustc_private)]
2-
use std::env;
3-
pub mod driver;
4-
pub mod printer;
5-
use driver::stable_mir_driver;
6-
use printer::emit_smir;
2+
use stable_mir_json::driver::stable_mir_driver;
73
use stable_mir_json::mk_graph::{emit_d2file, emit_dotfile};
4+
use stable_mir_json::printer::emit_smir;
5+
use std::env;
86

97
fn main() {
108
let mut args: Vec<String> = env::args().collect();

0 commit comments

Comments
 (0)