Skip to content

Commit 33eb2d7

Browse files
committed
start with properly testing attribute positions
1 parent dbab4e1 commit 33eb2d7

File tree

9 files changed

+2193
-0
lines changed

9 files changed

+2193
-0
lines changed
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
It's not uncommon to see comments like these when reading attribute related code:
2+
3+
```rust
4+
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
5+
// `#[no_mangle]` attribute with just a lint, because we previously
6+
// erroneously allowed it and some crates used it accidentally, to be compatible
7+
// with crates depending on them, we can't throw an error here.
8+
```
9+
10+
or:
11+
12+
```rust
13+
// FIXME: This can be used on stable but shouldn't.
14+
```
15+
16+
Or perhaps you've seen discussions getting derailed by comments like:
17+
18+
```text
19+
I discovered today that the following code already compiles on stable since at least Rust 1.31
20+
...
21+
```
22+
23+
This is largely because our coverage of attributes and where they're allowed is very poor.
24+
This test suite attempts to consistently and exhaustively check attributes in various positions.
25+
Hopefully, improving test coverage leads to the following:
26+
- We become aware of the weird edge cases that are already allowed.
27+
- We avoid unknowingly breaking those things.
28+
- We can avoid accidentally stabilizing things we don't want stabilized.
29+
30+
If you know an attribute or a position that isn't tested but should be, please file an issue or PR.
31+
32+
## Template
33+
34+
`ATTRIBUTE.rs`
35+
```rust
36+
//@aux-build:dummy.rs
37+
38+
#![forbid(unstable_features)]
39+
#![warn(unused_attributes)]
40+
41+
#![ATTRIBUTE] //~ WARN
42+
43+
#[ATTRIBUTE] //~ WARN
44+
extern crate dummy;
45+
46+
extern crate core;
47+
48+
#[ATTRIBUTE] //~ WARN
49+
pub mod empty_crate;
50+
51+
#[ATTRIBUTE] //~ WARN
52+
pub mod module {
53+
#![ATTRIBUTE] //~ WARN
54+
//~^ WARN unused attribute
55+
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
56+
57+
#[ATTRIBUTE] //~ WARN
58+
pub static GLOBAL: u32 = 42;
59+
60+
#[ATTRIBUTE] //~ WARN
61+
pub static mut GLOBAL_MUT: u32 = 42;
62+
63+
#[ATTRIBUTE] //~ WARN
64+
pub const CONST: u32 = 42;
65+
66+
#[ATTRIBUTE] //~ WARN
67+
use ::core::fmt::Debug;
68+
69+
#[ATTRIBUTE] //~ WARN
70+
trait TraitAlias = Debug; //~ ERROR trait aliases are experimental
71+
72+
#[ATTRIBUTE] //~ WARN
73+
pub type TypeAlias = u32;
74+
75+
#[ATTRIBUTE] //~ WARN
76+
pub struct Struct<
77+
#[ATTRIBUTE] 'lt, //~ WARN
78+
#[ATTRIBUTE] T> //~ WARN
79+
{
80+
#[ATTRIBUTE] //~ WARN
81+
pub struct_field: u32,
82+
#[ATTRIBUTE] //~ WARN
83+
pub generic_field: &'lt T,
84+
}
85+
86+
#[ATTRIBUTE] //~ WARN
87+
pub struct TupleStruct(#[ATTRIBUTE] pub u32); //~ WARN
88+
89+
#[ATTRIBUTE] //~ WARN
90+
pub enum Enum {
91+
#[ATTRIBUTE] //~ WARN
92+
FieldVariant {
93+
#[ATTRIBUTE] //~ WARN
94+
field: u32,
95+
},
96+
#[ATTRIBUTE] //~ WARN
97+
TupleVariant(#[ATTRIBUTE] u32), //~ WARN
98+
}
99+
#[ATTRIBUTE] //~ WARN
100+
pub union Union {
101+
#[ATTRIBUTE] //~ WARN
102+
pub field: u32,
103+
}
104+
105+
#[ATTRIBUTE] //~ WARN
106+
impl<'lt, T> Struct<'lt, T> {
107+
#![ATTRIBUTE] //~ WARN
108+
//~^ WARN unused attribute
109+
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
110+
111+
#[ATTRIBUTE] //~ WARN
112+
pub fn method(#[ATTRIBUTE] &mut self) { //~ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
113+
//~^ WARN
114+
#[ATTRIBUTE] //~ ERROR
115+
//~^ WARN
116+
self.struct_field = struct_field;
117+
}
118+
119+
#[ATTRIBUTE] //~ WARN
120+
pub fn static_method(#[ATTRIBUTE] _arg: u32) {} //~ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
121+
}
122+
123+
#[ATTRIBUTE]
124+
impl<
125+
#[ATTRIBUTE] 'lt, //~ WARN
126+
#[ATTRIBUTE] T //~ WARN
127+
> Drop for Struct<'lt, T> {
128+
#[ATTRIBUTE] //~ WARN
129+
fn drop(&mut self) {
130+
// ..
131+
}
132+
}
133+
134+
#[ATTRIBUTE] //~ WARN
135+
pub fn function<
136+
#[ATTRIBUTE] const N: usize //~ WARN
137+
>(arg: u32) -> u32 {
138+
#![ATTRIBUTE] //~ WARN
139+
//~^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
140+
141+
arg
142+
}
143+
144+
#[ATTRIBUTE] //~ WARN
145+
pub trait Trait {
146+
#[ATTRIBUTE] //~ WARN
147+
fn trait_method() {}
148+
}
149+
}
150+
151+
#[ATTRIBUTE] //~ WARN
152+
fn main() {
153+
let _closure = #[ATTRIBUTE] //~ ERROR attributes on expressions are experimental
154+
//~^ WARN
155+
| _arg: u32| {};
156+
157+
let _move_closure = #[ATTRIBUTE] //~ ERROR attributes on expressions are experimental
158+
//~^ WARN
159+
move | _arg: u32| {};
160+
161+
#[ATTRIBUTE] //~ WARN
162+
{
163+
#![ATTRIBUTE] //~ WARN
164+
//~^ WARN unused attribute
165+
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
166+
167+
#[ATTRIBUTE] //~ WARN
168+
let variable = 42_u32;
169+
170+
let _array = #[ATTRIBUTE] //~ ERROR attributes on expressions are experimental
171+
//~^ WARN
172+
[
173+
#[ATTRIBUTE] //~ WARN
174+
1,
175+
2,
176+
];
177+
let _tuple = #[ATTRIBUTE] //~ ERROR attributes on expressions are experimental
178+
//~^ WARN
179+
(
180+
#[ATTRIBUTE] //~ WARN
181+
1,
182+
2,
183+
);
184+
let _tuple_struct = module::TupleStruct(
185+
#[ATTRIBUTE] //~ WARN
186+
2,
187+
);
188+
let _struct = module::Struct {
189+
#[ATTRIBUTE] //~ WARN
190+
struct_field: 42,
191+
generic_field: &13,
192+
};
193+
194+
let _union = module::Union {
195+
#[ATTRIBUTE] //~ WARN
196+
field: 42,
197+
};
198+
199+
let _fn_call = module::function::<7>(
200+
#[ATTRIBUTE] //~ WARN
201+
42,
202+
);
203+
204+
#[ATTRIBUTE] //~ WARN
205+
match variable {
206+
#[ATTRIBUTE] //~ WARN
207+
_match_arm => {}
208+
}
209+
210+
let tail = ();
211+
212+
#[ATTRIBUTE] //~ WARN
213+
tail
214+
}
215+
216+
{
217+
fn f(_: impl Fn()) {}
218+
// Is this attribute argument-level or expression-level?
219+
f(
220+
#[ATTRIBUTE] //~ WARN
221+
|| {},
222+
);
223+
}
224+
225+
#[ATTRIBUTE] //~ WARN
226+
unsafe {
227+
let _x = [1, 2, 3].get_unchecked(1);
228+
}
229+
}
230+
231+
#[ATTRIBUTE] //~ WARN
232+
unsafe extern "C" {
233+
#![ATTRIBUTE] //~ WARN
234+
//~^ WARN unused attribute
235+
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
236+
237+
#[ATTRIBUTE] //~ WARN
238+
pub fn external_function(
239+
arg: *mut u8,
240+
...
241+
);
242+
243+
#[ATTRIBUTE] //~ WARN
244+
pub static EXTERNAL_STATIC: *const u32;
245+
246+
#[ATTRIBUTE] //~ WARN
247+
pub static mut EXTERNAL_STATIC_MUT: *mut u32;
248+
}
249+
250+
#[ATTRIBUTE] //~ WARN
251+
pub unsafe extern "C" fn abi_function(_: u32) {}
252+
253+
#[ATTRIBUTE] //~ WARN
254+
#[macro_export]
255+
macro_rules! my_macro {
256+
() => {};
257+
}
258+
259+
#[ATTRIBUTE] //~ WARN
260+
#[test]
261+
fn test_fn() {}
262+
```

0 commit comments

Comments
 (0)