Skip to content

Commit 53c2933

Browse files
committed
Auto merge of #30900 - michaelwoerister:trans_item_collect, r=nikomatsakis
The purpose of the translation item collector is to find all monomorphic instances of functions, methods and statics that need to be translated into LLVM IR in order to compile the current crate. So far these instances have been discovered lazily during the trans path. For incremental compilation we want to know the set of these instances in advance, and that is what the trans::collect module provides. In the future, incremental and regular translation will be driven by the collector implemented here. r? @nikomatsakis cc @rust-lang/compiler Translation Item Collection =========================== This module is responsible for discovering all items that will contribute to to code generation of the crate. The important part here is that it not only needs to find syntax-level items (functions, structs, etc) but also all their monomorphized instantiations. Every non-generic, non-const function maps to one LLVM artifact. Every generic function can produce from zero to N artifacts, depending on the sets of type arguments it is instantiated with. This also applies to generic items from other crates: A generic definition in crate X might produce monomorphizations that are compiled into crate Y. We also have to collect these here. The following kinds of "translation items" are handled here: - Functions - Methods - Closures - Statics - Drop glue The following things also result in LLVM artifacts, but are not collected here, since we instantiate them locally on demand when needed in a given codegen unit: - Constants - Vtables - Object Shims General Algorithm ----------------- Let's define some terms first: - A "translation item" is something that results in a function or global in the LLVM IR of a codegen unit. Translation items do not stand on their own, they can reference other translation items. For example, if function `foo()` calls function `bar()` then the translation item for `foo()` references the translation item for function `bar()`. In general, the definition for translation item A referencing a translation item B is that the LLVM artifact produced for A references the LLVM artifact produced for B. - Translation items and the references between them for a directed graph, where the translation items are the nodes and references form the edges. Let's call this graph the "translation item graph". - The translation item graph for a program contains all translation items that are needed in order to produce the complete LLVM IR of the program. The purpose of the algorithm implemented in this module is to build the translation item graph for the current crate. It runs in two phases: 1. Discover the roots of the graph by traversing the HIR of the crate. 2. Starting from the roots, find neighboring nodes by inspecting the MIR representation of the item corresponding to a given node, until no more new nodes are found. The roots of the translation item graph correspond to the non-generic syntactic items in the source code. We find them by walking the HIR of the crate, and whenever we hit upon a function, method, or static item, we create a translation item consisting of the items DefId and, since we only consider non-generic items, an empty type-substitution set. Given a translation item node, we can discover neighbors by inspecting its MIR. We walk the MIR and any time we hit upon something that signifies a reference to another translation item, we have found a neighbor. Since the translation item we are currently at is always monomorphic, we also know the concrete type arguments of its neighbors, and so all neighbors again will be monomorphic. The specific forms a reference to a neighboring node can take in MIR are quite diverse. Here is an overview: The most obvious form of one translation item referencing another is a function or method call (represented by a CALL terminator in MIR). But calls are not the only thing that might introduce a reference between two function translation items, and as we will see below, they are just a specialized of the form described next, and consequently will don't get any special treatment in the algorithm. A function does not need to actually be called in order to be a neighbor of another function. It suffices to just take a reference in order to introduce an edge. Consider the following example: ```rust fn print_val<T: Display>(x: T) { println!("{}", x); } fn call_fn(f: &Fn(i32), x: i32) { f(x); } fn main() { let print_i32 = print_val::<i32>; call_fn(&print_i32, 0); } ``` The MIR of none of these functions will contain an explicit call to `print_val::<i32>`. Nonetheless, in order to translate this program, we need an instance of this function. Thus, whenever we encounter a function or method in operand position, we treat it as a neighbor of the current translation item. Calls are just a special case of that. In a way, closures are a simple case. Since every closure object needs to be constructed somewhere, we can reliably discover them by observing `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also true for closures inlined from other crates. Drop glue translation items are introduced by MIR drop-statements. The generated translation item will again have drop-glue item neighbors if the type to be dropped contains nested values that also need to be dropped. It might also have a function item neighbor for the explicit `Drop::drop` implementation of its type. A subtle way of introducing neighbor edges is by casting to a trait object. Since the resulting fat-pointer contains a reference to a vtable, we need to instantiate all object-save methods of the trait, as we need to store pointers to these functions even if they never get called anywhere. This can be seen as a special case of taking a function reference. Since `Box` expression have special compiler support, no explicit calls to `exchange_malloc()` and `exchange_free()` may show up in MIR, even if the compiler will generate them. We have to observe `Rvalue::Box` expressions and Box-typed drop-statements for that purpose. Interaction with Cross-Crate Inlining ------------------------------------- The binary of a crate will not only contain machine code for the items defined in the source code of that crate. It will also contain monomorphic instantiations of any extern generic functions and of functions marked with The collection algorithm handles this more or less transparently. When constructing a neighbor node for an item, the algorithm will always call `inline::get_local_instance()` before proceeding. If no local instance can be acquired (e.g. for a function that is just linked to) no node is created; which is exactly what we want, since no machine code should be generated in the current crate for such an item. On the other hand, if we can successfully inline the function, we subsequently can just treat it like a local item, walking it's MIR et cetera. Eager and Lazy Collection Mode ------------------------------ Translation item collection can be performed in one of two modes: - Lazy mode means that items will only be instantiated when actually referenced. The goal is to produce the least amount of machine code possible. - Eager mode is meant to be used in conjunction with incremental compilation where a stable set of translation items is more important than a minimal one. Thus, eager mode will instantiate drop-glue for every drop-able type in the crate, even of no drop call for that type exists (yet). It will also instantiate default implementations of trait methods, something that otherwise is only done on demand. Open Issues ----------- Some things are not yet fully implemented in the current version of this module. Since no MIR is constructed yet for initializer expressions of constants and statics we cannot inspect these properly. Ideally, no translation item should be generated for const fns unless there is a call to them that cannot be evaluated at compile time. At the moment this is not implemented however: a translation item will be produced regardless of whether it is actually needed or not. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/rust-lang/rust/30900) <!-- Reviewable:end -->
2 parents 142214d + 4d074b8 commit 53c2933

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3342
-74
lines changed

configure

+1
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,7 @@ do
14091409
make_dir $h/test/debuginfo-gdb
14101410
make_dir $h/test/debuginfo-lldb
14111411
make_dir $h/test/codegen
1412+
make_dir $h/test/codegen-units
14121413
make_dir $h/test/rustdoc
14131414
done
14141415

mk/tests.mk

+11-1
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
310310
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \
311311
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \
312312
check-stage$(1)-T-$(2)-H-$(3)-codegen-exec \
313+
check-stage$(1)-T-$(2)-H-$(3)-codegen-units-exec \
313314
check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
314315
check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
315316

@@ -473,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
473474
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
474475
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
475476
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
477+
CODEGEN_UNITS_RS := $(wildcard $(S)src/test/codegen-units/*.rs)
476478
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
477479

478480
RPASS_TESTS := $(RPASS_RS)
@@ -488,6 +490,7 @@ PRETTY_TESTS := $(PRETTY_RS)
488490
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
489491
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
490492
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
493+
CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
491494
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
492495

493496
CTEST_SRC_BASE_rpass = run-pass
@@ -550,6 +553,11 @@ CTEST_BUILD_BASE_codegen = codegen
550553
CTEST_MODE_codegen = codegen
551554
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
552555

556+
CTEST_SRC_BASE_codegen-units = codegen-units
557+
CTEST_BUILD_BASE_codegen-units = codegen-units
558+
CTEST_MODE_codegen-units = codegen-units
559+
CTEST_RUNTOOL_codegen-units = $(CTEST_RUNTOOL)
560+
553561
CTEST_SRC_BASE_rustdocck = rustdoc
554562
CTEST_BUILD_BASE_rustdocck = rustdoc
555563
CTEST_MODE_rustdocck = rustdoc
@@ -673,6 +681,7 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
673681
$(S)src/etc/lldb_batchmode.py \
674682
$(S)src/etc/lldb_rust_formatters.py
675683
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
684+
CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS)
676685
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
677686
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
678687
$(S)src/etc/htmldocck.py
@@ -739,7 +748,7 @@ endif
739748
endef
740749

741750
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
742-
bench debuginfo-gdb debuginfo-lldb codegen rustdocck
751+
bench debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
743752

744753
$(foreach host,$(CFG_HOST), \
745754
$(eval $(foreach target,$(CFG_TARGET), \
@@ -917,6 +926,7 @@ TEST_GROUPS = \
917926
debuginfo-gdb \
918927
debuginfo-lldb \
919928
codegen \
929+
codegen-units \
920930
doc \
921931
$(foreach docname,$(DOC_NAMES),doc-$(docname)) \
922932
pretty \

src/compiletest/common.rs

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub enum Mode {
2525
DebugInfoLldb,
2626
Codegen,
2727
Rustdoc,
28+
CodegenUnits
2829
}
2930

3031
impl FromStr for Mode {
@@ -41,6 +42,7 @@ impl FromStr for Mode {
4142
"debuginfo-gdb" => Ok(DebugInfoGdb),
4243
"codegen" => Ok(Codegen),
4344
"rustdoc" => Ok(Rustdoc),
45+
"codegen-units" => Ok(CodegenUnits),
4446
_ => Err(()),
4547
}
4648
}
@@ -59,6 +61,7 @@ impl fmt::Display for Mode {
5961
DebugInfoLldb => "debuginfo-lldb",
6062
Codegen => "codegen",
6163
Rustdoc => "rustdoc",
64+
CodegenUnits => "codegen-units",
6265
}, f)
6366
}
6467
}

src/compiletest/runtest.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010

1111
use common::Config;
1212
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
13-
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc};
13+
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
1414
use errors;
1515
use header::TestProps;
1616
use header;
1717
use procsrv;
1818
use util::logv;
1919

2020
use std::env;
21+
use std::collections::HashSet;
2122
use std::fmt;
2223
use std::fs::{self, File};
2324
use std::io::BufReader;
@@ -56,6 +57,7 @@ pub fn run(config: Config, testfile: &Path) {
5657
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
5758
Codegen => run_codegen_test(&config, &props, &testfile),
5859
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
60+
CodegenUnits => run_codegen_units_test(&config, &props, &testfile),
5961
}
6062
}
6163

@@ -1747,3 +1749,44 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
17471749
fatal_proc_rec("htmldocck failed!", &res);
17481750
}
17491751
}
1752+
1753+
fn run_codegen_units_test(config: &Config, props: &TestProps, testfile: &Path) {
1754+
let proc_res = compile_test(config, props, testfile);
1755+
1756+
if !proc_res.status.success() {
1757+
fatal_proc_rec("compilation failed!", &proc_res);
1758+
}
1759+
1760+
check_no_compiler_crash(&proc_res);
1761+
1762+
let prefix = "TRANS_ITEM ";
1763+
1764+
let actual: HashSet<String> = proc_res
1765+
.stdout
1766+
.lines()
1767+
.filter(|line| line.starts_with(prefix))
1768+
.map(|s| (&s[prefix.len()..]).to_string())
1769+
.collect();
1770+
1771+
let expected: HashSet<String> = errors::load_errors(testfile)
1772+
.iter()
1773+
.map(|e| e.msg.trim().to_string())
1774+
.collect();
1775+
1776+
if actual != expected {
1777+
let mut missing: Vec<_> = expected.difference(&actual).collect();
1778+
missing.sort();
1779+
1780+
let mut too_much: Vec<_> = actual.difference(&expected).collect();
1781+
too_much.sort();
1782+
1783+
println!("Expected and actual sets of codegen-items differ.\n\
1784+
These items should have been contained but were not:\n\n\
1785+
{}\n\n\
1786+
These items were contained but should not have been:\n\n\
1787+
{}\n\n",
1788+
missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
1789+
too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));
1790+
panic!();
1791+
}
1792+
}

src/librustc/front/map/definitions.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -196,33 +196,33 @@ impl DefPathData {
196196

197197
PositionalField |
198198
Field(hir::StructFieldKind::UnnamedField(_)) => {
199-
InternedString::new("<field>")
199+
InternedString::new("{{field}}")
200200
}
201201

202202
// note that this does not show up in user printouts
203203
CrateRoot => {
204-
InternedString::new("<root>")
204+
InternedString::new("{{root}}")
205205
}
206206

207207
// note that this does not show up in user printouts
208208
InlinedRoot(_) => {
209-
InternedString::new("<inlined-root>")
209+
InternedString::new("{{inlined-root}}")
210210
}
211211

212212
Misc => {
213-
InternedString::new("?")
213+
InternedString::new("{{?}}")
214214
}
215215

216216
ClosureExpr => {
217-
InternedString::new("<closure>")
217+
InternedString::new("{{closure}}")
218218
}
219219

220220
StructCtor => {
221-
InternedString::new("<constructor>")
221+
InternedString::new("{{constructor}}")
222222
}
223223

224224
Initializer => {
225-
InternedString::new("<initializer>")
225+
InternedString::new("{{initializer}}")
226226
}
227227
}
228228
}

src/librustc/middle/cstore.rs

+5
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ pub trait CrateStore<'tcx> : Any {
223223
-> FoundAst<'tcx>;
224224
fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
225225
-> Option<Mir<'tcx>>;
226+
fn is_item_mir_available(&self, def: DefId) -> bool;
227+
226228
// This is basically a 1-based range of ints, which is a little
227229
// silly - I may fix that.
228230
fn crates(&self) -> Vec<ast::CrateNum>;
@@ -401,6 +403,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
401403
-> FoundAst<'tcx> { unimplemented!() }
402404
fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
403405
-> Option<Mir<'tcx>> { unimplemented!() }
406+
fn is_item_mir_available(&self, def: DefId) -> bool {
407+
unimplemented!()
408+
}
404409

405410
// This is basically a 1-based range of ints, which is a little
406411
// silly - I may fix that.

src/librustc/middle/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ impl<'tcx> ctxt<'tcx> {
563563
const_qualif_map: RefCell::new(NodeMap()),
564564
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
565565
cast_kinds: RefCell::new(NodeMap()),
566-
fragment_infos: RefCell::new(DefIdMap()),
566+
fragment_infos: RefCell::new(DefIdMap())
567567
}, f)
568568
}
569569
}

src/librustc/middle/ty/maps.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use middle::def_id::DefId;
1313
use middle::ty;
1414
use std::marker::PhantomData;
1515
use std::rc::Rc;
16-
use syntax::attr;
16+
use syntax::{attr, ast};
1717

1818
macro_rules! dep_map_ty {
1919
($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
@@ -42,3 +42,4 @@ dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
4242
dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
4343
dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> }
4444
dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
45+
dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId }

src/librustc/mir/repr.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use std::{iter, u32};
2525
use std::ops::{Index, IndexMut};
2626

2727
/// Lowered representation of a single function.
28-
#[derive(RustcEncodable, RustcDecodable)]
28+
#[derive(Clone, RustcEncodable, RustcDecodable)]
2929
pub struct Mir<'tcx> {
3030
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
3131
/// that indexes into this vector.
@@ -146,7 +146,7 @@ pub enum BorrowKind {
146146

147147
// A "variable" is a binding declared by the user as part of the fn
148148
// decl, a let, etc.
149-
#[derive(RustcEncodable, RustcDecodable)]
149+
#[derive(Clone, RustcEncodable, RustcDecodable)]
150150
pub struct VarDecl<'tcx> {
151151
pub mutability: Mutability,
152152
pub name: Name,
@@ -155,7 +155,7 @@ pub struct VarDecl<'tcx> {
155155

156156
// A "temp" is a temporary that we place on the stack. They are
157157
// anonymous, always mutable, and have only a type.
158-
#[derive(RustcEncodable, RustcDecodable)]
158+
#[derive(Clone, RustcEncodable, RustcDecodable)]
159159
pub struct TempDecl<'tcx> {
160160
pub ty: Ty<'tcx>,
161161
}
@@ -171,7 +171,7 @@ pub struct TempDecl<'tcx> {
171171
//
172172
// there is only one argument, of type `(i32, u32)`, but two bindings
173173
// (`x` and `y`).
174-
#[derive(RustcEncodable, RustcDecodable)]
174+
#[derive(Clone, RustcEncodable, RustcDecodable)]
175175
pub struct ArgDecl<'tcx> {
176176
pub ty: Ty<'tcx>,
177177
}
@@ -207,14 +207,14 @@ impl Debug for BasicBlock {
207207
///////////////////////////////////////////////////////////////////////////
208208
// BasicBlock and Terminator
209209

210-
#[derive(Debug, RustcEncodable, RustcDecodable)]
210+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
211211
pub struct BasicBlockData<'tcx> {
212212
pub statements: Vec<Statement<'tcx>>,
213213
pub terminator: Option<Terminator<'tcx>>,
214214
pub is_cleanup: bool,
215215
}
216216

217-
#[derive(RustcEncodable, RustcDecodable)]
217+
#[derive(Clone, RustcEncodable, RustcDecodable)]
218218
pub enum Terminator<'tcx> {
219219
/// block should have one successor in the graph; we jump there
220220
Goto {
@@ -481,13 +481,13 @@ impl<'tcx> Terminator<'tcx> {
481481
///////////////////////////////////////////////////////////////////////////
482482
// Statements
483483

484-
#[derive(RustcEncodable, RustcDecodable)]
484+
#[derive(Clone, RustcEncodable, RustcDecodable)]
485485
pub struct Statement<'tcx> {
486486
pub span: Span,
487487
pub kind: StatementKind<'tcx>,
488488
}
489489

490-
#[derive(Debug, RustcEncodable, RustcDecodable)]
490+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
491491
pub enum StatementKind<'tcx> {
492492
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
493493
Drop(DropKind, Lvalue<'tcx>),
@@ -721,7 +721,7 @@ pub enum Rvalue<'tcx> {
721721
InlineAsm(InlineAsm),
722722
}
723723

724-
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
724+
#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
725725
pub enum CastKind {
726726
Misc,
727727

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
643643
"keep the AST after lowering it to HIR"),
644644
show_span: Option<String> = (None, parse_opt_string,
645645
"show spans for compiler debugging (expr|pat|ty)"),
646+
print_trans_items: Option<String> = (None, parse_opt_string,
647+
"print the result of the translation item collection pass"),
646648
}
647649

648650
pub fn default_lib_output() -> CrateType {

src/librustc_metadata/astencode.rs

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
177177
}
178178
_ => { }
179179
}
180+
180181
Ok(ii)
181182
}
182183
}

src/librustc_metadata/csearch.rs

+5
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
445445
decoder::maybe_get_item_mir(&*cdata, tcx, def.index)
446446
}
447447

448+
fn is_item_mir_available(&self, def: DefId) -> bool {
449+
let cdata = self.get_crate_data(def.krate);
450+
decoder::is_item_mir_available(&*cdata, def.index)
451+
}
452+
448453
fn crates(&self) -> Vec<ast::CrateNum>
449454
{
450455
let mut result = vec![];

src/librustc_metadata/decoder.rs

+10
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,14 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd,
830830
}
831831
}
832832

833+
pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool {
834+
if let Some(item_doc) = cdata.get_item(id) {
835+
return reader::maybe_get_doc(item_doc, tag_mir as usize).is_some();
836+
}
837+
838+
false
839+
}
840+
833841
pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
834842
tcx: &ty::ctxt<'tcx>,
835843
id: DefIndex)
@@ -849,6 +857,8 @@ pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
849857
})
850858
}).unwrap();
851859

860+
assert!(decoder.position() == mir_doc.end);
861+
852862
let mut def_id_and_span_translator = MirDefIdAndSpanTranslator {
853863
crate_metadata: cdata,
854864
codemap: tcx.sess.codemap(),

0 commit comments

Comments
 (0)