@@ -20,7 +20,17 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
2020 // but they don't really handle the absence of files well.
2121 let mut ignore = false ;
2222 let mut requires_reason = false ;
23- let mut found_reason = false ;
23+ let mut explicit_reason = None ;
24+ let mut implicit_reasons = Vec :: new ( ) ;
25+ macro_rules! set_ignore {
26+ ( $predicate: expr, $( $arg: tt) * ) => {
27+ let p = $predicate;
28+ ignore |= p;
29+ if p {
30+ implicit_reasons. push( std:: fmt:: format( format_args!( $( $arg) * ) ) ) ;
31+ }
32+ } ;
33+ }
2434 let is_not_nightly = !version ( ) . 1 ;
2535 for rule in split_rules ( attr) {
2636 match rule. as_str ( ) {
@@ -29,57 +39,81 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
2939 // explicit opt-in (these generally only work on linux, and
3040 // have some extra requirements, and are slow, and can pollute
3141 // the environment since it downloads dependencies).
32- ignore |= is_not_nightly;
33- ignore |= option_env ! ( "CARGO_RUN_BUILD_STD_TESTS" ) . is_none ( ) ;
42+ set_ignore ! ( is_not_nightly, "requires nightly" ) ;
43+ set_ignore ! (
44+ option_env!( "CARGO_RUN_BUILD_STD_TESTS" ) . is_none( ) ,
45+ "CARGO_RUN_BUILD_STD_TESTS must be set"
46+ ) ;
3447 }
3548 "build_std_mock" => {
3649 // Only run the "mock" build-std tests on nightly and disable
3750 // for windows-gnu which is missing object files (see
3851 // https://github.com/rust-lang/wg-cargo-std-aware/issues/46).
39- ignore |= is_not_nightly;
40- ignore |= cfg ! ( all( target_os = "windows" , target_env = "gnu" ) ) ;
52+ set_ignore ! ( is_not_nightly, "requires nightly" ) ;
53+ set_ignore ! (
54+ cfg!( all( target_os = "windows" , target_env = "gnu" ) ) ,
55+ "does not work on windows-gnu"
56+ ) ;
4157 }
4258 "nightly" => {
4359 requires_reason = true ;
44- ignore |= is_not_nightly ;
60+ set_ignore ! ( is_not_nightly , "requires nightly" ) ;
4561 }
4662 s if s. starts_with ( "requires_" ) => {
4763 let command = & s[ 9 ..] ;
48- ignore |= ! has_command ( command) ;
64+ set_ignore ! ( ! has_command( command) , "{command} not installed" ) ;
4965 }
5066 s if s. starts_with ( ">=1." ) => {
5167 requires_reason = true ;
5268 let min_minor = s[ 4 ..] . parse ( ) . unwrap ( ) ;
53- ignore |= version ( ) . 0 < min_minor;
69+ let minor = version ( ) . 0 ;
70+ set_ignore ! ( minor < min_minor, "requires rustc 1.{minor} or newer" ) ;
5471 }
5572 s if s. starts_with ( "reason=" ) => {
56- found_reason = true ;
73+ explicit_reason = Some ( s [ 7 .. ] . parse ( ) . unwrap ( ) ) ;
5774 }
5875 _ => panic ! ( "unknown rule {:?}" , rule) ,
5976 }
6077 }
61- if requires_reason && !found_reason {
78+ if requires_reason && explicit_reason . is_none ( ) {
6279 panic ! (
6380 "#[cargo_test] with a rule also requires a reason, \
6481 such as #[cargo_test(nightly, reason = \" needs -Z unstable-thing\" )]"
6582 ) ;
6683 }
6784
85+ // Construct the appropriate attributes.
6886 let span = Span :: call_site ( ) ;
6987 let mut ret = TokenStream :: new ( ) ;
70- let add_attr = |ret : & mut TokenStream , attr_name| {
88+ let add_attr = |ret : & mut TokenStream , attr_name, attr_input | {
7189 ret. extend ( Some ( TokenTree :: from ( Punct :: new ( '#' , Spacing :: Alone ) ) ) ) ;
7290 let attr = TokenTree :: from ( Ident :: new ( attr_name, span) ) ;
91+ let mut attr_stream: TokenStream = attr. into ( ) ;
92+ if let Some ( input) = attr_input {
93+ attr_stream. extend ( input) ;
94+ }
7395 ret. extend ( Some ( TokenTree :: from ( Group :: new (
7496 Delimiter :: Bracket ,
75- attr . into ( ) ,
97+ attr_stream ,
7698 ) ) ) ) ;
7799 } ;
78- add_attr ( & mut ret, "test" ) ;
100+ add_attr ( & mut ret, "test" , None ) ;
79101 if ignore {
80- add_attr ( & mut ret, "ignore" ) ;
102+ let reason = explicit_reason
103+ . or_else ( || {
104+ ( !implicit_reasons. is_empty ( ) )
105+ . then ( || TokenTree :: from ( Literal :: string ( & implicit_reasons. join ( ", " ) ) ) . into ( ) )
106+ } )
107+ . map ( |reason : TokenStream | {
108+ let mut stream = TokenStream :: new ( ) ;
109+ stream. extend ( Some ( TokenTree :: from ( Punct :: new ( '=' , Spacing :: Alone ) ) ) ) ;
110+ stream. extend ( Some ( reason) ) ;
111+ stream
112+ } ) ;
113+ add_attr ( & mut ret, "ignore" , reason) ;
81114 }
82115
116+ // Find where the function body starts, and add the boilerplate at the start.
83117 for token in item {
84118 let group = match token {
85119 TokenTree :: Group ( g) => {
0 commit comments