Skip to content

Commit 14e5e0e

Browse files
committed
Don't allow #[should_panic] with non-() tests
1 parent 6c53749 commit 14e5e0e

File tree

4 files changed

+79
-34
lines changed

4 files changed

+79
-34
lines changed

src/libsyntax/test.rs

+40-27
Original file line numberDiff line numberDiff line change
@@ -320,56 +320,69 @@ fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
320320
#[derive(PartialEq)]
321321
enum HasTestSignature {
322322
Yes,
323-
No,
323+
No(BadTestSignature),
324+
}
325+
326+
#[derive(PartialEq)]
327+
enum BadTestSignature {
324328
NotEvenAFunction,
329+
WrongTypeSignature,
330+
NoArgumentsAllowed,
331+
ShouldPanicOnlyWithNoArgs,
325332
}
326333

327334
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
328335
let has_test_attr = attr::contains_name(&i.attrs, "test");
329336

330337
fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
338+
let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
331339
match i.node {
332340
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
333341
// If the termination trait is active, the compiler will check that the output
334342
// type implements the `Termination` trait as `libtest` enforces that.
335-
let output_matches = if cx.features.termination_trait_test {
336-
true
337-
} else {
338-
let no_output = match decl.output {
339-
ast::FunctionRetTy::Default(..) => true,
340-
ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
341-
_ => false
342-
};
343-
344-
no_output && !generics.is_parameterized()
343+
let has_output = match decl.output {
344+
ast::FunctionRetTy::Default(..) => false,
345+
ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => false,
346+
_ => true
345347
};
346348

347-
if decl.inputs.is_empty() && output_matches {
348-
Yes
349-
} else {
350-
No
349+
if !decl.inputs.is_empty() {
350+
return No(BadTestSignature::NoArgumentsAllowed);
351+
}
352+
353+
match (has_output, cx.features.termination_trait_test, has_should_panic_attr) {
354+
(true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
355+
(true, true, false) => if generics.is_parameterized() {
356+
No(BadTestSignature::WrongTypeSignature)
357+
} else {
358+
Yes
359+
},
360+
(true, false, _) => No(BadTestSignature::WrongTypeSignature),
361+
(false, _, _) => Yes
351362
}
352363
}
353-
_ => NotEvenAFunction,
364+
_ => No(BadTestSignature::NotEvenAFunction),
354365
}
355366
}
356367

357368
let has_test_signature = if has_test_attr {
358369
let diag = cx.span_diagnostic;
359370
match has_test_signature(cx, i) {
360371
Yes => true,
361-
No => {
362-
if cx.features.termination_trait_test {
363-
diag.span_err(i.span, "functions used as tests can not have any arguments");
364-
} else {
365-
diag.span_err(i.span, "functions used as tests must have signature fn() -> ()");
372+
No(cause) => {
373+
match cause {
374+
BadTestSignature::NotEvenAFunction =>
375+
diag.span_err(i.span, "only functions may be used as tests"),
376+
BadTestSignature::WrongTypeSignature =>
377+
diag.span_err(i.span,
378+
"functions used as tests must have signature fn() -> ()"),
379+
BadTestSignature::NoArgumentsAllowed =>
380+
diag.span_err(i.span, "functions used as tests can not have any arguments"),
381+
BadTestSignature::ShouldPanicOnlyWithNoArgs =>
382+
diag.span_err(i.span, "functions using `#[should_panic]` must return `()`"),
366383
}
367384
false
368-
},
369-
NotEvenAFunction => {
370-
diag.span_err(i.span, "only functions may be used as tests");
371-
false
372-
},
385+
}
373386
}
374387
} else {
375388
false
@@ -407,7 +420,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
407420
// well before resolve, can't get too deep.
408421
input_cnt == 1 && output_matches
409422
}
410-
_ => false
423+
_ => false
411424
}
412425
}
413426

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2017 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+
// compile-flags: --test
12+
13+
#![feature(termination_trait_test)]
14+
#![feature(test)]
15+
16+
extern crate test;
17+
use std::num::ParseIntError;
18+
use test::Bencher;
19+
20+
#[test]
21+
#[should_panic]
22+
fn not_a_num() -> Result<(), ParseIntError> {
23+
//~^ ERROR functions using `#[should_panic]` must return `()`
24+
let _: u32 = "abc".parse()?;
25+
Ok(())
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: functions using `#[should_panic]` must return `()`
2+
--> $DIR/termination-trait-in-test-should-panic.rs:22:1
3+
|
4+
LL | / fn not_a_num() -> Result<(), ParseIntError> {
5+
LL | | //~^ ERROR functions using `#[should_panic]` must return `()`
6+
LL | | let _: u32 = "abc".parse()?;
7+
LL | | Ok(())
8+
LL | | }
9+
| |_^
10+
11+
error: aborting due to previous error
12+

src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
// compile-flags: --test
12+
// run-pass
1213

1314
#![feature(termination_trait_test)]
1415
#![feature(test)]
@@ -23,13 +24,6 @@ fn is_a_num() -> Result<(), ParseIntError> {
2324
Ok(())
2425
}
2526

26-
#[test]
27-
#[should_panic]
28-
fn not_a_num() -> Result<(), ParseIntError> {
29-
let _: u32 = "abc".parse()?;
30-
Ok(())
31-
}
32-
3327
#[bench]
3428
fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
3529
Ok(())

0 commit comments

Comments
 (0)