From 33b05c77aa3f04d477eda13dcb92b9983fd8ec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 26 Oct 2022 04:13:38 +0200 Subject: [PATCH] alt-fix-50291 --- compiler/rustc_builtin_macros/src/test.rs | 85 ++++++++++++------- library/test/src/lib.rs | 5 ++ .../termination-trait-test-wrong-type.rs | 4 +- .../termination-trait-test-wrong-type.stderr | 20 ++++- 4 files changed, 79 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 705141614e252..028727c171dbb 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -103,7 +103,7 @@ pub fn expand_test_or_bench( }; // Note: non-associated fn items are already handled by `expand_test_or_bench` - if !matches!(item.kind, ast::ItemKind::Fn(_)) { + let ast::ItemKind::Fn(fn_) = &item.kind else { 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 { @@ -121,7 +121,7 @@ pub fn expand_test_or_bench( .emit(); 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 @@ -132,7 +132,9 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp)); + let sp = cx.with_def_site_ctxt(item.span); + let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span()); + let attr_sp = cx.with_def_site_ctxt(attr_sp); let test_id = Ident::new(sym::test, attr_sp); @@ -166,51 +168,68 @@ pub fn expand_test_or_bench( // creates $name: $expr let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr); + let test_fn_body = |expr| match &fn_.sig.decl.output { + ast::FnRetTy::Ty(ty) => cx.expr_block(cx.block( + sp, + vec![ + cx.stmt_let_type_only( + sp, + cx.ty_path(cx.path_all( + ret_ty_sp, + false, + vec![test_id, Ident::from_str_and_span("AssertIsTermination", sp)], + vec![ast::GenericArg::Type(ty.clone())], + )), + ), + cx.stmt_expr(expr), + ], + )), + ast::FnRetTy::Default(_) => expr, + }; + let test_fn = if is_bench { // A simple ident for a lambda let b = Ident::from_str_and_span("b", attr_sp); + // self::test::assert_test_result( + let assertion = 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)], + ), + ], + ); // ) + 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, - ), // ) + // |b| + cx.lambda1(sp, test_fn_body(assertion), b), ], ) } else { + // test::assert_test_result( + let assertion = 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![]), + ], + ); // ) + 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![]), // ) - ], - ), // } - ), // ) + // || + cx.lambda0(sp, test_fn_body(assertion)), ], ) }; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index b1e0bbfc591c1..7439dc547ae61 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -178,6 +178,11 @@ fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { } } +/// Assert that the given type implements [`Termination`]. +/// +/// Generated by `#[test]` and `#[bench]` to make the compiler emit a good error message. +pub struct AssertIsTermination(std::marker::PhantomData); + /// Invoked when unit tests terminate. Returns `Result::Err` if the test is /// considered a failure. By default, invokes `report() and checks for a `0` /// result. diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs index 193a523aed24b..8fc5e9cf56b72 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs @@ -3,6 +3,8 @@ use std::num::ParseFloatError; #[test] -fn can_parse_zero_as_f32() -> Result { //~ ERROR +fn can_parse_zero_as_f32() -> Result { + //~^ ERROR the trait bound `f32: Termination` is not satisfied + //~| ERROR the trait bound `f32: Termination` is not satisfied "0".parse() } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index 6ee32314607ad..abf240e066ee5 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,9 +1,27 @@ +error[E0277]: the trait bound `f32: Termination` is not satisfied + --> $DIR/termination-trait-test-wrong-type.rs:6:31 + | +LL | #[test] + | ------- in this procedural macro expansion +LL | fn can_parse_zero_as_f32() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` + | + = note: required for `Result` to implement `Termination` +note: required by a bound in `AssertIsTermination` + --> $SRC_DIR/test/src/lib.rs:LL:COL + | +LL | pub struct AssertIsTermination(std::marker::PhantomData); + | ^^^^^^^^^^^ required by this bound in `AssertIsTermination` + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `f32: Termination` is not satisfied --> $DIR/termination-trait-test-wrong-type.rs:6:1 | LL | #[test] | ------- in this procedural macro expansion LL | / fn can_parse_zero_as_f32() -> Result { +LL | | +LL | | LL | | "0".parse() LL | | } | |_^ the trait `Termination` is not implemented for `f32` @@ -16,6 +34,6 @@ LL | pub fn assert_test_result(result: T) -> Result<(), String> | ^^^^^^^^^^^ required by this bound in `assert_test_result` = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`.