diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index e47c1b1363df0..20001400857a6 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -137,6 +137,21 @@ fn expand_contract_clause_tts( annotated: TokenStream, clause_keyword: rustc_span::Symbol, ) -> Result { + if annotation.is_empty() { + let (name, example) = if clause_keyword == kw::ContractRequires { + ("requires", "condition") + } else { + ("ensures", "|result: &T| condition") + }; + ecx.sess.dcx().span_err( + attr_span, + format!("`{name}` attribute requires an argument, e.g., `#[{name}({example})]`"), + ); + // Returning `Err` would replace it with a dummy fragment and cause cascading name-resolution errors. + // Instead, we return the original token stream so that there is no later noises. + return Ok(annotated); + } + let feature_span = ecx.with_def_site_ctxt(attr_span); expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push(TokenTree::Token( diff --git a/tests/ui/contracts/empty-ensures.rs b/tests/ui/contracts/empty-ensures.rs index 79e57df6eb984..242e903b7cc96 100644 --- a/tests/ui/contracts/empty-ensures.rs +++ b/tests/ui/contracts/empty-ensures.rs @@ -6,7 +6,7 @@ extern crate core; use core::contracts::ensures; #[ensures()] -//~^ ERROR expected an `Fn(&_)` closure, found `()` [E0277] +//~^ ERROR `ensures` attribute requires an argument fn foo(x: u32) -> u32 { x * 2 } diff --git a/tests/ui/contracts/empty-ensures.stderr b/tests/ui/contracts/empty-ensures.stderr index b87f709eeb7a4..369ba431b62ce 100644 --- a/tests/ui/contracts/empty-ensures.stderr +++ b/tests/ui/contracts/empty-ensures.stderr @@ -1,16 +1,8 @@ -error[E0277]: expected an `Fn(&_)` closure, found `()` +error: `ensures` attribute requires an argument, e.g., `#[ensures(|result: &T| condition)]` --> $DIR/empty-ensures.rs:8:1 | LL | #[ensures()] | ^^^^^^^^^^^^ - | | - | expected an `Fn(&_)` closure, found `()` - | required by a bound introduced by this call - | - = 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 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/empty-requires.rs b/tests/ui/contracts/empty-requires.rs index dedcc10d52cb0..eae86607acf31 100644 --- a/tests/ui/contracts/empty-requires.rs +++ b/tests/ui/contracts/empty-requires.rs @@ -1,4 +1,3 @@ -//@ dont-require-annotations: NOTE //@ compile-flags: -Zcontract-checks=yes #![expect(incomplete_features)] #![feature(contracts)] @@ -7,8 +6,7 @@ extern crate core; use core::contracts::requires; #[requires()] -//~^ ERROR mismatched types [E0308] -//~| NOTE expected `bool`, found `()` +//~^ ERROR `requires` attribute requires an argument fn foo(x: u32) -> u32 { x * 2 } diff --git a/tests/ui/contracts/empty-requires.stderr b/tests/ui/contracts/empty-requires.stderr index 702b8a23c55e3..c8fa644702259 100644 --- a/tests/ui/contracts/empty-requires.stderr +++ b/tests/ui/contracts/empty-requires.stderr @@ -1,9 +1,8 @@ -error[E0308]: mismatched types - --> $DIR/empty-requires.rs:9:1 +error: `requires` attribute requires an argument, e.g., `#[requires(condition)]` + --> $DIR/empty-requires.rs:8:1 | LL | #[requires()] - | ^^^^^^^^^^^^^ expected `bool`, found `()` + | ^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lint/single-use-lifetimes-issue-146834.rs b/tests/ui/lint/single-use-lifetimes-issue-146834.rs new file mode 100644 index 0000000000000..8c03e40fa8070 --- /dev/null +++ b/tests/ui/lint/single-use-lifetimes-issue-146834.rs @@ -0,0 +1,18 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/146834. + +//@ compile-flags: -Wsingle-use-lifetimes +//@ edition: 2024 + +#![expect(incomplete_features)] +#![feature(contracts)] + +#[core::contracts::ensures] +//~^ ERROR `ensures` attribute requires an argument +fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { + //~^ ERROR missing lifetime specifiers + //~| WARN lifetime parameter `'a` only used once + //~| WARN lifetime parameter `'b` only used once + loop {} +} + +fn main() {} diff --git a/tests/ui/lint/single-use-lifetimes-issue-146834.stderr b/tests/ui/lint/single-use-lifetimes-issue-146834.stderr new file mode 100644 index 0000000000000..d7b84680fd081 --- /dev/null +++ b/tests/ui/lint/single-use-lifetimes-issue-146834.stderr @@ -0,0 +1,55 @@ +error: `ensures` attribute requires an argument, e.g., `#[ensures(|result: &T| condition)]` + --> $DIR/single-use-lifetimes-issue-146834.rs:9:1 + | +LL | #[core::contracts::ensures] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/single-use-lifetimes-issue-146834.rs:11:42 + | +LL | fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { + | ------- ------- ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +note: these named lifetimes are available to use + --> $DIR/single-use-lifetimes-issue-146834.rs:11:6 + | +LL | fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { + | ^^ ^^ +help: consider using one of the available lifetimes here + | +LL | fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { + | +++++++++ +++++++++ + +warning: lifetime parameter `'a` only used once + --> $DIR/single-use-lifetimes-issue-146834.rs:11:6 + | +LL | fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { + | ^^ -- ...is used only here + | | + | this lifetime... + | + = note: requested on the command line with `-W single-use-lifetimes` +help: elide the single-use lifetime + | +LL - fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { +LL + fn f<'b>(a: &i32, b: &'b i32) -> (&i32, &i32) { + | + +warning: lifetime parameter `'b` only used once + --> $DIR/single-use-lifetimes-issue-146834.rs:11:10 + | +LL | fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { + | ^^ this lifetime... -- ...is used only here + | +help: elide the single-use lifetime + | +LL - fn f<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { +LL + fn f<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { + | + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs index 2b1bacf7e0c31..db85d496991f7 100644 --- a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs +++ b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs @@ -4,7 +4,7 @@ struct T; impl T { - #[core::contracts::ensures] //~ ERROR expected an `Fn(&_)` closure, found `()` + #[core::contracts::ensures] //~ ERROR `ensures` attribute requires an argument fn b() {(loop)} //~^ ERROR expected `{`, found `)` //~| ERROR expected `{`, found `)` diff --git a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr index 56dbdae14189b..ab6459bdc919a 100644 --- a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr +++ b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr @@ -6,6 +6,12 @@ LL | fn b() {(loop)} | | | while parsing this `loop` expression +error: `ensures` attribute requires an argument, e.g., `#[ensures(|result: &T| condition)]` + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:7:5 + | +LL | #[core::contracts::ensures] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: expected `{`, found `)` --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18 | @@ -16,19 +22,5 @@ LL | fn b() {(loop)} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: expected an `Fn(&_)` closure, found `()` - --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:7:5 - | -LL | #[core::contracts::ensures] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected an `Fn(&_)` closure, found `()` - | required by a bound introduced by this call - | - = 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 3 previous errors -For more information about this error, try `rustc --explain E0277`.