Rollup merge of #110035 - Ezrashaw:improve-test-attr-expansion-code, r=davidtwco
fix: ensure bad `#[test]` invocs retain correct AST Fixes #109816 Ensures that a `StmtKind::Item` doesn't get converted into a plain `Item` (causing the ICE from the linked issue) Also unifies the error path a bit.
This commit is contained in:
commit
d40c827e9a
@ -118,34 +118,22 @@ pub fn expand_test_or_bench(
|
||||
}
|
||||
}
|
||||
other => {
|
||||
cx.struct_span_err(
|
||||
other.span(),
|
||||
"`#[test]` attribute is only allowed on non associated functions",
|
||||
)
|
||||
.emit();
|
||||
not_testable_error(cx, attr_sp, None);
|
||||
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 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(),
|
||||
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),
|
||||
}))]
|
||||
} else {
|
||||
vec![Annotatable::Item(item)]
|
||||
};
|
||||
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
|
||||
@ -398,6 +386,36 @@ pub fn expand_test_or_bench(
|
||||
}
|
||||
}
|
||||
|
||||
fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, 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();
|
||||
}
|
||||
|
||||
fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
|
||||
let span = item.ident.span;
|
||||
let (source_file, lo_line, lo_col, hi_line, hi_col) =
|
||||
|
7
tests/ui/test-attrs/issue-109816.rs
Normal file
7
tests/ui/test-attrs/issue-109816.rs
Normal 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);
|
||||
}
|
16
tests/ui/test-attrs/issue-109816.stderr
Normal file
16
tests/ui/test-attrs/issue-109816.stderr
Normal 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
|
||||
|
@ -1,18 +1,16 @@
|
||||
// #[test] attribute is not allowed on associated functions or methods
|
||||
// reworded error message
|
||||
// compile-flags:--test
|
||||
|
||||
struct A {}
|
||||
|
||||
impl A {
|
||||
#[test]
|
||||
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
|
||||
fn new() -> A {
|
||||
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
|
||||
A {}
|
||||
}
|
||||
#[test]
|
||||
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
|
||||
fn recovery_witness() -> A {
|
||||
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
|
||||
A {}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,24 @@
|
||||
error: `#[test]` attribute is only allowed on non associated functions
|
||||
--> $DIR/test-attr-non-associated-functions.rs:9:5
|
||||
error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $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
|
||||
--> $DIR/test-attr-non-associated-functions.rs:14:5
|
||||
error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $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
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
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 {}
|
||||
| ----------- 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
|
||||
|
|
||||
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 | | /*
|
||||
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
|
||||
|
|
||||
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" {}
|
||||
| ------------- 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
|
||||
|
|
||||
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 {}
|
||||
| ------------ 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
|
||||
|
|
||||
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 {}
|
||||
| ------------------- 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
|
||||
|
|
||||
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;
|
||||
| ------------------------ 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
|
||||
|
|
||||
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;
|
||||
| ----------------------------- 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
|
||||
|
|
||||
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 | | Unit,
|
||||
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
|
||||
|
|
||||
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);
|
||||
| ------------------- 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
|
||||
|
|
||||
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 | | x: i32,
|
||||
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
|
||||
|
|
||||
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 | / struct MoreAttrs {
|
||||
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
|
||||
|
|
||||
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!();
|
||||
| ------- expected a non-associated function, found an item macro invocation
|
||||
|
|
||||
|
Loading…
x
Reference in New Issue
Block a user