Skip to content

Commit ac661f6

Browse files
committed
Add -Zborrowck-unreachable=no
The magic button for when you don't care about whether your code works, you just want it to compile. Currently, this avoids running borrowck or typeck on dead code that isn't monomorphized. In the future, it could be extended to ignore (but still emit) parse errors, mismatches in generic parameters, uses of private items, as long as the use doesn't need to make it to codegen. However, I don't propose to put them under the same flag. There is precedent for this in Haskell as -f defer-type-errors: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/defer_type_errors.html Build systems also commonly have this as --keep-going, which ignores failed builds while continuing to run other builds that aren't dependent on the one that failed. Some example motivations: - When making a large refactor, run a single test that doesn't affect the rest of the codebase. In essence this is a "poor man's workspace", but adhoc and much faster than splitting out a single crate into multiple. - Prototype a new application where you're rapidly changing the code and don't need it to be precisely correct, just see if it could eventually be made to compile.
1 parent 65a6e22 commit ac661f6

File tree

7 files changed

+51
-1
lines changed

7 files changed

+51
-1
lines changed

compiler/rustc_driver/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,13 @@ fn run_compiler(
367367
return early_exit();
368368
}
369369

370+
// We need to get at least far before we have even a hope of generating a binary.
371+
// FIXME: is that true? maybe we can ignore unresolved locals in dead code and that sort of thing
372+
// That might require making name-resolution incremental, though.
373+
if !sess.opts.unstable_opts.borrowck_unreachable {
374+
return queries.linker().map(Some);
375+
}
376+
370377
queries.global_ctxt()?;
371378

372379
if sess.opts.unstable_opts.no_analysis {

compiler/rustc_interface/src/queries.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,9 @@ impl<'tcx> Queries<'tcx> {
237237
self.ongoing_codegen.compute(|| {
238238
let outputs = self.prepare_outputs()?;
239239
self.global_ctxt()?.peek_mut().enter(|tcx| {
240-
tcx.analysis(()).ok();
240+
if tcx.sess.opts.unstable_opts.borrowck_unreachable {
241+
tcx.analysis(()).ok();
242+
}
241243

242244
// Don't do code generation if there were any errors
243245
self.session().compile_status()?;

compiler/rustc_monomorphize/src/collector.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,16 @@ struct RootCollector<'a, 'tcx> {
11861186

11871187
impl<'v> RootCollector<'_, 'v> {
11881188
fn process_item(&mut self, id: hir::ItemId) {
1189+
let def_id = id.owner_id.def_id;
1190+
let (live_symbols, _) = self.tcx.live_symbols_and_ignored_derived_traits(());
1191+
if !live_symbols.contains(&def_id) {
1192+
// This is dead code; ignore it.
1193+
return;
1194+
}
1195+
// We need this for `-Zborrowck-unreachable=no`, since we don't borrowck the whole crate at once, only on-demand.
1196+
if self.tcx.hir().maybe_body_owned_by(def_id).is_some() {
1197+
self.tcx.ensure().mir_borrowck(def_id);
1198+
}
11891199
match self.tcx.def_kind(id.owner_id) {
11901200
DefKind::Enum | DefKind::Struct | DefKind::Union => {
11911201
let item = self.tcx.hir().item(id);

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,8 @@ options! {
13111311
(default: no)"),
13121312
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
13131313
"force all crates to be `rustc_private` unstable (default: no)"),
1314+
borrowck_unreachable: bool = (true, parse_bool, [TRACKED],
1315+
"force borrowck to run even on functions that are never used"),
13141316
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
13151317
"set the optimization fuel quota for a crate"),
13161318
function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// compile-flags: -Z borrowck-unreachable=no
2+
// build-fail
3+
fn live_code(s: &str) -> &'static str {
4+
s //~ ERROR lifetime may not live long enough
5+
}
6+
7+
fn main() {
8+
println!("{}", live_code("he he he"));
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/borrowck-live-code.rs:4:5
3+
|
4+
LL | fn live_code(s: &str) -> &'static str {
5+
| - let's call the lifetime of this reference `'1`
6+
LL | s
7+
| ^ returning this value requires that `'1` must outlive `'static`
8+
9+
error: aborting due to previous error
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Z borrowck-unreachable=no
2+
// run-pass
3+
4+
fn dead_code(s: &str) -> &'static str {
5+
s
6+
}
7+
8+
fn main() {
9+
println!("he he he")
10+
}

0 commit comments

Comments
 (0)