diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 49ee276af4e6f..fcc68010a34c6 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use crate::errors; /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, attr}; +use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; @@ -122,11 +122,7 @@ pub fn expand_test_or_bench( let ast::ItemKind::Fn(fn_) = &item.kind else { not_testable_error(cx, attr_sp, Some(&item)); return if is_stmt { - vec![Annotatable::Stmt(P(ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: item.span, - kind: ast::StmtKind::Item(item), - }))] + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] } else { vec![Annotatable::Item(item)] }; @@ -138,7 +134,11 @@ pub fn expand_test_or_bench( if (!is_bench && !has_test_signature(cx, &item)) || (is_bench && !has_bench_signature(cx, &item)) { - return vec![Annotatable::Item(item)]; + return if is_stmt { + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] + } else { + vec![Annotatable::Item(item)] + }; } let sp = cx.with_def_site_ctxt(item.span); @@ -550,24 +550,21 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { return false; } - match (has_output, has_should_panic_attr) { - (true, true) => { - sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); - false - } - (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, + if has_should_panic_attr && has_output { + sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); + return false; + } + + if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) + { + sd.span_err( + i.span, + "functions used as tests can not have any non-lifetime generic parameters", + ); + return false; } + + true } _ => { // should be unreachable because `is_test_fn_item` should catch all non-fn items diff --git a/tests/ui/test-attrs/test-function-signature.rs b/tests/ui/test-attrs/test-function-signature.rs new file mode 100644 index 0000000000000..9e86e9209e320 --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.rs @@ -0,0 +1,31 @@ +// compile-flags: --test + +#[test] +fn foo() -> Result<(), ()> { + Ok(()) +} + +#[test] +fn bar() -> i32 { //~ ERROR the trait bound `i32: Termination` is not satisfied + 0 +} + +#[test] +fn baz(val: i32) {} //~ ERROR functions used as tests can not have any arguments + +#[test] +fn lifetime_generic<'a>() -> Result<(), &'a str> { + Err("coerce me to any lifetime") +} + +#[test] +fn type_generic() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +#[test] +fn const_generic() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +// Regression test for . This used to ICE. +fn nested() { + #[test] + fn foo(arg: ()) {} //~ ERROR functions used as tests can not have any arguments +} diff --git a/tests/ui/test-attrs/test-function-signature.stderr b/tests/ui/test-attrs/test-function-signature.stderr new file mode 100644 index 0000000000000..abdb30dc9312b --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.stderr @@ -0,0 +1,39 @@ +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:14:1 + | +LL | fn baz(val: i32) {} + | ^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:22:1 + | +LL | fn type_generic() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:25:1 + | +LL | fn const_generic() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:30:5 + | +LL | fn foo(arg: ()) {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `i32: Termination` is not satisfied + --> $DIR/test-function-signature.rs:9:13 + | +LL | #[test] + | ------- in this procedural macro expansion +LL | fn bar() -> i32 { + | ^^^ the trait `Termination` is not implemented for `i32` + | +note: required by a bound in `assert_test_result` + --> $SRC_DIR/test/src/lib.rs:LL:COL + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`.