1
Fork 0

fix: ensure bad #[test] invocs retain correct AST

This commit is contained in:
Ezra Shaw 2023-04-07 14:32:55 +12:00
parent c934ce9e0a
commit f4e7a99662
No known key found for this signature in database
GPG key ID: 67ABF16FB0ECD870
6 changed files with 95 additions and 52 deletions

View file

@ -107,6 +107,36 @@ pub fn expand_test_or_bench(
return vec![]; return vec![];
} }
let not_testable_error = |item: Option<&ast::Item>| {
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.map(|i| &i.kind) {
// These were a warning before #92959 and need to continue being that to avoid breaking
// stable user code (#94508).
Some(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(),
};
if let Some(item) = item {
err.span_label(
item.span,
format!(
"expected a non-associated function, found {} {}",
item.kind.article(),
item.kind.descr()
),
);
}
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
.span_suggestion(attr_sp,
"replace with conditional compilation to make the item only exist when tests are being run",
"#[cfg(test)]",
Applicability::MaybeIncorrect)
.emit();
};
let (item, is_stmt) = match item { let (item, is_stmt) = match item {
Annotatable::Item(i) => (i, false), Annotatable::Item(i) => (i, false),
Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
@ -118,34 +148,22 @@ pub fn expand_test_or_bench(
} }
} }
other => { other => {
cx.struct_span_err( not_testable_error(None);
other.span(),
"`#[test]` attribute is only allowed on non associated functions",
)
.emit();
return vec![other]; return vec![other];
} }
}; };
// Note: non-associated fn items are already handled by `expand_test_or_bench`
let ast::ItemKind::Fn(fn_) = &item.kind else { let ast::ItemKind::Fn(fn_) = &item.kind else {
let diag = &cx.sess.parse_sess.span_diagnostic; not_testable_error(Some(&item));
let msg = "the `#[test]` attribute may only be used on a non-associated function"; return if is_stmt {
let mut err = match item.kind { vec![Annotatable::Stmt(P(ast::Stmt {
// These were a warning before #92959 and need to continue being that to avoid breaking id: ast::DUMMY_NODE_ID,
// stable user code (#94508). span: item.span,
ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg), kind: ast::StmtKind::Item(item),
// `.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 } else {
// reworked in the future to not need it, it'd be nice. vec![Annotatable::Item(item)]
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
}; };
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
.emit();
return vec![Annotatable::Item(item)];
}; };
// has_*_signature will report any errors in the type so compilation // has_*_signature will report any errors in the type so compilation

View file

@ -0,0 +1,7 @@
// compile-flags: --test
fn align_offset_weird_strides() {
#[test]
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
struct A5(u32, u8);
}

View file

@ -0,0 +1,16 @@
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/issue-109816.rs:4:5
|
LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL |
LL | struct A5(u32, u8);
| ------------------- expected a non-associated function, found a struct
|
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
|
error: aborting due to previous error

View file

@ -1,18 +1,16 @@
// #[test] attribute is not allowed on associated functions or methods
// reworded error message
// compile-flags:--test // compile-flags:--test
struct A {} struct A {}
impl A { impl A {
#[test] #[test]
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
fn new() -> A { fn new() -> A {
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
A {} A {}
} }
#[test] #[test]
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
fn recovery_witness() -> A { fn recovery_witness() -> A {
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
A {} A {}
} }
} }

View file

@ -1,20 +1,24 @@
error: `#[test]` attribute is only allowed on non associated functions error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-attr-non-associated-functions.rs:9:5 --> $DIR/test-attr-non-associated-functions.rs:6:5
|
LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
|
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| |
LL | / fn new() -> A {
LL | |
LL | | A {}
LL | | }
| |_____^
error: `#[test]` attribute is only allowed on non associated functions error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-attr-non-associated-functions.rs:14:5 --> $DIR/test-attr-non-associated-functions.rs:11:5
|
LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
|
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| |
LL | / fn recovery_witness() -> A {
LL | |
LL | | A {}
LL | | }
| |_____^
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -2,7 +2,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:3:1 --> $DIR/test-on-not-fn.rs:3:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | mod test {} LL | mod test {}
| ----------- expected a non-associated function, found a module | ----------- expected a non-associated function, found a module
| |
@ -15,7 +15,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:6:1 --> $DIR/test-on-not-fn.rs:6:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | / mod loooooooooooooong_teeeeeeeeeest { LL | / mod loooooooooooooong_teeeeeeeeeest {
LL | | /* LL | | /*
LL | | this is a comment LL | | this is a comment
@ -34,7 +34,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:20:1 --> $DIR/test-on-not-fn.rs:20:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | extern "C" {} LL | extern "C" {}
| ------------- expected a non-associated function, found an extern block | ------------- expected a non-associated function, found an extern block
| |
@ -47,7 +47,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:23:1 --> $DIR/test-on-not-fn.rs:23:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | trait Foo {} LL | trait Foo {}
| ------------ expected a non-associated function, found a trait | ------------ expected a non-associated function, found a trait
| |
@ -60,7 +60,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:26:1 --> $DIR/test-on-not-fn.rs:26:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | impl Foo for i32 {} LL | impl Foo for i32 {}
| ------------------- expected a non-associated function, found an implementation | ------------------- expected a non-associated function, found an implementation
| |
@ -73,7 +73,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:29:1 --> $DIR/test-on-not-fn.rs:29:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | const FOO: i32 = -1_i32; LL | const FOO: i32 = -1_i32;
| ------------------------ expected a non-associated function, found a constant item | ------------------------ expected a non-associated function, found a constant item
| |
@ -86,7 +86,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:32:1 --> $DIR/test-on-not-fn.rs:32:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | static BAR: u64 = 10_000_u64; LL | static BAR: u64 = 10_000_u64;
| ----------------------------- expected a non-associated function, found a static item | ----------------------------- expected a non-associated function, found a static item
| |
@ -99,7 +99,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:35:1 --> $DIR/test-on-not-fn.rs:35:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | / enum MyUnit { LL | / enum MyUnit {
LL | | Unit, LL | | Unit,
LL | | } LL | | }
@ -114,7 +114,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:40:1 --> $DIR/test-on-not-fn.rs:40:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | struct NewI32(i32); LL | struct NewI32(i32);
| ------------------- expected a non-associated function, found a struct | ------------------- expected a non-associated function, found a struct
| |
@ -127,7 +127,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:43:1 --> $DIR/test-on-not-fn.rs:43:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | / union Spooky { LL | / union Spooky {
LL | | x: i32, LL | | x: i32,
LL | | y: u32, LL | | y: u32,
@ -143,7 +143,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:50:1 --> $DIR/test-on-not-fn.rs:50:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | #[derive(Copy, Clone, Debug)] LL | #[derive(Copy, Clone, Debug)]
LL | / struct MoreAttrs { LL | / struct MoreAttrs {
LL | | a: i32, LL | | a: i32,
@ -160,7 +160,7 @@ warning: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:61:1 --> $DIR/test-on-not-fn.rs:61:1
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
LL | foo!(); LL | foo!();
| ------- expected a non-associated function, found an item macro invocation | ------- expected a non-associated function, found an item macro invocation
| |