Skip to content

Commit 34f88f3

Browse files
committed
Combine run-pass tests into a single crate
1 parent 8b3d4d9 commit 34f88f3

File tree

22 files changed

+680
-30
lines changed

22 files changed

+680
-30
lines changed

config.toml.example

+3
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@
283283
# desired in distributions, for example.
284284
#rpath = true
285285

286+
# Merge Rust test files into larger units for faster testing
287+
#combine-tests = false
288+
286289
# Suppresses extraneous output from tests to ensure the output of the test
287290
# harness is relatively clean.
288291
#quiet-tests = false

src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ pub struct Config {
119119
pub low_priority: bool,
120120
pub channel: String,
121121
pub quiet_tests: bool,
122+
pub combine_tests: bool,
122123
pub test_miri: bool,
123124
pub save_toolstates: Option<PathBuf>,
124125

@@ -288,6 +289,7 @@ struct Rust {
288289
debug: Option<bool>,
289290
dist_src: Option<bool>,
290291
quiet_tests: Option<bool>,
292+
combine_tests: Option<bool>,
291293
test_miri: Option<bool>,
292294
save_toolstates: Option<String>,
293295
codegen_backends: Option<Vec<String>>,
@@ -478,6 +480,7 @@ impl Config {
478480
set(&mut config.backtrace, rust.backtrace);
479481
set(&mut config.channel, rust.channel.clone());
480482
set(&mut config.rust_dist_src, rust.dist_src);
483+
set(&mut config.combine_tests, rust.combine_tests);
481484
set(&mut config.quiet_tests, rust.quiet_tests);
482485
set(&mut config.test_miri, rust.test_miri);
483486
set(&mut config.wasm_syscall, rust.wasm_syscall);

src/bootstrap/configure.py

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def v(*args):
4747
o("test-miri", "rust.test-miri", "run miri's test suite")
4848
o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
4949
o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests")
50+
o("combined-tests", "rust.combine-tests", "merge tests together when possible")
5051
o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
5152
o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
5253
o("local-rust", None, "use an installed rustc rather than downloading a snapshot")

src/bootstrap/test.rs

+4
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,10 @@ impl Step for Compiletest {
848848
cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
849849
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
850850

851+
if builder.config.combine_tests && mode == "run-pass" {
852+
cmd.arg("--combine");
853+
}
854+
851855
// Avoid depending on rustdoc when we don't need it.
852856
if mode == "rustdoc" || mode == "run-make" {
853857
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
11141114
"generate comments into the assembly (may change behavior)"),
11151115
no_verify: bool = (false, parse_bool, [TRACKED],
11161116
"skip LLVM verification"),
1117+
submodules_crate_like: bool = (false, parse_bool, [TRACKED],
1118+
"pretend immediate submodules of the crate are crates themselves"),
11171119
borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
11181120
"gather borrowck statistics"),
11191121
no_landing_pads: bool = (false, parse_bool, [TRACKED],

src/librustc/session/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,8 @@ pub fn build_session_(
10951095
};
10961096
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
10971097

1098-
let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
1098+
let mut p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
1099+
p_s.combine_test_mode = sopts.debugging_opts.submodules_crate_like;
10991100
let default_sysroot = match sopts.maybe_sysroot {
11001101
Some(_) => None,
11011102
None => Some(filesearch::get_or_default_sysroot()),

src/librustc_driver/driver.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ pub fn phase_1_parse_input<'a>(control: &CompileController,
521521
profile::begin(sess);
522522
}
523523

524-
let krate = time(sess, "parsing", || {
524+
let mut krate = time(sess, "parsing", || {
525525
match *input {
526526
Input::File(ref file) => {
527527
parse::parse_crate_from_file(file, &sess.parse_sess)
@@ -549,6 +549,17 @@ pub fn phase_1_parse_input<'a>(control: &CompileController,
549549
syntax::show_span::run(sess.diagnostic(), s, &krate);
550550
}
551551

552+
if sess.opts.debugging_opts.submodules_crate_like {
553+
krate = time(sess,
554+
"Pretending submodules are crates",
555+
|| rustc_passes::submodules_crate_like::modify_crate(sess, krate));
556+
}
557+
558+
if sess.opts.debugging_opts.ast_json_noexpand {
559+
println!("\n\n\n\n\n\n\n\n");
560+
println!("{}", json::as_json(&krate));
561+
}
562+
552563
if sess.opts.debugging_opts.hir_stats {
553564
hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS");
554565
}

src/librustc_driver/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -895,8 +895,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
895895
}
896896

897897
if sess.opts.debugging_opts.parse_only ||
898-
sess.opts.debugging_opts.show_span.is_some() ||
899-
sess.opts.debugging_opts.ast_json_noexpand {
898+
sess.opts.debugging_opts.show_span.is_some()/* ||
899+
sess.opts.debugging_opts.ast_json_noexpand*/ {
900900
control.after_parse.stop = Compilation::Stop;
901901
}
902902

src/librustc_passes/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc::ty::maps::Providers;
3838

3939
mod diagnostics;
4040

41+
pub mod submodules_crate_like;
4142
pub mod ast_validation;
4243
pub mod rvalue_promotion;
4344
pub mod hir_stats;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
// Copyright 2018 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+
use rustc::session::Session;
12+
use syntax::ast::*;
13+
use syntax::ptr::P;
14+
use syntax::fold;
15+
use syntax::fold::Folder;
16+
use syntax::symbol::keywords;
17+
use syntax::codemap::dummy_spanned;
18+
use syntax_pos::DUMMY_SP;
19+
use syntax_pos::symbol::Symbol;
20+
21+
struct ModFolder<'a> {
22+
use_std: &'a Item,
23+
root: Option<Ident>,
24+
main: Symbol,
25+
}
26+
27+
impl<'a> ModFolder<'a> {
28+
fn fold_qpath(&mut self, qself: &mut Option<QSelf>, path: &mut Path) {
29+
let old = path.segments.len();
30+
*path = self.fold_path(path.clone());
31+
let add = path.segments.len() - old;
32+
qself.as_mut().map(|qself| {
33+
qself.position += add;
34+
qself.ty = self.fold_ty(qself.ty.clone());
35+
});
36+
}
37+
}
38+
39+
impl<'a> fold::Folder for ModFolder<'a> {
40+
fn fold_use_tree(&mut self, mut use_tree: UseTree) -> UseTree {
41+
if let Some(root) = self.root {
42+
let pos = {
43+
let get = |i| {
44+
use_tree.prefix.segments.get(i).map(|p: &PathSegment| p.identifier.name)
45+
};
46+
if get(0) == Some(keywords::SelfValue.name()) ||
47+
get(0) == Some(keywords::Super.name()) {
48+
None
49+
} else {
50+
let mut i = 0;
51+
if get(i) == Some(keywords::CrateRoot.name()) {
52+
i += 1;
53+
}
54+
if get(i) == Some(keywords::Crate.name()) {
55+
i += 1;
56+
}
57+
Some(i)
58+
}
59+
};
60+
if let Some(pos) = pos {
61+
use_tree.prefix.segments.insert(pos, PathSegment {
62+
identifier: root,
63+
span: use_tree.span,
64+
parameters: None,
65+
});
66+
}
67+
use_tree
68+
} else {
69+
fold::noop_fold_use_tree(use_tree, self)
70+
}
71+
}
72+
73+
fn fold_path(&mut self, mut p: Path) -> Path {
74+
if let Some(root) = self.root {
75+
if let Some(first) = p.segments.first().cloned() {
76+
if first.identifier.name == keywords::CrateRoot.name() {
77+
let idx = if p.segments.get(1).map(|p| p.identifier.name) ==
78+
Some(keywords::Crate.name()) {
79+
2
80+
} else {
81+
1
82+
};
83+
p.segments.insert(idx, PathSegment {
84+
identifier: root,
85+
span: p.span,
86+
parameters: None,
87+
});
88+
}
89+
}
90+
fold::noop_fold_path(p, self)
91+
} else {
92+
fold::noop_fold_path(p, self)
93+
}
94+
}
95+
96+
fn fold_ty(&mut self, mut t: P<Ty>) -> P<Ty> {
97+
if match t.node {
98+
TyKind::Path(ref mut qself, ref mut path) => {
99+
self.fold_qpath(qself, path);
100+
true
101+
}
102+
_ => false,
103+
} {
104+
return t;
105+
}
106+
fold::noop_fold_ty(t, self)
107+
}
108+
109+
fn fold_pat(&mut self, mut p: P<Pat>) -> P<Pat> {
110+
if match p.node {
111+
PatKind::Path(ref mut qself, ref mut path) => {
112+
self.fold_qpath(qself, path);
113+
true
114+
}
115+
_ => false,
116+
} {
117+
return p;
118+
}
119+
fold::noop_fold_pat(p, self)
120+
}
121+
122+
fn fold_expr(&mut self, mut e: P<Expr>) -> P<Expr> {
123+
if match e.node {
124+
ExprKind::Path(ref mut qself, ref mut path) => {
125+
self.fold_qpath(qself, path);
126+
true
127+
}
128+
_ => false,
129+
} {
130+
return e;
131+
}
132+
e.map(|e| fold::noop_fold_expr(e, self))
133+
}
134+
135+
fn fold_item_simple(&mut self, mut item: Item) -> Item {
136+
if self.root.is_some() {
137+
fold::noop_fold_item_simple(item, self)
138+
} else {
139+
let is_root = match item.node {
140+
ItemKind::Mod(ref mut module) => {
141+
for mut item in &mut module.items {
142+
if item.ident.name == self.main {
143+
item.vis = dummy_spanned(VisibilityKind::Public);
144+
}
145+
}
146+
true
147+
}
148+
_ => false,
149+
};
150+
151+
if is_root {
152+
let mut folder = ModFolder {
153+
use_std: self.use_std,
154+
root: Some(item.ident),
155+
main: self.main,
156+
};
157+
158+
let mut item = fold::noop_fold_item_simple(item, &mut folder);
159+
match item.node {
160+
ItemKind::Mod(ref mut module) => {
161+
module.items.push(P(self.use_std.clone()));
162+
}
163+
_ => (),
164+
}
165+
item
166+
} else {
167+
fold::noop_fold_item_simple(item, self)
168+
}
169+
}
170+
}
171+
172+
fn fold_mac(&mut self, _mac: Mac) -> Mac {
173+
fold::noop_fold_mac(_mac, self)
174+
}
175+
}
176+
177+
pub fn modify_crate(_session: &Session, krate: Crate) -> Crate {
178+
let std_i = Ident::from_str("std");
179+
let use_std = Item {
180+
ident: keywords::Invalid.ident(),
181+
attrs: Vec::new(),
182+
id: DUMMY_NODE_ID,
183+
node: ItemKind::Use(P(UseTree {
184+
span: DUMMY_SP,
185+
kind: UseTreeKind::Simple(Some(std_i)),
186+
prefix: Path {
187+
segments: vec![PathSegment {
188+
identifier: std_i,
189+
span: DUMMY_SP,
190+
parameters: None,
191+
}],
192+
span: DUMMY_SP,
193+
},
194+
})),
195+
vis: dummy_spanned(VisibilityKind::Inherited),
196+
span: DUMMY_SP,
197+
tokens: None,
198+
};
199+
let Crate {
200+
module,
201+
attrs,
202+
span,
203+
} = krate;
204+
let module = ModFolder {
205+
use_std: &use_std,
206+
root: None,
207+
main: Symbol::intern("main"),
208+
}.fold_mod(module);
209+
Crate {
210+
module,
211+
attrs,
212+
span,
213+
}
214+
}

src/libsyntax/feature_gate.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1187,12 +1187,17 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga
11871187
}
11881188

11891189
fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1190-
explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
1190+
explain: &str, mut level: GateStrength) -> DiagnosticBuilder<'a> {
11911191
let diag = &sess.span_diagnostic;
11921192

11931193
let issue = match issue {
11941194
GateIssue::Language => find_lang_feature_issue(feature),
1195-
GateIssue::Library(lib) => lib,
1195+
GateIssue::Library(lib) => {
1196+
if sess.combine_test_mode {
1197+
level = GateStrength::Soft;
1198+
}
1199+
lib
1200+
},
11961201
};
11971202

11981203
let explanation = if let Some(n) = issue {

src/libsyntax/parse/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct ParseSess {
5353
// Spans where a `mod foo;` statement was included in a non-mod.rs file.
5454
// These are used to issue errors if the non_modrs_mods feature is not enabled.
5555
pub non_modrs_mods: RefCell<Vec<(ast::Ident, Span)>>,
56+
pub combine_test_mode: bool,
5657
/// Used to determine and report recursive mod inclusions
5758
included_mod_stack: RefCell<Vec<PathBuf>>,
5859
code_map: Lrc<CodeMap>,
@@ -77,6 +78,7 @@ impl ParseSess {
7778
registered_diagnostics: Lock::new(ErrorMap::new()),
7879
included_mod_stack: RefCell::new(vec![]),
7980
code_map,
81+
combine_test_mode: false,
8082
non_modrs_mods: RefCell::new(vec![]),
8183
}
8284
}

src/libsyntax/ptr.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
3939
use std::fmt::{self, Display, Debug};
4040
use std::iter::FromIterator;
41-
use std::ops::Deref;
41+
use std::ops::{Deref, DerefMut};
4242
use std::{mem, ptr, slice, vec};
4343

4444
use serialize::{Encodable, Decodable, Encoder, Decoder};
@@ -103,6 +103,12 @@ impl<T: ?Sized> Deref for P<T> {
103103
}
104104
}
105105

106+
impl<T: ?Sized> DerefMut for P<T> {
107+
fn deref_mut(&mut self) -> &mut T {
108+
&mut *self.ptr
109+
}
110+
}
111+
106112
impl<T: 'static + Clone> Clone for P<T> {
107113
fn clone(&self) -> P<T> {
108114
P((**self).clone())

0 commit comments

Comments
 (0)