Skip to content

Identify non-function annotated by contract in macro expand #138852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions compiler/rustc_builtin_macros/src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,31 @@ fn expand_contract_clause(
if let TokenTree::Token(token, _) = tt { token.is_ident_named(sym) } else { false }
};

let is_top_level_kw = |tt: &TokenTree| {
if let TokenTree::Token(token, _) = tt {
if token.is_ident_named(kw::Fn)
|| token.is_ident_named(kw::Struct)
|| token.is_ident_named(kw::Enum)
|| token.is_ident_named(kw::Trait)
|| token.is_ident_named(kw::Impl)
|| token.is_ident_named(kw::Static)
|| token.is_ident_named(kw::Const)
|| token.is_ident_named(kw::Type)
|| token.is_ident_named(kw::Mod)
{
return true;
}
}
false
};

// Find the `fn` keyword to check if this is a function.
if cursor
.find(|tt| {
new_tts.push_tree((*tt).clone());
is_kw(tt, kw::Fn)
})
.is_none()
{
// If some other top-level keyword is found before the `fn` keyword, we emit an error.
let found_kw = cursor.find(|tt| {
new_tts.push_tree((*tt).clone());
is_top_level_kw(tt)
});
if found_kw.is_none() || !is_kw(found_kw.unwrap(), kw::Fn) {
return Err(ecx
.sess
.dcx()
Expand Down
21 changes: 18 additions & 3 deletions tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ struct Dummy(usize);
//~^ ERROR contract annotations can only be used on functions
const MAX_VAL: usize = 100;

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

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

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

#[core::contracts::ensures]
//~^ ERROR contract annotations can only be used on functions
mod InvalidModule {}

#[core::contracts::ensures]
//~^ ERROR contract annotations can only be used on functions
static INVALID_STATIC: usize = 0;

#[core::contracts::ensures]
//~^ ERROR contract annotations can only be used on functions
struct InvalidStruct {}

#[core::contracts::ensures]
//~^ ERROR expected a `Fn(&'a _)` closure, found `()` [E0277]
fn function() {}

fn main() {
}
45 changes: 37 additions & 8 deletions tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,54 @@ error: contract annotations can only be used on functions
LL | #[core::contracts::ensures(|v| v == 100)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

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

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

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

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

error: contract annotations can only be used on functions
--> $DIR/disallow-contract-annotation-on-non-fn.rs:51:1
|
LL | #[core::contracts::ensures]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: contract annotations can only be used on functions
--> $DIR/disallow-contract-annotation-on-non-fn.rs:55:1
|
LL | #[core::contracts::ensures]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: contract annotations can only be used on functions
--> $DIR/disallow-contract-annotation-on-non-fn.rs:59:1
|
LL | #[core::contracts::ensures]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/disallow-contract-annotation-on-non-fn.rs:3:12
|
Expand All @@ -49,5 +67,16 @@ LL | #![feature(contracts)]
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= note: `#[warn(incomplete_features)]` on by default

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

error: aborting due to 11 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(contracts)]
//~^ WARNING the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
//~| ERROR `main` function not found in crate `attribute_affected_trait_bound_issue_137129` [E0601]
#![core::contracts::ensures]
//~^ ERROR inner macro attributes are unstable [E0658]
//~| ERROR contract annotations can only be used on functions
struct A {
b: dyn A + 'static,
}
fn f1() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
error[E0658]: inner macro attributes are unstable
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:4:4
|
LL | #![core::contracts::ensures]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: contract annotations can only be used on functions
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:4:1
|
LL | #![core::contracts::ensures]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/attribute-affected-trait-bound-issue-137129.rs:1:12
|
LL | #![feature(contracts)]
| ^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
= note: `#[warn(incomplete_features)]` on by default

error: `#[panic_handler]` function required, but not found

error: unwinding panics are not supported without std
|
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
= 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

error[E0601]: `main` function not found in crate `attribute_affected_trait_bound_issue_137129`

error: aborting due to 5 previous errors; 1 warning emitted

Some errors have detailed explanations: E0601, E0658.
For more information about an error, try `rustc --explain E0601`.
Loading