Skip to content

Commit 8d8f41b

Browse files
committed
auto merge of #19392 : murarth/rust/rustc-compile-twice, r=nick29581
Closes #19371
2 parents 6163581 + 004533e commit 8d8f41b

File tree

6 files changed

+98
-0
lines changed

6 files changed

+98
-0
lines changed

src/librustc_trans/driver/driver.rs

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ pub fn compile_input(sess: Session,
5151
outdir: &Option<Path>,
5252
output: &Option<Path>,
5353
addl_plugins: Option<Plugins>) {
54+
// These may be left in an incoherent state after a previous compile.
55+
// `clear_tables` and `get_ident_interner().clear()` can be used to free
56+
// memory, but they do not restore the initial state.
57+
syntax::ext::mtwt::reset_tables();
58+
token::reset_ident_interner();
59+
5460
// We need nested scopes here, because the intermediate results can keep
5561
// large chunks of memory alive and we want to free them as soon as
5662
// possible to keep the peak memory usage low

src/libsyntax/ext/mtwt.rs

+10
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ pub fn clear_tables() {
136136
with_resolve_table_mut(|table| *table = HashMap::new());
137137
}
138138

139+
/// Reset the tables to their initial state
140+
pub fn reset_tables() {
141+
with_sctable(|table| {
142+
*table.table.borrow_mut() = vec!(EmptyCtxt, IllegalCtxt);
143+
*table.mark_memo.borrow_mut() = HashMap::new();
144+
*table.rename_memo.borrow_mut() = HashMap::new();
145+
});
146+
with_resolve_table_mut(|table| *table = HashMap::new());
147+
}
148+
139149
/// Add a value to the end of a vec, return its index
140150
fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
141151
vec.push(val);

src/libsyntax/parse/token.rs

+6
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,12 @@ pub fn get_ident_interner() -> Rc<IdentInterner> {
564564
KEY.with(|k| k.clone())
565565
}
566566

567+
/// Reset the ident interner to its initial state.
568+
pub fn reset_ident_interner() {
569+
let interner = get_ident_interner();
570+
interner.reset(mk_fresh_ident_interner());
571+
}
572+
567573
/// Represents a string stored in the task-local interner. Because the
568574
/// interner lives for the life of the task, this can be safely treated as an
569575
/// immortal string, as long as it never crosses between tasks.

src/libsyntax/util/interner.rs

+5
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ impl StrInterner {
214214
*self.map.borrow_mut() = HashMap::new();
215215
*self.vect.borrow_mut() = Vec::new();
216216
}
217+
218+
pub fn reset(&self, other: StrInterner) {
219+
*self.map.borrow_mut() = other.map.into_inner();
220+
*self.vect.borrow_mut() = other.vect.into_inner();
221+
}
217222
}
218223

219224
#[cfg(test)]
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-include ../tools.mk
2+
3+
# This test ensures that rustc compile_input can be called twice in one task
4+
# without causing a panic.
5+
# The program needs the path to rustc to get sysroot.
6+
7+
all:
8+
$(RUSTC) foo.rs
9+
$(call RUN,foo $(TMPDIR) $(RUSTC))

src/test/run-make/issue-19371/foo.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate rustc;
12+
extern crate rustc_trans;
13+
extern crate syntax;
14+
15+
use rustc::session::{build_session, Session};
16+
use rustc::session::config::{basic_options, build_configuration, OutputTypeExe};
17+
use rustc_trans::driver::driver::{Input, StrInput, compile_input};
18+
use syntax::diagnostics::registry::Registry;
19+
20+
fn main() {
21+
let src = r#"
22+
fn main() {}
23+
"#;
24+
25+
let args = std::os::args();
26+
27+
if args.len() < 4 {
28+
panic!("expected rustc path");
29+
}
30+
31+
let tmpdir = Path::new(args[1].as_slice());
32+
33+
let mut sysroot = Path::new(args[3].as_slice());
34+
sysroot.pop();
35+
sysroot.pop();
36+
37+
compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
38+
39+
compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
40+
}
41+
42+
fn basic_sess(sysroot: Path) -> Session {
43+
let mut opts = basic_options();
44+
opts.output_types = vec![OutputTypeExe];
45+
opts.maybe_sysroot = Some(sysroot);
46+
47+
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
48+
let sess = build_session(opts, None, descriptions);
49+
sess
50+
}
51+
52+
fn compile(code: String, output: Path, sysroot: Path) {
53+
let sess = basic_sess(sysroot);
54+
let cfg = build_configuration(&sess);
55+
56+
compile_input(sess,
57+
cfg,
58+
&StrInput(code),
59+
&None,
60+
&Some(output),
61+
None);
62+
}

0 commit comments

Comments
 (0)