Skip to content

Commit 945ba12

Browse files
authored
Auto merge of #34002 - jseyfried:strip_tests_in_cfg, r=nrc
Treat `#[test]` like `#[cfg(test)]` in non-test builds This PR treats `#[test]` like `#[cfg(test)]` in non-test builds. In particular, like `#[cfg(test)]`, - `#[test]` nodes are stripped during `cfg` processing, and - `#[test]` is disallowed on non-optional expressions. Closes #33946. r? @nrc
2 parents f80ff7d + 29c4b67 commit 945ba12

File tree

5 files changed

+41
-51
lines changed

5 files changed

+41
-51
lines changed

src/librustc_driver/driver.rs

+2
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
582582
sess.track_errors(|| {
583583
syntax::config::strip_unconfigured_items(sess.diagnostic(),
584584
krate,
585+
sess.opts.test,
585586
&mut feature_gated_cfgs)
586587
})
587588
})?;
@@ -692,6 +693,7 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
692693
features: Some(&features),
693694
recursion_limit: sess.recursion_limit.get(),
694695
trace_mac: sess.opts.debugging_opts.trace_macros,
696+
should_test: sess.opts.test,
695697
};
696698
let mut loader = macro_import::MacroLoader::new(sess, &cstore, crate_name);
697699
let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,

src/libsyntax/config.rs

+33-37
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,37 @@ use ptr::P;
1919

2020
use util::small_vector::SmallVector;
2121

22-
pub trait CfgFolder: fold::Folder {
23-
// Check if a node with the given attributes is in this configuration.
24-
fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool;
25-
26-
// Update a node before checking if it is in this configuration (used to implement `cfg_attr`).
27-
fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T { node }
28-
29-
// Visit attributes on expression and statements (but not attributes on items in blocks).
30-
fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {}
31-
32-
// Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
33-
fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {}
34-
35-
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
36-
let node = self.process_attrs(node);
37-
if self.in_cfg(node.attrs()) { Some(node) } else { None }
38-
}
39-
}
40-
41-
/// A folder that strips out items that do not belong in the current
42-
/// configuration.
22+
/// A folder that strips out items that do not belong in the current configuration.
4323
pub struct StripUnconfigured<'a> {
4424
diag: CfgDiagReal<'a, 'a>,
25+
should_test: bool,
4526
config: &'a ast::CrateConfig,
4627
}
4728

4829
impl<'a> StripUnconfigured<'a> {
4930
pub fn new(config: &'a ast::CrateConfig,
31+
should_test: bool,
5032
diagnostic: &'a Handler,
5133
feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>)
5234
-> Self {
5335
StripUnconfigured {
5436
config: config,
37+
should_test: should_test,
5538
diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs },
5639
}
5740
}
5841

42+
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
43+
let node = self.process_cfg_attrs(node);
44+
if self.in_cfg(node.attrs()) { Some(node) } else { None }
45+
}
46+
47+
fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
48+
node.map_attrs(|attrs| {
49+
attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
50+
})
51+
}
52+
5953
fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
6054
if !attr.check_name("cfg_attr") {
6155
return Some(attr);
@@ -89,13 +83,15 @@ impl<'a> StripUnconfigured<'a> {
8983
None
9084
}
9185
}
92-
}
9386

94-
impl<'a> CfgFolder for StripUnconfigured<'a> {
95-
// Determine if an item should be translated in the current crate
96-
// configuration based on the item's attributes
87+
// Determine if a node with the given attributes should be included in this configuation.
9788
fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
9889
attrs.iter().all(|attr| {
90+
// When not compiling with --test we should not compile the #[test] functions
91+
if !self.should_test && is_test_or_bench(attr) {
92+
return false;
93+
}
94+
9995
let mis = match attr.node.value.node {
10096
ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis,
10197
_ => return true
@@ -112,21 +108,17 @@ impl<'a> CfgFolder for StripUnconfigured<'a> {
112108
})
113109
}
114110

115-
fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T {
116-
node.map_attrs(|attrs| {
117-
attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
118-
})
119-
}
120-
111+
// Visit attributes on expression and statements (but not attributes on items in blocks).
121112
fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
122113
// flag the offending attributes
123114
for attr in attrs.iter() {
124115
self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span));
125116
}
126117
}
127118

119+
// Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
128120
fn visit_unremovable_expr(&mut self, expr: &ast::Expr) {
129-
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
121+
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
130122
let msg = "removing an expression is not supported in this position";
131123
self.diag.diag.span_err(attr.span, msg);
132124
}
@@ -135,15 +127,15 @@ impl<'a> CfgFolder for StripUnconfigured<'a> {
135127

136128
// Support conditional compilation by transforming the AST, stripping out
137129
// any items that do not belong in the current configuration
138-
pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
130+
pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, should_test: bool,
139131
feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
140132
-> ast::Crate
141133
{
142134
let config = &krate.config.clone();
143-
StripUnconfigured::new(config, diagnostic, feature_gated_cfgs).fold_crate(krate)
135+
StripUnconfigured::new(config, should_test, diagnostic, feature_gated_cfgs).fold_crate(krate)
144136
}
145137

146-
impl<T: CfgFolder> fold::Folder for T {
138+
impl<'a> fold::Folder for StripUnconfigured<'a> {
147139
fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
148140
ast::ForeignMod {
149141
abi: foreign_mod.abi,
@@ -204,7 +196,7 @@ impl<T: CfgFolder> fold::Folder for T {
204196
// NB: This is intentionally not part of the fold_expr() function
205197
// in order for fold_opt_expr() to be able to avoid this check
206198
self.visit_unremovable_expr(&expr);
207-
let expr = self.process_attrs(expr);
199+
let expr = self.process_cfg_attrs(expr);
208200
fold_expr(self, expr)
209201
}
210202

@@ -256,7 +248,7 @@ impl<T: CfgFolder> fold::Folder for T {
256248
}
257249
}
258250

259-
fn fold_expr<F: CfgFolder>(folder: &mut F, expr: P<ast::Expr>) -> P<ast::Expr> {
251+
fn fold_expr(folder: &mut StripUnconfigured, expr: P<ast::Expr>) -> P<ast::Expr> {
260252
expr.map(|ast::Expr {id, span, node, attrs}| {
261253
fold::noop_fold_expr(ast::Expr {
262254
id: id,
@@ -278,6 +270,10 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
278270
attr.check_name("cfg")
279271
}
280272

273+
fn is_test_or_bench(attr: &ast::Attribute) -> bool {
274+
attr.check_name("test") || attr.check_name("bench")
275+
}
276+
281277
pub trait CfgDiag {
282278
fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
283279
fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);

src/libsyntax/ext/expand.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
10011001

10021002
fn strip_unconfigured(&mut self) -> StripUnconfigured {
10031003
StripUnconfigured::new(&self.cx.cfg,
1004+
self.cx.ecfg.should_test,
10041005
&self.cx.parse_sess.span_diagnostic,
10051006
self.cx.feature_gated_cfgs)
10061007
}
@@ -1106,6 +1107,7 @@ pub struct ExpansionConfig<'feat> {
11061107
pub features: Option<&'feat Features>,
11071108
pub recursion_limit: usize,
11081109
pub trace_mac: bool,
1110+
pub should_test: bool, // If false, strip `#[test]` nodes
11091111
}
11101112

11111113
macro_rules! feature_tests {
@@ -1128,6 +1130,7 @@ impl<'feat> ExpansionConfig<'feat> {
11281130
features: None,
11291131
recursion_limit: 64,
11301132
trace_mac: false,
1133+
should_test: false,
11311134
}
11321135
}
11331136

src/libsyntax/test.rs

+1-14
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn modify_for_testing(sess: &ParseSess,
8181
if should_test {
8282
generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic)
8383
} else {
84-
strip_test_functions(krate)
84+
krate
8585
}
8686
}
8787

@@ -306,19 +306,6 @@ fn generate_test_harness(sess: &ParseSess,
306306
return res;
307307
}
308308

309-
fn strip_test_functions(krate: ast::Crate) -> ast::Crate {
310-
// When not compiling with --test we should not compile the
311-
// #[test] functions
312-
struct StripTests;
313-
impl config::CfgFolder for StripTests {
314-
fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
315-
!attr::contains_name(attrs, "test") && !attr::contains_name(attrs, "bench")
316-
}
317-
}
318-
319-
StripTests.fold_crate(krate)
320-
}
321-
322309
/// Craft a span that will be ignored by the stability lint's
323310
/// call to codemap's is_internal check.
324311
/// The expanded code calls some unstable functions in the test crate.

src/test/compile-fail/cfg-non-opt-expr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ fn main() {
1717
//~^ ERROR removing an expression is not supported in this position
1818
let _ = [1, 2, 3][#[cfg(unset)] 1];
1919
//~^ ERROR removing an expression is not supported in this position
20+
let _ = #[test] ();
21+
//~^ ERROR removing an expression is not supported in this position
2022
}

0 commit comments

Comments
 (0)