2018-07-21 01:04:02 +00:00
/// The expansion from a test function to the appropriate test struct for libtest
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
2021-11-24 09:20:23 +00:00
use crate ::util ::{ check_builtin_macro_attribute , warn_on_duplicate_attribute } ;
2019-10-08 12:15:26 +00:00
2020-04-27 17:56:11 +00:00
use rustc_ast as ast ;
2020-02-29 17:37:32 +00:00
use rustc_ast ::attr ;
2020-11-23 00:32:39 +00:00
use rustc_ast ::ptr ::P ;
2020-01-11 16:02:46 +00:00
use rustc_ast_pretty ::pprust ;
2022-01-15 09:16:13 +00:00
use rustc_errors ::Applicability ;
2019-12-29 14:23:55 +00:00
use rustc_expand ::base ::* ;
2020-07-30 01:27:50 +00:00
use rustc_session ::Session ;
2020-04-19 11:00:18 +00:00
use rustc_span ::symbol ::{ sym , Ident , Symbol } ;
2019-12-31 17:15:40 +00:00
use rustc_span ::Span ;
2019-07-18 23:10:36 +00:00
2018-07-21 01:04:02 +00:00
use std ::iter ;
2019-07-18 18:29:15 +00:00
// #[test_case] is used by custom test authors to mark tests
// When building for test, it needs to make the item public and gensym the name
// Otherwise, we'll omit the item. This behavior means that any item annotated
// with #[test_case] is never addressable.
//
// We mark item with an inert attribute "rustc_test_marker" which the test generation
// logic will pick up on.
pub fn expand_test_case (
ecx : & mut ExtCtxt < '_ > ,
attr_sp : Span ,
meta_item : & ast ::MetaItem ,
2019-12-24 22:38:22 +00:00
anno_item : Annotatable ,
2019-07-18 18:29:15 +00:00
) -> Vec < Annotatable > {
check_builtin_macro_attribute ( ecx , meta_item , sym ::test_case ) ;
2021-11-24 09:20:23 +00:00
warn_on_duplicate_attribute ( & ecx , & anno_item , sym ::test_case ) ;
2019-07-18 18:29:15 +00:00
2019-12-24 22:38:22 +00:00
if ! ecx . ecfg . should_test {
return vec! [ ] ;
}
2019-07-18 18:29:15 +00:00
2019-08-25 20:03:24 +00:00
let sp = ecx . with_def_site_ctxt ( attr_sp ) ;
2019-07-18 18:29:15 +00:00
let mut item = anno_item . expect_item ( ) ;
item = item . map ( | mut item | {
2020-08-21 23:11:00 +00:00
item . vis = ast ::Visibility {
span : item . vis . span ,
kind : ast ::VisibilityKind ::Public ,
tokens : None ,
} ;
2019-08-25 20:03:24 +00:00
item . ident . span = item . ident . span . with_ctxt ( sp . ctxt ( ) ) ;
2019-12-24 22:38:22 +00:00
item . attrs . push ( ecx . attribute ( ecx . meta_word ( sp , sym ::rustc_test_marker ) ) ) ;
2019-07-18 18:29:15 +00:00
item
} ) ;
2019-12-24 22:38:22 +00:00
return vec! [ Annotatable ::Item ( item ) ] ;
2019-07-18 18:29:15 +00:00
}
2018-07-21 01:04:02 +00:00
pub fn expand_test (
2019-02-04 12:49:54 +00:00
cx : & mut ExtCtxt < '_ > ,
2018-07-21 01:04:02 +00:00
attr_sp : Span ,
2019-07-18 23:10:36 +00:00
meta_item : & ast ::MetaItem ,
2018-07-21 01:04:02 +00:00
item : Annotatable ,
) -> Vec < Annotatable > {
2019-07-18 23:10:36 +00:00
check_builtin_macro_attribute ( cx , meta_item , sym ::test ) ;
2021-11-24 09:20:23 +00:00
warn_on_duplicate_attribute ( & cx , & item , sym ::test ) ;
2018-07-21 01:04:02 +00:00
expand_test_or_bench ( cx , attr_sp , item , false )
}
pub fn expand_bench (
2019-02-04 12:49:54 +00:00
cx : & mut ExtCtxt < '_ > ,
2018-07-21 01:04:02 +00:00
attr_sp : Span ,
2019-07-18 23:10:36 +00:00
meta_item : & ast ::MetaItem ,
2018-07-21 01:04:02 +00:00
item : Annotatable ,
) -> Vec < Annotatable > {
2019-07-18 23:10:36 +00:00
check_builtin_macro_attribute ( cx , meta_item , sym ::bench ) ;
2021-11-24 09:20:23 +00:00
warn_on_duplicate_attribute ( & cx , & item , sym ::bench ) ;
2018-07-21 01:04:02 +00:00
expand_test_or_bench ( cx , attr_sp , item , true )
}
pub fn expand_test_or_bench (
2019-02-04 12:49:54 +00:00
cx : & mut ExtCtxt < '_ > ,
2018-07-21 01:04:02 +00:00
attr_sp : Span ,
item : Annotatable ,
2019-12-24 22:38:22 +00:00
is_bench : bool ,
2018-07-21 01:04:02 +00:00
) -> Vec < Annotatable > {
// If we're not in test configuration, remove the annotated item
2019-12-24 22:38:22 +00:00
if ! cx . ecfg . should_test {
return vec! [ ] ;
}
2018-07-21 01:04:02 +00:00
2020-11-23 00:32:39 +00:00
let ( item , is_stmt ) = match item {
Annotatable ::Item ( i ) = > ( i , false ) ,
Annotatable ::Stmt ( stmt ) if matches! ( stmt . kind , ast ::StmtKind ::Item ( _ ) ) = > {
// FIXME: Use an 'if let' guard once they are implemented
if let ast ::StmtKind ::Item ( i ) = stmt . into_inner ( ) . kind {
( i , true )
} else {
unreachable! ( )
}
}
2020-03-17 12:27:56 +00:00
other = > {
cx . struct_span_err (
other . span ( ) ,
2019-12-24 22:38:22 +00:00
" `#[test]` attribute is only allowed on non associated functions " ,
)
2020-03-17 12:27:56 +00:00
. emit ( ) ;
return vec! [ other ] ;
}
2019-12-24 22:38:22 +00:00
} ;
2018-07-21 01:04:02 +00:00
2022-01-15 09:16:13 +00:00
// Note: non-associated fn items are already handled by `expand_test_or_bench`
if ! matches! ( item . kind , ast ::ItemKind ::Fn ( _ ) ) {
2022-03-04 20:34:10 +00:00
let diag = & cx . sess . parse_sess . span_diagnostic ;
let msg = " the `#[test]` attribute may only be used on a non-associated function " ;
let mut err = match item . kind {
// These were a warning before #92959 and need to continue being that to avoid breaking
// stable user code (#94508).
ast ::ItemKind ::MacCall ( _ ) = > diag . struct_span_warn ( attr_sp , msg ) ,
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
// reworked in the future to not need it, it'd be nice.
_ = > diag . struct_span_err ( attr_sp , msg ) . forget_guarantee ( ) ,
} ;
err . span_label ( attr_sp , " the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions " )
2022-01-15 09:16:13 +00:00
. span_label ( item . span , format! ( " expected a non-associated function, found {} {} " , item . kind . article ( ) , item . kind . descr ( ) ) )
2022-06-13 06:48:40 +00:00
. span_suggestion ( attr_sp , " replace with conditional compilation to make the item only exist when tests are being run " , " #[cfg(test)] " , Applicability ::MaybeIncorrect )
2022-01-15 09:16:13 +00:00
. emit ( ) ;
2018-07-21 01:04:02 +00:00
return vec! [ Annotatable ::Item ( item ) ] ;
}
// has_*_signature will report any errors in the type so compilation
// will fail. We shouldn't try to expand in this case because the errors
// would be spurious.
2019-12-24 22:38:22 +00:00
if ( ! is_bench & & ! has_test_signature ( cx , & item ) )
| | ( is_bench & & ! has_bench_signature ( cx , & item ) )
{
2018-07-21 01:04:02 +00:00
return vec! [ Annotatable ::Item ( item ) ] ;
}
2019-08-25 20:03:24 +00:00
let ( sp , attr_sp ) = ( cx . with_def_site_ctxt ( item . span ) , cx . with_def_site_ctxt ( attr_sp ) ) ;
2018-07-21 01:04:02 +00:00
2020-04-19 11:00:18 +00:00
let test_id = Ident ::new ( sym ::test , attr_sp ) ;
2018-07-21 01:04:02 +00:00
// creates test::$name
2020-07-14 05:05:26 +00:00
let test_path = | name | cx . path ( sp , vec! [ test_id , Ident ::from_str_and_span ( name , sp ) ] ) ;
2018-07-21 01:04:02 +00:00
2019-04-17 09:02:04 +00:00
// creates test::ShouldPanic::$name
2020-07-14 05:05:26 +00:00
let should_panic_path = | name | {
cx . path (
sp ,
vec! [
test_id ,
Ident ::from_str_and_span ( " ShouldPanic " , sp ) ,
Ident ::from_str_and_span ( name , sp ) ,
] ,
)
} ;
2018-07-21 01:04:02 +00:00
2019-09-28 14:07:18 +00:00
// creates test::TestType::$name
2020-07-14 05:05:26 +00:00
let test_type_path = | name | {
cx . path (
sp ,
vec! [
test_id ,
Ident ::from_str_and_span ( " TestType " , sp ) ,
Ident ::from_str_and_span ( name , sp ) ,
] ,
)
} ;
2019-09-28 14:07:18 +00:00
2018-07-21 01:04:02 +00:00
// creates $name: $expr
2020-07-14 05:05:26 +00:00
let field = | name , expr | cx . field_imm ( sp , Ident ::from_str_and_span ( name , sp ) , expr ) ;
2018-07-21 01:04:02 +00:00
let test_fn = if is_bench {
// A simple ident for a lambda
2020-07-14 05:05:26 +00:00
let b = Ident ::from_str_and_span ( " b " , attr_sp ) ;
2018-07-21 01:04:02 +00:00
2019-12-24 22:38:22 +00:00
cx . expr_call (
sp ,
cx . expr_path ( test_path ( " StaticBenchFn " ) ) ,
vec! [
// |b| self::test::assert_test_result(
cx . lambda1 (
sp ,
cx . expr_call (
sp ,
cx . expr_path ( test_path ( " assert_test_result " ) ) ,
vec! [
// super::$test_fn(b)
cx . expr_call (
sp ,
cx . expr_path ( cx . path ( sp , vec! [ item . ident ] ) ) ,
vec! [ cx . expr_ident ( sp , b ) ] ,
) ,
] ,
) ,
b ,
) , // )
] ,
)
2018-07-21 01:04:02 +00:00
} else {
2019-12-24 22:38:22 +00:00
cx . expr_call (
sp ,
cx . expr_path ( test_path ( " StaticTestFn " ) ) ,
vec! [
// || {
cx . lambda0 (
sp ,
// test::assert_test_result(
cx . expr_call (
sp ,
cx . expr_path ( test_path ( " assert_test_result " ) ) ,
vec! [
// $test_fn()
cx . expr_call ( sp , cx . expr_path ( cx . path ( sp , vec! [ item . ident ] ) ) , vec! [ ] ) , // )
] ,
) , // }
) , // )
] ,
)
2018-07-21 01:04:02 +00:00
} ;
2019-12-24 22:38:22 +00:00
let mut test_const = cx . item (
sp ,
2020-04-19 11:00:18 +00:00
Ident ::new ( item . ident . name , sp ) ,
2018-09-02 16:03:24 +00:00
vec! [
// #[cfg(test)]
2019-12-24 22:38:22 +00:00
cx . attribute ( attr ::mk_list_item (
2020-04-19 11:00:18 +00:00
Ident ::new ( sym ::cfg , attr_sp ) ,
vec! [ attr ::mk_nested_word_item ( Ident ::new ( sym ::test , attr_sp ) ) ] ,
2019-12-24 22:38:22 +00:00
) ) ,
2018-09-02 16:03:24 +00:00
// #[rustc_test_marker]
2019-07-30 18:12:52 +00:00
cx . attribute ( cx . meta_word ( attr_sp , sym ::rustc_test_marker ) ) ,
2018-09-02 16:03:24 +00:00
] ,
2018-07-21 01:04:02 +00:00
// const $ident: test::TestDescAndFn =
2019-12-24 22:38:22 +00:00
ast ::ItemKind ::Const (
2020-02-23 09:24:30 +00:00
ast ::Defaultness ::Final ,
2019-12-24 22:38:22 +00:00
cx . ty ( sp , ast ::TyKind ::Path ( None , test_path ( " TestDescAndFn " ) ) ) ,
2018-07-21 01:04:02 +00:00
// test::TestDescAndFn {
2020-02-14 13:21:02 +00:00
Some (
cx . expr_struct (
sp ,
test_path ( " TestDescAndFn " ) ,
vec! [
// desc: test::TestDesc {
field (
" desc " ,
cx . expr_struct (
sp ,
test_path ( " TestDesc " ) ,
vec! [
// name: "path::to::test"
field (
" name " ,
cx . expr_call (
2019-12-24 22:38:22 +00:00
sp ,
2020-02-14 13:21:02 +00:00
cx . expr_path ( test_path ( " StaticTestName " ) ) ,
vec! [ cx . expr_str (
sp ,
Symbol ::intern ( & item_path (
// skip the name of the root module
& cx . current_expansion . module . mod_path [ 1 .. ] ,
& item . ident ,
) ) ,
) ] ,
2019-12-24 22:38:22 +00:00
) ,
2020-02-14 13:21:02 +00:00
) ,
// ignore: true | false
2020-07-30 01:27:50 +00:00
field (
" ignore " ,
cx . expr_bool ( sp , should_ignore ( & cx . sess , & item ) ) ,
) ,
2022-01-10 06:01:12 +00:00
// ignore_message: Some("...") | None
field (
" ignore_message " ,
if let Some ( msg ) = should_ignore_message ( cx , & item ) {
cx . expr_some ( sp , cx . expr_str ( sp , msg ) )
} else {
cx . expr_none ( sp )
} ,
) ,
2021-05-03 12:55:22 +00:00
// compile_fail: true | false
field ( " compile_fail " , cx . expr_bool ( sp , false ) ) ,
// no_run: true | false
field ( " no_run " , cx . expr_bool ( sp , false ) ) ,
2020-02-14 13:21:02 +00:00
// should_panic: ...
field (
" should_panic " ,
match should_panic ( cx , & item ) {
// test::ShouldPanic::No
ShouldPanic ::No = > {
cx . expr_path ( should_panic_path ( " No " ) )
}
// test::ShouldPanic::Yes
ShouldPanic ::Yes ( None ) = > {
cx . expr_path ( should_panic_path ( " Yes " ) )
}
// test::ShouldPanic::YesWithMessage("...")
ShouldPanic ::Yes ( Some ( sym ) ) = > cx . expr_call (
sp ,
cx . expr_path ( should_panic_path ( " YesWithMessage " ) ) ,
vec! [ cx . expr_str ( sp , sym ) ] ,
) ,
} ,
) ,
// test_type: ...
field (
" test_type " ,
match test_type ( cx ) {
// test::TestType::UnitTest
TestType ::UnitTest = > {
cx . expr_path ( test_type_path ( " UnitTest " ) )
}
// test::TestType::IntegrationTest
TestType ::IntegrationTest = > {
cx . expr_path ( test_type_path ( " IntegrationTest " ) )
}
// test::TestPath::Unknown
TestType ::Unknown = > {
cx . expr_path ( test_type_path ( " Unknown " ) )
}
} ,
) ,
// },
] ,
) ,
2019-09-28 14:07:18 +00:00
) ,
2020-02-14 13:21:02 +00:00
// testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
field ( " testfn " , test_fn ) , // }
] ,
) , // }
) ,
2019-12-24 22:38:22 +00:00
) ,
) ;
test_const = test_const . map ( | mut tc | {
2020-08-21 23:11:00 +00:00
tc . vis . kind = ast ::VisibilityKind ::Public ;
2019-12-24 22:38:22 +00:00
tc
} ) ;
2018-07-21 01:04:02 +00:00
2019-08-25 20:03:24 +00:00
// extern crate test
2019-12-24 22:38:22 +00:00
let test_extern = cx . item ( sp , test_id , vec! [ ] , ast ::ItemKind ::ExternCrate ( None ) ) ;
2018-07-21 01:04:02 +00:00
2020-08-05 11:35:53 +00:00
tracing ::debug! ( " synthetic test item: \n {} \n " , pprust ::item_to_string ( & test_const ) ) ;
2018-07-21 01:04:02 +00:00
2020-11-23 00:32:39 +00:00
if is_stmt {
vec! [
// Access to libtest under a hygienic name
Annotatable ::Stmt ( P ( cx . stmt_item ( sp , test_extern ) ) ) ,
// The generated test case
Annotatable ::Stmt ( P ( cx . stmt_item ( sp , test_const ) ) ) ,
// The original item
Annotatable ::Stmt ( P ( cx . stmt_item ( sp , item ) ) ) ,
]
} else {
vec! [
// Access to libtest under a hygienic name
Annotatable ::Item ( test_extern ) ,
// The generated test case
Annotatable ::Item ( test_const ) ,
// The original item
Annotatable ::Item ( item ) ,
]
}
2018-07-21 01:04:02 +00:00
}
2020-04-19 11:00:18 +00:00
fn item_path ( mod_path : & [ Ident ] , item_ident : & Ident ) -> String {
2019-12-24 22:38:22 +00:00
mod_path
. iter ( )
. chain ( iter ::once ( item_ident ) )
. map ( | x | x . to_string ( ) )
. collect ::< Vec < String > > ( )
. join ( " :: " )
2018-07-21 01:04:02 +00:00
}
enum ShouldPanic {
No ,
Yes ( Option < Symbol > ) ,
}
2020-07-30 01:27:50 +00:00
fn should_ignore ( sess : & Session , i : & ast ::Item ) -> bool {
sess . contains_name ( & i . attrs , sym ::ignore )
2018-07-21 01:04:02 +00:00
}
2022-01-10 06:01:12 +00:00
fn should_ignore_message ( cx : & ExtCtxt < '_ > , i : & ast ::Item ) -> Option < Symbol > {
match cx . sess . find_by_name ( & i . attrs , sym ::ignore ) {
Some ( attr ) = > {
match attr . meta_item_list ( ) {
// Handle #[ignore(bar = "foo")]
Some ( _ ) = > None ,
// Handle #[ignore] and #[ignore = "message"]
None = > attr . value_str ( ) ,
}
}
None = > None ,
}
}
2019-02-04 12:49:54 +00:00
fn should_panic ( cx : & ExtCtxt < '_ > , i : & ast ::Item ) -> ShouldPanic {
2020-07-30 01:27:50 +00:00
match cx . sess . find_by_name ( & i . attrs , sym ::should_panic ) {
2018-07-21 01:04:02 +00:00
Some ( attr ) = > {
2020-07-30 01:27:50 +00:00
let sd = & cx . sess . parse_sess . span_diagnostic ;
2019-01-01 23:21:05 +00:00
2018-07-21 01:04:02 +00:00
match attr . meta_item_list ( ) {
// Handle #[should_panic(expected = "foo")]
Some ( list ) = > {
2019-12-24 22:38:22 +00:00
let msg = list
. iter ( )
2020-08-02 10:17:20 +00:00
. find ( | mi | mi . has_name ( sym ::expected ) )
2018-07-21 01:04:02 +00:00
. and_then ( | mi | mi . meta_item ( ) )
. and_then ( | mi | mi . value_str ( ) ) ;
if list . len ( ) ! = 1 | | msg . is_none ( ) {
sd . struct_span_warn (
2019-03-03 17:56:24 +00:00
attr . span ,
2018-07-21 01:04:02 +00:00
" argument must be of the form: \
2019-12-24 22:38:22 +00:00
` expected = \ " error message \" ` " ,
)
. note (
2020-01-10 14:13:05 +00:00
" errors in this attribute were erroneously \
2018-07-21 01:04:02 +00:00
allowed and will become a hard error in a \
2021-10-03 06:53:02 +00:00
future release " ,
2019-12-24 22:38:22 +00:00
)
. emit ( ) ;
2018-07-21 01:04:02 +00:00
ShouldPanic ::Yes ( None )
} else {
ShouldPanic ::Yes ( msg )
}
2019-12-24 22:38:22 +00:00
}
2019-01-01 23:21:05 +00:00
// Handle #[should_panic] and #[should_panic = "expected"]
2019-12-24 22:38:22 +00:00
None = > ShouldPanic ::Yes ( attr . value_str ( ) ) ,
2018-07-21 01:04:02 +00:00
}
}
None = > ShouldPanic ::No ,
}
}
2019-09-28 14:07:18 +00:00
enum TestType {
UnitTest ,
IntegrationTest ,
Unknown ,
}
/// Attempts to determine the type of test.
/// Since doctests are created without macro expanding, only possible variants here
/// are `UnitTest`, `IntegrationTest` or `Unknown`.
fn test_type ( cx : & ExtCtxt < '_ > ) -> TestType {
// Root path from context contains the topmost sources directory of the crate.
// I.e., for `project` with sources in `src` and tests in `tests` folders
// (no matter how many nested folders lie inside),
// there will be two different root paths: `/project/src` and `/project/tests`.
let crate_path = cx . root_path . as_path ( ) ;
if crate_path . ends_with ( " src " ) {
// `/src` folder contains unit-tests.
TestType ::UnitTest
} else if crate_path . ends_with ( " tests " ) {
// `/tests` folder contains integration tests.
TestType ::IntegrationTest
} else {
// Crate layout doesn't match expected one, test type is unknown.
TestType ::Unknown
}
}
2019-02-04 12:49:54 +00:00
fn has_test_signature ( cx : & ExtCtxt < '_ > , i : & ast ::Item ) -> bool {
2020-07-30 01:27:50 +00:00
let has_should_panic_attr = cx . sess . contains_name ( & i . attrs , sym ::should_panic ) ;
let sd = & cx . sess . parse_sess . span_diagnostic ;
2021-11-07 08:43:49 +00:00
if let ast ::ItemKind ::Fn ( box ast ::Fn { ref sig , ref generics , .. } ) = i . kind {
2020-01-30 01:42:33 +00:00
if let ast ::Unsafe ::Yes ( span ) = sig . header . unsafety {
sd . struct_span_err ( i . span , " unsafe functions cannot be used for tests " )
2020-02-11 07:24:05 +00:00
. span_label ( span , " `unsafe` because of this " )
2020-01-30 01:42:33 +00:00
. emit ( ) ;
2019-12-24 22:38:22 +00:00
return false ;
2018-07-21 01:04:02 +00:00
}
2020-01-30 04:31:04 +00:00
if let ast ::Async ::Yes { span , .. } = sig . header . asyncness {
sd . struct_span_err ( i . span , " async functions cannot be used for tests " )
2020-02-11 07:24:05 +00:00
. span_label ( span , " `async` because of this " )
2020-01-30 04:31:04 +00:00
. emit ( ) ;
2019-12-24 22:38:22 +00:00
return false ;
2018-07-21 01:04:02 +00:00
}
// If the termination trait is active, the compiler will check that the output
// type implements the `Termination` trait as `libtest` enforces that.
2019-11-07 12:33:37 +00:00
let has_output = match sig . decl . output {
2020-02-15 03:10:59 +00:00
ast ::FnRetTy ::Default ( .. ) = > false ,
ast ::FnRetTy ::Ty ( ref t ) if t . kind . is_unit ( ) = > false ,
2019-12-24 22:38:22 +00:00
_ = > true ,
2018-07-21 01:04:02 +00:00
} ;
2019-11-07 12:33:37 +00:00
if ! sig . decl . inputs . is_empty ( ) {
2018-07-21 01:04:02 +00:00
sd . span_err ( i . span , " functions used as tests can not have any arguments " ) ;
return false ;
}
match ( has_output , has_should_panic_attr ) {
( true , true ) = > {
sd . span_err ( i . span , " functions using `#[should_panic]` must return `()` " ) ;
false
2019-12-24 22:38:22 +00:00
}
( true , false ) = > {
if ! generics . params . is_empty ( ) {
sd . span_err ( i . span , " functions used as tests must have signature fn() -> () " ) ;
false
} else {
true
}
}
( false , _ ) = > true ,
2018-07-21 01:04:02 +00:00
}
} else {
2022-01-15 09:16:13 +00:00
// should be unreachable because `is_test_fn_item` should catch all non-fn items
2018-07-21 01:04:02 +00:00
false
}
}
2019-02-04 12:49:54 +00:00
fn has_bench_signature ( cx : & ExtCtxt < '_ > , i : & ast ::Item ) -> bool {
2021-11-07 08:43:49 +00:00
let has_sig = if let ast ::ItemKind ::Fn ( box ast ::Fn { ref sig , .. } ) = i . kind {
2018-11-27 02:59:49 +00:00
// N.B., inadequate check, but we're running
2018-07-21 01:04:02 +00:00
// well before resolve, can't get too deep.
2019-11-07 12:33:37 +00:00
sig . decl . inputs . len ( ) = = 1
2018-07-21 01:04:02 +00:00
} else {
false
} ;
if ! has_sig {
2020-07-30 01:27:50 +00:00
cx . sess . parse_sess . span_diagnostic . span_err (
2019-12-24 22:38:22 +00:00
i . span ,
" functions used as benches must have \
signature ` fn ( & mut Bencher ) -> impl Termination ` " ,
) ;
2018-07-21 01:04:02 +00:00
}
has_sig
}