rustc: enforce stack discipline on ty::ctxt.

This commit is contained in:
Eduard Burtescu 2015-06-14 04:50:23 +03:00
parent 84b49b2d35
commit bc383f6294
7 changed files with 231 additions and 198 deletions

View file

@ -2810,20 +2810,22 @@ impl<'tcx> CommonTypes<'tcx> {
}
}
pub fn mk_ctxt<'tcx>(s: Session,
arenas: &'tcx CtxtArenas<'tcx>,
def_map: DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index<'tcx>) -> ctxt<'tcx>
pub fn with_ctxt<'tcx, F, R>(s: Session,
arenas: &'tcx CtxtArenas<'tcx>,
def_map: DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index<'tcx>,
f: F) -> (Session, R)
where F: FnOnce(&ctxt<'tcx>) -> R
{
let mut interner = FnvHashMap();
let common_types = CommonTypes::new(&arenas.type_, &mut interner);
ctxt {
let tcx = ctxt {
arenas: arenas,
interner: RefCell::new(interner),
substs_interner: RefCell::new(FnvHashMap()),
@ -2885,7 +2887,9 @@ pub fn mk_ctxt<'tcx>(s: Session,
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
}
};
let result = f(&tcx);
(tcx.sess, result)
}
// Type constructors

View file

@ -65,7 +65,7 @@ pub fn compile_input(sess: Session,
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
let (outputs, trans, sess) = {
let (sess, result) = {
let (outputs, expanded_crate, id) = {
let krate = phase_1_parse_input(&sess, cfg, input);
@ -119,37 +119,52 @@ pub fn compile_input(sess: Session,
&ast_map.krate(),
&id[..]));
let (tcx, analysis) = phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
id,
control.make_glob_map);
phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
id,
control.make_glob_map,
|tcx, analysis| {
controller_entry_point!(after_analysis,
tcx.sess,
CompileState::state_after_analysis(input,
&tcx.sess,
outdir,
tcx.map.krate(),
&analysis,
&tcx));
{
let state = CompileState::state_after_analysis(input,
&tcx.sess,
outdir,
tcx.map.krate(),
&analysis,
tcx);
(control.after_analysis.callback)(state);
if log_enabled!(::log::INFO) {
println!("Pre-trans");
tcx.print_debug_stats();
}
let trans = phase_4_translate_to_llvm(&tcx, analysis);
tcx.sess.abort_if_errors();
if control.after_analysis.stop == Compilation::Stop {
return Err(());
}
}
if log_enabled!(::log::INFO) {
println!("Post-trans");
tcx.print_debug_stats();
}
if log_enabled!(::log::INFO) {
println!("Pre-trans");
tcx.print_debug_stats();
}
let trans = phase_4_translate_to_llvm(tcx, analysis);
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();
if log_enabled!(::log::INFO) {
println!("Post-trans");
tcx.print_debug_stats();
}
(outputs, trans, tcx.sess)
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();
Ok((outputs, trans))
})
};
let (outputs, trans) = if let Ok(out) = result {
out
} else {
return;
};
phase_5_run_llvm_passes(&sess, &trans, &outputs);
controller_entry_point!(after_llvm,
@ -578,12 +593,16 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session,
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
ast_map: ast_map::Map<'tcx>,
arenas: &'tcx ty::CtxtArenas<'tcx>,
name: String,
make_glob_map: resolve::MakeGlobMap)
-> (ty::ctxt<'tcx>, ty::CrateAnalysis) {
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
ast_map: ast_map::Map<'tcx>,
arenas: &'tcx ty::CtxtArenas<'tcx>,
name: String,
make_glob_map: resolve::MakeGlobMap,
f: F)
-> (Session, R)
where F: FnOnce(&ty::ctxt<'tcx>,
ty::CrateAnalysis) -> R
{
let time_passes = sess.time_passes();
let krate = ast_map.krate();
@ -627,86 +646,88 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
time(time_passes, "static item recursion checking", (), |_|
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
let ty_cx = ty::mk_ctxt(sess,
arenas,
def_map,
named_region_map,
ast_map,
freevars,
region_map,
lang_items,
stability::Index::new(krate));
ty::with_ctxt(sess,
arenas,
def_map,
named_region_map,
ast_map,
freevars,
region_map,
lang_items,
stability::Index::new(krate),
|tcx| {
// passes are timed inside typeck
typeck::check_crate(&ty_cx, trait_map);
// passes are timed inside typeck
typeck::check_crate(tcx, trait_map);
time(time_passes, "const checking", (), |_|
middle::check_const::check_crate(&ty_cx));
time(time_passes, "const checking", (), |_|
middle::check_const::check_crate(tcx));
let (exported_items, public_items) =
time(time_passes, "privacy checking", (), |_|
rustc_privacy::check_crate(&ty_cx, &export_map, external_exports));
let (exported_items, public_items) =
time(time_passes, "privacy checking", (), |_|
rustc_privacy::check_crate(tcx, &export_map, external_exports));
// Do not move this check past lint
time(time_passes, "stability index", (), |_|
ty_cx.stability.borrow_mut().build(&ty_cx, krate, &public_items));
// Do not move this check past lint
time(time_passes, "stability index", (), |_|
tcx.stability.borrow_mut().build(tcx, krate, &public_items));
time(time_passes, "intrinsic checking", (), |_|
middle::intrinsicck::check_crate(&ty_cx));
time(time_passes, "intrinsic checking", (), |_|
middle::intrinsicck::check_crate(tcx));
time(time_passes, "effect checking", (), |_|
middle::effect::check_crate(&ty_cx));
time(time_passes, "effect checking", (), |_|
middle::effect::check_crate(tcx));
time(time_passes, "match checking", (), |_|
middle::check_match::check_crate(&ty_cx));
time(time_passes, "match checking", (), |_|
middle::check_match::check_crate(tcx));
time(time_passes, "liveness checking", (), |_|
middle::liveness::check_crate(&ty_cx));
time(time_passes, "liveness checking", (), |_|
middle::liveness::check_crate(tcx));
time(time_passes, "borrow checking", (), |_|
borrowck::check_crate(&ty_cx));
time(time_passes, "borrow checking", (), |_|
borrowck::check_crate(tcx));
time(time_passes, "rvalue checking", (), |_|
middle::check_rvalues::check_crate(&ty_cx, krate));
time(time_passes, "rvalue checking", (), |_|
middle::check_rvalues::check_crate(tcx, krate));
// Avoid overwhelming user with errors if type checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
// lot of annoying errors in the compile-fail tests (basically,
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
ty_cx.sess.abort_if_errors();
// Avoid overwhelming user with errors if type checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
// lot of annoying errors in the compile-fail tests (basically,
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
tcx.sess.abort_if_errors();
let reachable_map =
time(time_passes, "reachability checking", (), |_|
reachable::find_reachable(&ty_cx, &exported_items));
let reachable_map =
time(time_passes, "reachability checking", (), |_|
reachable::find_reachable(tcx, &exported_items));
time(time_passes, "death checking", (), |_| {
middle::dead::check_crate(&ty_cx,
&exported_items,
&reachable_map)
});
time(time_passes, "death checking", (), |_| {
middle::dead::check_crate(tcx,
&exported_items,
&reachable_map)
});
let ref lib_features_used =
time(time_passes, "stability checking", (), |_|
stability::check_unstable_api_usage(&ty_cx));
let ref lib_features_used =
time(time_passes, "stability checking", (), |_|
stability::check_unstable_api_usage(tcx));
time(time_passes, "unused lib feature checking", (), |_|
stability::check_unused_or_stable_features(
&ty_cx.sess, lib_features_used));
time(time_passes, "unused lib feature checking", (), |_|
stability::check_unused_or_stable_features(
&tcx.sess, lib_features_used));
time(time_passes, "lint checking", (), |_|
lint::check_crate(&ty_cx, &exported_items));
time(time_passes, "lint checking", (), |_|
lint::check_crate(tcx, &exported_items));
// The above three passes generate errors w/o aborting
ty_cx.sess.abort_if_errors();
// The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors();
(ty_cx, ty::CrateAnalysis {
export_map: export_map,
exported_items: exported_items,
public_items: public_items,
reachable: reachable_map,
name: name,
glob_map: glob_map,
f(tcx, ty::CrateAnalysis {
export_map: export_map,
exported_items: exported_items,
public_items: public_items,
reachable: reachable_map,
name: name,
glob_map: glob_map,
})
})
}

View file

@ -148,13 +148,15 @@ impl PpSourceMode {
}
PpmTyped => {
let ast_map = ast_map.expect("--pretty=typed missing ast_map");
let (tcx, _) = driver::phase_3_run_analysis_passes(sess,
ast_map,
arenas,
id,
resolve::MakeGlobMap::No);
let annotation = TypedAnnotation { tcx: tcx };
f(&annotation, payload)
driver::phase_3_run_analysis_passes(sess,
ast_map,
arenas,
id,
resolve::MakeGlobMap::No,
|tcx, _| {
let annotation = TypedAnnotation { tcx: tcx };
f(&annotation, payload)
}).1
}
}
}
@ -284,11 +286,11 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
}
struct TypedAnnotation<'tcx> {
tcx: ty::ctxt<'tcx>,
struct TypedAnnotation<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
}
impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> {
impl<'b, 'tcx> PrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
fn sess<'a>(&'a self) -> &'a Session { &self.tcx.sess }
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> {
@ -298,7 +300,7 @@ impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> {
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> {
fn pre(&self,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
@ -645,12 +647,14 @@ pub fn pretty_print_input(sess: Session,
match code {
Some(code) => {
let variants = gather_flowgraph_variants(&sess);
let (tcx, _) = driver::phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
id,
resolve::MakeGlobMap::No);
print_flowgraph(variants, &tcx, code, mode, out)
driver::phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
id,
resolve::MakeGlobMap::No,
|tcx, _| {
print_flowgraph(variants, tcx, code, mode, out)
}).1
}
None => {
let message = format!("--pretty=flowgraph needs \

View file

@ -129,20 +129,22 @@ fn test_env<F>(source_string: &str,
resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
let tcx = ty::mk_ctxt(sess,
&arenas,
def_map,
named_region_map,
ast_map,
freevars,
region_map,
lang_items,
stability::Index::new(krate));
let infcx = infer::new_infer_ctxt(&tcx);
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
ty::with_ctxt(sess,
&arenas,
def_map,
named_region_map,
ast_map,
freevars,
region_map,
lang_items,
stability::Index::new(krate),
|tcx| {
let infcx = infer::new_infer_ctxt(tcx);
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
});
}
impl<'a, 'tcx> Env<'a, 'tcx> {

View file

@ -32,17 +32,17 @@ pub use rustc::session::config::Input;
pub use rustc::session::search_paths::SearchPaths;
/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
pub enum MaybeTyped<'tcx> {
Typed(ty::ctxt<'tcx>),
pub enum MaybeTyped<'a, 'tcx: 'a> {
Typed(&'a ty::ctxt<'tcx>),
NotTyped(session::Session)
}
pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
(Vec<String>, clean::TypeKind)>>>;
pub struct DocContext<'tcx> {
pub struct DocContext<'a, 'tcx: 'a> {
pub krate: &'tcx ast::Crate,
pub maybe_typed: MaybeTyped<'tcx>,
pub maybe_typed: MaybeTyped<'a, 'tcx>,
pub input: Input,
pub external_paths: ExternalPaths,
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
@ -52,17 +52,17 @@ pub struct DocContext<'tcx> {
pub deref_trait_did: Cell<Option<ast::DefId>>,
}
impl<'tcx> DocContext<'tcx> {
impl<'b, 'tcx> DocContext<'b, 'tcx> {
pub fn sess<'a>(&'a self) -> &'a session::Session {
match self.maybe_typed {
Typed(ref tcx) => &tcx.sess,
Typed(tcx) => &tcx.sess,
NotTyped(ref sess) => sess
}
}
pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
match self.maybe_typed {
Typed(ref tcx) => Some(tcx),
Typed(tcx) => Some(tcx),
NotTyped(_) => None
}
}
@ -133,48 +133,49 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
let arenas = ty::CtxtArenas::new();
let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
let (tcx, ty::CrateAnalysis {
exported_items, public_items, ..
}) = driver::phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
name,
resolve::MakeGlobMap::No);
driver::phase_3_run_analysis_passes(sess,
ast_map,
&arenas,
name,
resolve::MakeGlobMap::No,
|tcx, analysis| {
let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
let ctxt = DocContext {
krate: tcx.map.krate(),
maybe_typed: Typed(tcx),
input: input,
external_traits: RefCell::new(Some(HashMap::new())),
external_typarams: RefCell::new(Some(HashMap::new())),
external_paths: RefCell::new(Some(HashMap::new())),
inlined: RefCell::new(Some(HashSet::new())),
populated_crate_impls: RefCell::new(HashSet::new()),
deref_trait_did: Cell::new(None),
};
debug!("crate: {:?}", ctxt.krate);
let ctxt = DocContext {
krate: tcx.map.krate(),
maybe_typed: Typed(tcx),
input: input,
external_traits: RefCell::new(Some(HashMap::new())),
external_typarams: RefCell::new(Some(HashMap::new())),
external_paths: RefCell::new(Some(HashMap::new())),
inlined: RefCell::new(Some(HashSet::new())),
populated_crate_impls: RefCell::new(HashSet::new()),
deref_trait_did: Cell::new(None),
};
debug!("crate: {:?}", ctxt.krate);
let mut analysis = CrateAnalysis {
exported_items: exported_items,
public_items: public_items,
external_paths: RefCell::new(None),
external_typarams: RefCell::new(None),
inlined: RefCell::new(None),
deref_trait_did: None,
};
let mut analysis = CrateAnalysis {
exported_items: exported_items,
public_items: public_items,
external_paths: RefCell::new(None),
external_typarams: RefCell::new(None),
inlined: RefCell::new(None),
deref_trait_did: None,
};
let krate = {
let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
v.visit(ctxt.krate);
v.clean(&ctxt)
};
let krate = {
let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
v.visit(ctxt.krate);
v.clean(&ctxt)
};
let external_paths = ctxt.external_paths.borrow_mut().take();
*analysis.external_paths.borrow_mut() = external_paths;
let map = ctxt.external_typarams.borrow_mut().take();
*analysis.external_typarams.borrow_mut() = map;
let map = ctxt.inlined.borrow_mut().take();
*analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis)
let external_paths = ctxt.external_paths.borrow_mut().take();
*analysis.external_paths.borrow_mut() = external_paths;
let map = ctxt.external_typarams.borrow_mut().take();
*analysis.external_typarams.borrow_mut() = map;
let map = ctxt.inlined.borrow_mut().take();
*analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis)
}).1
}

View file

@ -38,14 +38,14 @@ use doctree::*;
pub struct RustdocVisitor<'a, 'tcx: 'a> {
pub module: Module,
pub attrs: Vec<ast::Attribute>,
pub cx: &'a core::DocContext<'tcx>,
pub cx: &'a core::DocContext<'a, 'tcx>,
pub analysis: Option<&'a core::CrateAnalysis>,
view_item_stack: HashSet<ast::NodeId>,
inlining_from_glob: bool,
}
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
pub fn new(cx: &'a core::DocContext<'tcx>,
pub fn new(cx: &'a core::DocContext<'a, 'tcx>,
analysis: Option<&'a core::CrateAnalysis>) -> RustdocVisitor<'a, 'tcx> {
// If the root is reexported, terminate all recursion.
let mut stack = HashSet::new();

View file

@ -221,25 +221,26 @@ fn compile_program(input: &str, sysroot: PathBuf)
let arenas = ty::CtxtArenas::new();
let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
let (tcx, analysis) = driver::phase_3_run_analysis_passes(
sess, ast_map, &arenas, id, MakeGlobMap::No);
driver::phase_3_run_analysis_passes(
sess, ast_map, &arenas, id, MakeGlobMap::No, |tcx, analysis| {
let trans = driver::phase_4_translate_to_llvm(&tcx, analysis);
let trans = driver::phase_4_translate_to_llvm(tcx, analysis);
let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
// Collect crates used in the session.
// Reverse order finds dependencies first.
let deps = crates.into_iter().rev()
.filter_map(|(_, p)| p).collect();
// Collect crates used in the session.
// Reverse order finds dependencies first.
let deps = crates.into_iter().rev()
.filter_map(|(_, p)| p).collect();
assert_eq!(trans.modules.len(), 1);
let llmod = trans.modules[0].llmod;
assert_eq!(trans.modules.len(), 1);
let llmod = trans.modules[0].llmod;
// Workaround because raw pointers do not impl Send
let modp = llmod as usize;
// Workaround because raw pointers do not impl Send
let modp = llmod as usize;
(modp, deps)
(modp, deps)
}).1
}).unwrap();
match handle.join() {