Skip to content

Commit d40c827

Browse files
authored
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.
2 parents 559b2ea + 9e70541 commit d40c827

File tree

6 files changed

+97
-54
lines changed

6 files changed

+97
-54
lines changed

compiler/rustc_builtin_macros/src/test.rs

+40-22
Original file line numberDiff line numberDiff line change
@@ -118,34 +118,22 @@ pub fn expand_test_or_bench(
118118
}
119119
}
120120
other => {
121-
cx.struct_span_err(
122-
other.span(),
123-
"`#[test]` attribute is only allowed on non associated functions",
124-
)
125-
.emit();
121+
not_testable_error(cx, attr_sp, None);
126122
return vec![other];
127123
}
128124
};
129125

130-
// Note: non-associated fn items are already handled by `expand_test_or_bench`
131126
let ast::ItemKind::Fn(fn_) = &item.kind else {
132-
let diag = &cx.sess.parse_sess.span_diagnostic;
133-
let msg = "the `#[test]` attribute may only be used on a non-associated function";
134-
let mut err = match item.kind {
135-
// These were a warning before #92959 and need to continue being that to avoid breaking
136-
// stable user code (#94508).
137-
ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
138-
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
139-
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
140-
// reworked in the future to not need it, it'd be nice.
141-
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
127+
not_testable_error(cx, attr_sp, Some(&item));
128+
return if is_stmt {
129+
vec![Annotatable::Stmt(P(ast::Stmt {
130+
id: ast::DUMMY_NODE_ID,
131+
span: item.span,
132+
kind: ast::StmtKind::Item(item),
133+
}))]
134+
} else {
135+
vec![Annotatable::Item(item)]
142136
};
143-
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
144-
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
145-
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
146-
.emit();
147-
148-
return vec![Annotatable::Item(item)];
149137
};
150138

151139
// has_*_signature will report any errors in the type so compilation
@@ -398,6 +386,36 @@ pub fn expand_test_or_bench(
398386
}
399387
}
400388

389+
fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
390+
let diag = &cx.sess.parse_sess.span_diagnostic;
391+
let msg = "the `#[test]` attribute may only be used on a non-associated function";
392+
let mut err = match item.map(|i| &i.kind) {
393+
// These were a warning before #92959 and need to continue being that to avoid breaking
394+
// stable user code (#94508).
395+
Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg),
396+
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
397+
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
398+
// reworked in the future to not need it, it'd be nice.
399+
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
400+
};
401+
if let Some(item) = item {
402+
err.span_label(
403+
item.span,
404+
format!(
405+
"expected a non-associated function, found {} {}",
406+
item.kind.article(),
407+
item.kind.descr()
408+
),
409+
);
410+
}
411+
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
412+
.span_suggestion(attr_sp,
413+
"replace with conditional compilation to make the item only exist when tests are being run",
414+
"#[cfg(test)]",
415+
Applicability::MaybeIncorrect)
416+
.emit();
417+
}
418+
401419
fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
402420
let span = item.ident.span;
403421
let (source_file, lo_line, lo_col, hi_line, hi_col) =

tests/ui/test-attrs/issue-109816.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// compile-flags: --test
2+
3+
fn align_offset_weird_strides() {
4+
#[test]
5+
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
6+
struct A5(u32, u8);
7+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: the `#[test]` attribute may only be used on a non-associated function
2+
--> $DIR/issue-109816.rs:4:5
3+
|
4+
LL | #[test]
5+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
6+
LL |
7+
LL | struct A5(u32, u8);
8+
| ------------------- expected a non-associated function, found a struct
9+
|
10+
help: replace with conditional compilation to make the item only exist when tests are being run
11+
|
12+
LL | #[cfg(test)]
13+
|
14+
15+
error: aborting due to previous error
16+

tests/ui/test-attrs/test-attr-non-associated-functions.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
// #[test] attribute is not allowed on associated functions or methods
2-
// reworded error message
31
// compile-flags:--test
42

53
struct A {}
64

75
impl A {
86
#[test]
7+
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
98
fn new() -> A {
10-
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
119
A {}
1210
}
1311
#[test]
12+
//~^ ERROR the `#[test]` attribute may only be used on a non-associated function
1413
fn recovery_witness() -> A {
15-
//~^ ERROR `#[test]` attribute is only allowed on non associated functions
1614
A {}
1715
}
1816
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1-
error: `#[test]` attribute is only allowed on non associated functions
2-
--> $DIR/test-attr-non-associated-functions.rs:9:5
3-
|
4-
LL | / fn new() -> A {
5-
LL | |
6-
LL | | A {}
7-
LL | | }
8-
| |_____^
1+
error: the `#[test]` attribute may only be used on a non-associated function
2+
--> $DIR/test-attr-non-associated-functions.rs:6:5
3+
|
4+
LL | #[test]
5+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
6+
|
7+
help: replace with conditional compilation to make the item only exist when tests are being run
8+
|
9+
LL | #[cfg(test)]
10+
|
911

10-
error: `#[test]` attribute is only allowed on non associated functions
11-
--> $DIR/test-attr-non-associated-functions.rs:14:5
12-
|
13-
LL | / fn recovery_witness() -> A {
14-
LL | |
15-
LL | | A {}
16-
LL | | }
17-
| |_____^
12+
error: the `#[test]` attribute may only be used on a non-associated function
13+
--> $DIR/test-attr-non-associated-functions.rs:11:5
14+
|
15+
LL | #[test]
16+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
17+
|
18+
help: replace with conditional compilation to make the item only exist when tests are being run
19+
|
20+
LL | #[cfg(test)]
21+
|
1822

1923
error: aborting due to 2 previous errors
2024

tests/ui/test-attrs/test-on-not-fn.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
22
--> $DIR/test-on-not-fn.rs:3:1
33
|
44
LL | #[test]
5-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
5+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
66
LL | mod test {}
77
| ----------- expected a non-associated function, found a module
88
|
@@ -15,7 +15,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
1515
--> $DIR/test-on-not-fn.rs:6:1
1616
|
1717
LL | #[test]
18-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
18+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
1919
LL | / mod loooooooooooooong_teeeeeeeeeest {
2020
LL | | /*
2121
LL | | this is a comment
@@ -34,7 +34,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
3434
--> $DIR/test-on-not-fn.rs:20:1
3535
|
3636
LL | #[test]
37-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
37+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
3838
LL | extern "C" {}
3939
| ------------- expected a non-associated function, found an extern block
4040
|
@@ -47,7 +47,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
4747
--> $DIR/test-on-not-fn.rs:23:1
4848
|
4949
LL | #[test]
50-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
50+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
5151
LL | trait Foo {}
5252
| ------------ expected a non-associated function, found a trait
5353
|
@@ -60,7 +60,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
6060
--> $DIR/test-on-not-fn.rs:26:1
6161
|
6262
LL | #[test]
63-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
63+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
6464
LL | impl Foo for i32 {}
6565
| ------------------- expected a non-associated function, found an implementation
6666
|
@@ -73,7 +73,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
7373
--> $DIR/test-on-not-fn.rs:29:1
7474
|
7575
LL | #[test]
76-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
76+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
7777
LL | const FOO: i32 = -1_i32;
7878
| ------------------------ expected a non-associated function, found a constant item
7979
|
@@ -86,7 +86,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
8686
--> $DIR/test-on-not-fn.rs:32:1
8787
|
8888
LL | #[test]
89-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
89+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
9090
LL | static BAR: u64 = 10_000_u64;
9191
| ----------------------------- expected a non-associated function, found a static item
9292
|
@@ -99,7 +99,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
9999
--> $DIR/test-on-not-fn.rs:35:1
100100
|
101101
LL | #[test]
102-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
102+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
103103
LL | / enum MyUnit {
104104
LL | | Unit,
105105
LL | | }
@@ -114,7 +114,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
114114
--> $DIR/test-on-not-fn.rs:40:1
115115
|
116116
LL | #[test]
117-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
117+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
118118
LL | struct NewI32(i32);
119119
| ------------------- expected a non-associated function, found a struct
120120
|
@@ -127,7 +127,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
127127
--> $DIR/test-on-not-fn.rs:43:1
128128
|
129129
LL | #[test]
130-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
130+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
131131
LL | / union Spooky {
132132
LL | | x: i32,
133133
LL | | y: u32,
@@ -143,7 +143,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
143143
--> $DIR/test-on-not-fn.rs:50:1
144144
|
145145
LL | #[test]
146-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
146+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
147147
LL | #[derive(Copy, Clone, Debug)]
148148
LL | / struct MoreAttrs {
149149
LL | | a: i32,
@@ -160,7 +160,7 @@ warning: the `#[test]` attribute may only be used on a non-associated function
160160
--> $DIR/test-on-not-fn.rs:61:1
161161
|
162162
LL | #[test]
163-
| ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions
163+
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions
164164
LL | foo!();
165165
| ------- expected a non-associated function, found an item macro invocation
166166
|

0 commit comments

Comments
 (0)