Skip to content

Commit aef7aa8

Browse files
committed
Identify non-function annotated by contract in macro expand
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent ae8ab87 commit aef7aa8

File tree

5 files changed

+127
-18
lines changed

5 files changed

+127
-18
lines changed

compiler/rustc_builtin_macros/src/contracts.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,31 @@ fn expand_contract_clause(
5757
if let TokenTree::Token(token, _) = tt { token.is_ident_named(sym) } else { false }
5858
};
5959

60+
let is_top_level_kw = |tt: &TokenTree| {
61+
if let TokenTree::Token(token, _) = tt {
62+
if token.is_ident_named(kw::Fn)
63+
|| token.is_ident_named(kw::Struct)
64+
|| token.is_ident_named(kw::Enum)
65+
|| token.is_ident_named(kw::Trait)
66+
|| token.is_ident_named(kw::Impl)
67+
|| token.is_ident_named(kw::Static)
68+
|| token.is_ident_named(kw::Const)
69+
|| token.is_ident_named(kw::Type)
70+
|| token.is_ident_named(kw::Mod)
71+
{
72+
return true;
73+
}
74+
}
75+
false
76+
};
77+
6078
// Find the `fn` keyword to check if this is a function.
61-
if cursor
62-
.find(|tt| {
63-
new_tts.push_tree((*tt).clone());
64-
is_kw(tt, kw::Fn)
65-
})
66-
.is_none()
67-
{
79+
// If some other top-level keyword is found before the `fn` keyword, we emit an error.
80+
let found_kw = cursor.find(|tt| {
81+
new_tts.push_tree((*tt).clone());
82+
is_top_level_kw(tt)
83+
});
84+
if found_kw.is_none() || !is_kw(found_kw.unwrap(), kw::Fn) {
6885
return Err(ecx
6986
.sess
7087
.dcx()

tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ struct Dummy(usize);
1212
//~^ ERROR contract annotations can only be used on functions
1313
const MAX_VAL: usize = 100;
1414

15-
// FIXME: Improve the error message here. The macro thinks this is a function.
1615
#[core::contracts::ensures(|v| v == 100)]
17-
//~^ ERROR contract annotations is only supported in functions with bodies
16+
//~^ ERROR contract annotations can only be used on functions
1817
type NewDummy = fn(usize) -> Dummy;
1918

2019
#[core::contracts::ensures(|v| v == 100)]
21-
//~^ ERROR contract annotations is only supported in functions with bodies
20+
//~^ ERROR contract annotations can only be used on functions
2221
const NEW_DUMMY_FN : fn(usize) -> Dummy = || { Dummy(0) };
2322

2423
#[core::contracts::requires(true)]
@@ -49,5 +48,21 @@ pub trait DummyBuilder {
4948
fn build() -> Dummy;
5049
}
5150

51+
#[core::contracts::ensures]
52+
//~^ ERROR contract annotations can only be used on functions
53+
mod InvalidModule {}
54+
55+
#[core::contracts::ensures]
56+
//~^ ERROR contract annotations can only be used on functions
57+
static INVALID_STATIC: usize = 0;
58+
59+
#[core::contracts::ensures]
60+
//~^ ERROR contract annotations can only be used on functions
61+
struct InvalidStruct {}
62+
63+
#[core::contracts::ensures]
64+
//~^ ERROR expected a `Fn(&'a _)` closure, found `()` [E0277]
65+
fn function() {}
66+
5267
fn main() {
5368
}

tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,54 @@ error: contract annotations can only be used on functions
1010
LL | #[core::contracts::ensures(|v| v == 100)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: contract annotations is only supported in functions with bodies
14-
--> $DIR/disallow-contract-annotation-on-non-fn.rs:16:1
13+
error: contract annotations can only be used on functions
14+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:15:1
1515
|
1616
LL | #[core::contracts::ensures(|v| v == 100)]
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818

19-
error: contract annotations is only supported in functions with bodies
20-
--> $DIR/disallow-contract-annotation-on-non-fn.rs:20:1
19+
error: contract annotations can only be used on functions
20+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:19:1
2121
|
2222
LL | #[core::contracts::ensures(|v| v == 100)]
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2424

2525
error: contract annotations can only be used on functions
26-
--> $DIR/disallow-contract-annotation-on-non-fn.rs:24:1
26+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:23:1
2727
|
2828
LL | #[core::contracts::requires(true)]
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3030

3131
error: contract annotations can only be used on functions
32-
--> $DIR/disallow-contract-annotation-on-non-fn.rs:35:1
32+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:34:1
3333
|
3434
LL | #[core::contracts::ensures(|dummy| dummy.0 > 0)]
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3636

3737
error: contract annotations can only be used on functions
38-
--> $DIR/disallow-contract-annotation-on-non-fn.rs:46:1
38+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:45:1
3939
|
4040
LL | #[core::contracts::requires(true)]
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4242

43+
error: contract annotations can only be used on functions
44+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:51:1
45+
|
46+
LL | #[core::contracts::ensures]
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
error: contract annotations can only be used on functions
50+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:55:1
51+
|
52+
LL | #[core::contracts::ensures]
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
54+
55+
error: contract annotations can only be used on functions
56+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:59:1
57+
|
58+
LL | #[core::contracts::ensures]
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
60+
4361
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
4462
--> $DIR/disallow-contract-annotation-on-non-fn.rs:3:12
4563
|
@@ -49,5 +67,16 @@ LL | #![feature(contracts)]
4967
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
5068
= note: `#[warn(incomplete_features)]` on by default
5169

52-
error: aborting due to 7 previous errors; 1 warning emitted
70+
error[E0277]: expected a `Fn(&'a _)` closure, found `()`
71+
--> $DIR/disallow-contract-annotation-on-non-fn.rs:63:1
72+
|
73+
LL | #[core::contracts::ensures]
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn(&'a _)` closure, found `()`
75+
|
76+
= help: the trait `for<'a> Fn(&'a _)` is not implemented for `()`
77+
note: required by a bound in `build_check_ensures`
78+
--> $SRC_DIR/core/src/contracts.rs:LL:COL
79+
80+
error: aborting due to 11 previous errors; 1 warning emitted
5381

82+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(contracts)]
2+
//~^ WARNING the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
3+
//~| ERROR `main` function not found in crate `attribute_affected_trait_bound_issue_137129` [E0601]
4+
#![core::contracts::ensures]
5+
//~^ ERROR inner macro attributes are unstable [E0658]
6+
//~| ERROR contract annotations can only be used on functions
7+
struct A {
8+
b: dyn A + 'static,
9+
}
10+
fn f1() {}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error[E0658]: inner macro attributes are unstable
2+
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:4:4
3+
|
4+
LL | #![core::contracts::ensures]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
8+
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: contract annotations can only be used on functions
12+
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:4:1
13+
|
14+
LL | #![core::contracts::ensures]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
18+
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:1:12
19+
|
20+
LL | #![feature(contracts)]
21+
| ^^^^^^^^^
22+
|
23+
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
24+
= note: `#[warn(incomplete_features)]` on by default
25+
26+
error: `#[panic_handler]` function required, but not found
27+
28+
error: unwinding panics are not supported without std
29+
|
30+
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
31+
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
32+
33+
error[E0601]: `main` function not found in crate `attribute_affected_trait_bound_issue_137129`
34+
35+
error: aborting due to 5 previous errors; 1 warning emitted
36+
37+
Some errors have detailed explanations: E0601, E0658.
38+
For more information about an error, try `rustc --explain E0601`.

0 commit comments

Comments
 (0)