diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 6cffd8e119b7e..f31869906baf1 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -34,9 +34,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // into: // // let __postcond = if contract_checks { - // CONTRACT_DECLARATIONS; - // contract_check_requires(PRECOND); - // Some(|ret_val| POSTCOND) + // let __ensures_builder = || { + // CONTRACT_DECLARATIONS; + // contract_check_requires(|| PRECOND); + // build_check_ensures(Some(|| { POSTCOND_DECLS; |ret_val| POSTCOND })) + // }; + // contract_check_requires_and_build_ensures(__ensures_builder) // } else { // None // }; @@ -50,7 +53,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // } // } - let precond = self.lower_precond(req); + let lowered_req = self.lower_expr_mut(&req); + let precond = self.lower_precond(lowered_req); let postcond_checker = self.lower_postcond_checker(ens); let contract_check = self.lower_contract_check_with_postcond( @@ -71,7 +75,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // into: // // let __postcond = if contract_checks { - // Some(|ret_val| POSTCOND) + // let __ensures_builder = || { + // CONTRACT_DECLARATIONS; + // build_check_ensures(Some(|| { POSTCOND_DECLS; |ret_val| POSTCOND })) + // }; + // contract_check_requires_and_build_ensures(__ensures_builder) // } else { // None // }; @@ -79,7 +87,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // let ret = { body }; // // if contract_checks { - // CONTRACT_DECLARATIONS; // contract_check_ensures(__postcond, ret) // } else { // ret @@ -102,13 +109,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // { // if contracts_checks { - // CONTRACT_DECLARATIONS; - // contract_requires(PRECOND); + // contract_requires(|| { CONTRACT_DECLARATIONS; PRECOND }); // } // body // } - let precond = self.lower_precond(req); - let precond_check = self.lower_contract_check_just_precond(contract_decls, precond); + let lowered_req = self.lower_expr(&req); + let precond = self.block_decls_with_precond(contract_decls, lowered_req); + let precond_check = self.lower_contract_check_just_precond(precond); let body = self.arena.alloc(body(self)); @@ -137,17 +144,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Lower the precondition check intrinsic. - fn lower_precond(&mut self, req: &Box) -> rustc_hir::Stmt<'hir> { - let lowered_req = self.lower_expr_mut(&req); + fn lower_precond(&mut self, req: rustc_hir::Expr<'hir>) -> rustc_hir::Stmt<'hir> { let req_span = self.mark_span_with_reason( rustc_span::DesugaringKind::Contract, - lowered_req.span, + req.span, Some(Arc::clone(&self.allow_contracts)), ); + let req_closure = self.expr_closure(req_span, req); let precond = self.expr_call_lang_item_fn_mut( req_span, rustc_hir::LangItem::ContractCheckRequires, - &*arena_vec![self; lowered_req], + &*arena_vec![self; req_closure], ); self.stmt_expr(req.span, precond) } @@ -163,33 +170,42 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Some(Arc::clone(&self.allow_contracts)), ); let lowered_ens = self.lower_expr_mut(&ens); + let ens_closure = self.expr_closure(ens_span, lowered_ens); self.expr_call_lang_item_fn( ens_span, rustc_hir::LangItem::ContractBuildCheckEnsures, - &*arena_vec![self; lowered_ens], + &*arena_vec![self; ens_closure], ) } + fn block_decls_with_precond( + &mut self, + contract_decls: &'hir [rustc_hir::Stmt<'_>], + lowered_req: &'hir rustc_hir::Expr<'_>, + ) -> rustc_hir::Stmt<'hir> { + let req_span = span_of_stmts(contract_decls, lowered_req.span); + + let precond_stmts = self.block_all(req_span, contract_decls, Some(lowered_req)); + let precond_stmts = self.expr_block(precond_stmts); + self.lower_precond(precond_stmts) + } + fn lower_contract_check_just_precond( &mut self, - contract_decls: &'hir [rustc_hir::Stmt<'hir>], precond: rustc_hir::Stmt<'hir>, ) -> rustc_hir::Stmt<'hir> { - let stmts = self - .arena - .alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain([precond].into_iter())); - - let then_block_stmts = self.block_all(precond.span, stmts, None); + let span = precond.span; + let then_block_stmts = self.block_all(span, &*arena_vec![self; precond], None); let then_block = self.arena.alloc(self.expr_block(&then_block_stmts)); let precond_check = rustc_hir::ExprKind::If( - self.arena.alloc(self.expr_bool_literal(precond.span, self.tcx.sess.contract_checks())), + self.arena.alloc(self.expr_bool_literal(span, self.tcx.sess.contract_checks())), then_block, None, ); - let precond_check = self.expr(precond.span, precond_check); - self.stmt_expr(precond.span, precond_check) + let precond_check = self.expr(span, precond_check); + self.stmt_expr(span, precond_check) } fn lower_contract_check_with_postcond( @@ -201,26 +217,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let stmts = self .arena .alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain(precond.into_iter())); - let span = match precond { - Some(precond) => precond.span, - None => postcond_checker.span, - }; - - let postcond_checker = self.arena.alloc(self.expr_enum_variant_lang_item( - postcond_checker.span, - rustc_hir::lang_items::LangItem::OptionSome, - &*arena_vec![self; *postcond_checker], - )); - let then_block_stmts = self.block_all(span, stmts, Some(postcond_checker)); - let then_block = self.arena.alloc(self.expr_block(&then_block_stmts)); - let none_expr = self.arena.alloc(self.expr_enum_variant_lang_item( - postcond_checker.span, - rustc_hir::lang_items::LangItem::OptionNone, - Default::default(), - )); - let else_block = self.block_expr(none_expr); - let else_block = self.arena.alloc(self.expr_block(else_block)); + let span = self.contract_check_with_postcond_span(stmts, postcond_checker); + + let then_block = self.contract_check_with_postcond_block(stmts, postcond_checker, span); + let else_block = self.option_none_block(span); let contract_check = rustc_hir::ExprKind::If( self.arena.alloc(self.expr_bool_literal(span, self.tcx.sess.contract_checks())), @@ -230,32 +231,89 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(self.expr(span, contract_check)) } + fn contract_check_with_postcond_span( + &mut self, + stmts: &mut [rustc_hir::Stmt<'hir>], + postcond_checker: &rustc_hir::Expr<'_>, + ) -> rustc_span::Span { + // For error diagnostics, span is set to decls + precondition, because + // those will determine the well-typedness of the __ensures_builder + // closure. postcond_checker is already type-checked as part of the + // call to build_check_ensures. + let span = + span_of_stmts(stmts, stmts.last().map(|s| s.span).unwrap_or(postcond_checker.span)); + self.mark_span_with_reason( + rustc_span::DesugaringKind::Contract, + span, + Some(Arc::clone(&self.allow_contracts)), + ) + } + + fn contract_check_with_postcond_block( + &mut self, + stmts: &'hir mut [rustc_hir::Stmt<'hir>], + postcond_checker: &'hir rustc_hir::Expr<'_>, + span: rustc_span::Span, + ) -> &'hir mut rustc_hir::Expr<'hir> { + let (builder_decl, builder_ident_expr) = + self.contract_check_with_postcond_builder(stmts, postcond_checker, span); + + let build_postcond_call = self.expr_call_lang_item_fn( + span, + rustc_hir::LangItem::ContractCheckRequiresAndBuildEnsures, + &*arena_vec![self; *builder_ident_expr], + ); + let block_stmts = + self.block_all(span, arena_vec![self; builder_decl], Some(build_postcond_call)); + self.arena.alloc(self.expr_block(block_stmts)) + } + + fn contract_check_with_postcond_builder( + &mut self, + stmts: &'hir mut [rustc_hir::Stmt<'hir>], + postcond_checker: &'hir rustc_hir::Expr<'_>, + span: rustc_span::Span, + ) -> (rustc_hir::Stmt<'hir>, &'hir rustc_hir::Expr<'hir>) { + let block_closure = + self.contract_check_with_postcond_builder_closure(stmts, postcond_checker, span); + + let (builder_ident, builder_hir_id, builder_decl) = + self.bind_expression(block_closure, span, "__ensures_builder"); + let builder_ident_expr = self.expr_ident(span, builder_ident, builder_hir_id); + + (builder_decl, builder_ident_expr) + } + + fn contract_check_with_postcond_builder_closure( + &mut self, + stmts: &'hir mut [rustc_hir::Stmt<'hir>], + postcond_checker: &'hir rustc_hir::Expr<'_>, + span: rustc_span::Span, + ) -> &'hir mut rustc_hir::Expr<'hir> { + let stmts = self.block_all(span, stmts, Some(postcond_checker)); + let stmts = self.expr_block(stmts); + let closure = self.expr_closure(span, stmts); + self.arena.alloc(closure) + } + + fn option_none_block(&mut self, span: rustc_span::Span) -> &'hir mut rustc_hir::Expr<'hir> { + let none_expr = self.arena.alloc(self.expr_enum_variant_lang_item( + span, + rustc_hir::lang_items::LangItem::OptionNone, + Default::default(), + )); + let else_block = self.block_expr(none_expr); + self.arena.alloc(self.expr_block(else_block)) + } + fn wrap_body_with_contract_check( &mut self, body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>, contract_check: &'hir rustc_hir::Expr<'hir>, postcond_span: rustc_span::Span, ) -> &'hir rustc_hir::Block<'hir> { - let check_ident: rustc_span::Ident = - rustc_span::Ident::from_str_and_span("__ensures_checker", postcond_span); - let (check_hir_id, postcond_decl) = { - // Set up the postcondition `let` statement. - let (checker_pat, check_hir_id) = self.pat_ident_binding_mode_mut( - postcond_span, - check_ident, - rustc_hir::BindingMode::NONE, - ); - ( - check_hir_id, - self.stmt_let_pat( - None, - postcond_span, - Some(contract_check), - self.arena.alloc(checker_pat), - rustc_hir::LocalSource::Contract, - ), - ) - }; + let (check_ident, check_hir_id, postcond_decl) = + self.bind_expression(contract_check, postcond_span, "__ensures_checker"); // Install contract_ensures so we will intercept `return` statements, // then lower the body. @@ -274,6 +332,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { wrapped_body } + fn bind_expression( + &mut self, + expr: &'hir rustc_hir::Expr<'hir>, + span: rustc_span::Span, + var_name: &str, + ) -> (rustc_span::Ident, rustc_hir::HirId, rustc_hir::Stmt<'hir>) { + let ident = rustc_span::Ident::from_str_and_span(var_name, span); + let (pat, hir_id) = + self.pat_ident_binding_mode_mut(span, ident, rustc_hir::BindingMode::NONE); + + let decl = self.stmt_let_pat( + None, + span, + Some(expr), + self.arena.alloc(pat), + rustc_hir::LocalSource::Contract, + ); + (ident, hir_id, decl) + } + /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check /// a contract ensures clause, if it exists. pub(super) fn checked_return( @@ -307,20 +385,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ret // } // } - let ret_ident: rustc_span::Ident = rustc_span::Ident::from_str_and_span("__ret", span); - - // Set up the return `let` statement. - let (ret_pat, ret_hir_id) = - self.pat_ident_binding_mode_mut(span, ret_ident, rustc_hir::BindingMode::NONE); - - let ret_stmt = self.stmt_let_pat( - None, - span, - Some(expr), - self.arena.alloc(ret_pat), - rustc_hir::LocalSource::Contract, - ); - + let (ret_ident, ret_hir_id, ret_stmt) = self.bind_expression(expr, span, "__ret"); let ret = self.expr_ident(span, ret_ident, ret_hir_id); let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id); @@ -355,3 +420,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(self.expr_block(self.arena.alloc(ret_block))) } } + +fn span_of_stmts<'hir>( + stmts: &'hir [rustc_hir::Stmt<'_>], + default_span: rustc_span::Span, +) -> rustc_span::Span { + match stmts { + [] => default_span, + [first, ..] => first.span.to(default_span), + } +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d9bf6b52f31f7..59df16e2725e2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2344,6 +2344,48 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Lit(Spanned { node: LitKind::Bool(val), span })) } + pub(super) fn expr_closure( + &mut self, + span: Span, + body_expr: hir::Expr<'hir>, + ) -> hir::Expr<'hir> { + let closure_node_id = self.next_node_id(); + + let closure_def_id = self.create_def( + closure_node_id, + None, + hir::def::DefKind::Closure, + hir::definitions::DefPathData::LateClosure, + span, + ); + + let hir_id = self.lower_node_id(closure_node_id); + let body_id = self.lower_body(|_| (Default::default(), body_expr)); + + let fn_decl = self.arena.alloc(hir::FnDecl { + inputs: &[], + output: hir::FnRetTy::DefaultReturn(span), + c_variadic: false, + implicit_self: hir::ImplicitSelfKind::None, + lifetime_elision_allowed: true, + }); + + let closure = self.arena.alloc(hir::Closure { + def_id: closure_def_id, + binder: hir::ClosureBinder::Default, + constness: hir::Constness::NotConst, + capture_clause: hir::CaptureBy::Ref, + bound_generic_params: &[], + fn_decl, + body: body_id, + fn_decl_span: span, + fn_arg_span: None, + kind: hir::ClosureKind::Closure, + }); + + hir::Expr { hir_id, kind: hir::ExprKind::Closure(closure), span } + } + pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> { let hir_id = self.next_id(); hir::Expr { hir_id, kind, span: self.lower_span(span) } diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 5e361891f6d04..f577687ccfbfc 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -296,6 +296,8 @@ pub enum DefPathData { LifetimeNs(Symbol), /// A closure expression. Closure, + /// A closure expression created during AST->HIR lowering. + LateClosure, // Subportions of items: /// Implicit constructor for a unit or tuple-like struct or enum variant. @@ -466,6 +468,7 @@ impl DefPathData { | Use | GlobalAsm | Closure + | LateClosure | Ctor | AnonConst | LateAnonConst @@ -490,6 +493,7 @@ impl DefPathData { | Use | GlobalAsm | Closure + | LateClosure | Ctor | AnonConst | LateAnonConst @@ -510,7 +514,7 @@ impl DefPathData { ForeignMod => DefPathDataName::Anon { namespace: kw::Extern }, Use => DefPathDataName::Anon { namespace: kw::Use }, GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm }, - Closure => DefPathDataName::Anon { namespace: sym::closure }, + Closure | LateClosure => DefPathDataName::Anon { namespace: sym::closure }, Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst | LateAnonConst => DefPathDataName::Anon { namespace: sym::constant }, DesugaredAnonymousLifetime => DefPathDataName::Named(kw::UnderscoreLifetime), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 557f76208bfe6..8054824b585af 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -436,6 +436,7 @@ language_item_table! { // Experimental lang items for implementing contract pre- and post-condition checking. ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None; ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None; + ContractCheckRequiresAndBuildEnsures, sym::contract_check_requires_and_build_ensures, contract_check_requires_and_build_ensures_fn, Target::Fn, GenericRequirement::None; // Experimental lang items for `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727) DefaultTrait4, sym::default_trait4, default_trait4_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8bb22c2a831bf..e00d9ee49b324 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4123,26 +4123,6 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Tup(Default::default())) } - pub(crate) fn mk_closure_expr(&self, span: Span, body: Box) -> Box { - self.mk_expr( - span, - ast::ExprKind::Closure(Box::new(ast::Closure { - binder: rustc_ast::ClosureBinder::NotPresent, - constness: rustc_ast::Const::No, - movability: rustc_ast::Movability::Movable, - capture_clause: rustc_ast::CaptureBy::Ref, - coroutine_kind: None, - fn_decl: Box::new(rustc_ast::FnDecl { - inputs: Default::default(), - output: rustc_ast::FnRetTy::Default(span), - }), - fn_arg_span: span, - fn_decl_span: span, - body, - })), - ) - } - /// Create expression span ensuring the span of the parent node /// is larger than the span of lhs and rhs, including the attributes. fn mk_expr_sp(&self, lhs: &Box, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 8c02092fd6788..3c91f393ee6b1 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -371,7 +371,6 @@ impl<'a> Parser<'a> { }, None => self.mk_unit_expr(decls_and_precond.span), }; - let precond = self.mk_closure_expr(precond.span, precond); let decls = decls_and_precond.stmts; (decls, Some(precond)) } else { diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 5505fe82cea65..c9ce27f48edd5 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -680,7 +680,9 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's hir::definitions::DefPathData::TypeNs(..) => "t", hir::definitions::DefPathData::ValueNs(..) => "v", - hir::definitions::DefPathData::Closure => "C", + hir::definitions::DefPathData::Closure | hir::definitions::DefPathData::LateClosure => { + "C" + } hir::definitions::DefPathData::Ctor => "c", hir::definitions::DefPathData::AnonConst => "K", hir::definitions::DefPathData::LateAnonConst => "k", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1915ff0380fda..07f3ef7419f7f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -782,6 +782,7 @@ symbols! { contract_build_check_ensures, contract_check_ensures, contract_check_requires, + contract_check_requires_and_build_ensures, contract_checks, contracts, contracts_ensures, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 95cbb9e07ebb7..7288233ff6704 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -885,7 +885,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { // Uppercase categories are more stable than lowercase ones. DefPathData::TypeNs(_) => 't', DefPathData::ValueNs(_) => 'v', - DefPathData::Closure => 'C', + DefPathData::Closure | DefPathData::LateClosure => 'C', DefPathData::Ctor => 'c', DefPathData::AnonConst => 'K', DefPathData::LateAnonConst => 'k', diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 495f84bce4bf2..33466e426baef 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -1,8 +1,9 @@ //! Unstable module containing the unstable contracts lang items and attribute macros. +use crate::intrinsics::const_eval_select; pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; -/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute. +/// This function is used as part of the desugaring of the `#[ensures]` attribute. /// /// This is an existing hack to allow users to omit the type of the return value in their ensures /// attribute. @@ -14,11 +15,39 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_require // Similar to `contract_check_requires`, we need to use the user-facing // `contracts` feature rather than the perma-unstable `contracts_internals`. // Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. -#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] -pub const fn build_check_ensures(cond: C) -> C +pub fn build_check_ensures(cond: C) -> E where - C: Fn(&Ret) -> bool + Copy + 'static, + C: FnOnce() -> E + Copy, + E: Fn(&Ret) -> bool + Copy + 'static, { - cond + cond() +} + +/// This function is used as part of the contracts HIR lowering (desugaring) to +/// ensure contract code is only executed in a non-const environment, allowing +/// the contract to call non-const functions even when the function being +/// annotated with contracts is const itself. +/// +/// The `contract` closure should execute the necessary requires check via +/// `contract_check_ensures` and return an ensures closure built by +/// `build_check_ensures`. +#[unstable(feature = "contracts_internals", issue = "128044")] +#[rustc_const_unstable(feature = "contracts", issue = "128044")] +#[lang = "contract_check_requires_and_build_ensures"] +pub const fn contract_check_requires_and_build_ensures< + C: FnOnce() -> E + Copy, + E: Fn(&Ret) -> bool + Copy, + Ret, +>( + contract: C, +) -> Option { + const_eval_select!( + @capture[C: FnOnce() -> E + Copy, E: Fn(&Ret) -> bool + Copy, Ret] { contract: C } -> Option: + if const { + None + } else { + Some(contract()) + } + ) } diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 20c220e98bcc8..6bd96f14c5b07 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -1,20 +1,18 @@ -error[E0277]: the trait bound `Baz: Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}` +error[E0277]: the trait bound `Baz: Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:1: 13:82}` --> $DIR/contract-captures-via-closure-noncopy.rs:13:1 | LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^^ - | | | - | | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}` - | | this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:13:42}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | unsatisfied trait bound - | required by a bound introduced by this call + | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:1: 13:82}` | - = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}`, the trait `Copy` is not implemented for `Baz` + = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:1: 13:82}`, the trait `Copy` is not implemented for `Baz` note: required because it's used within this closure - --> $DIR/contract-captures-via-closure-noncopy.rs:13:42 + --> $DIR/contract-captures-via-closure-noncopy.rs:13:1 | LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `build_check_ensures` --> $SRC_DIR/core/src/contracts.rs:LL:COL help: consider annotating `Baz` with `#[derive(Copy)]` diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.rs new file mode 100644 index 0000000000000..9606336c4917d --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.rs @@ -0,0 +1,18 @@ +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::{ensures, requires}; + +#[requires(*x = 0; true)] +//~^ ERROR: the trait bound `&mut &mut u32: Copy` is not satisfied +#[ensures(|_ret| true)] +fn buggy_add(x: &mut u32, y: u32) { + *x = *x + y; +} + +fn main() { + let mut x = 10; + buggy_add(&mut x, 100); + assert_eq!(x, 110); +} diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.stderr b/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.stderr new file mode 100644 index 0000000000000..2dd8e40f3caf8 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations-with-ensures.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `&mut &mut u32: Copy` is not satisfied in `{closure@$DIR/contracts-disabled-side-effect-declarations-with-ensures.rs:7:12: 7:24}` + --> $DIR/contracts-disabled-side-effect-declarations-with-ensures.rs:7:12 + | +LL | #[requires(*x = 0; true)] + | ^^^^^^^^^^^^ + | | + | unsatisfied trait bound + | within this `{closure@$DIR/contracts-disabled-side-effect-declarations-with-ensures.rs:7:12: 7:24}` + | + = help: within `{closure@$DIR/contracts-disabled-side-effect-declarations-with-ensures.rs:7:12: 7:24}`, the trait `Copy` is not implemented for `&mut &mut u32` +help: the trait `Copy` is implemented for `u32` + --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation + = note: `Copy` is implemented for `&&mut u32`, but not for `&mut &mut u32` +note: required because it's used within this closure + --> $DIR/contracts-disabled-side-effect-declarations-with-ensures.rs:7:12 + | +LL | #[requires(*x = 0; true)] + | ^^^^^^^^^^^^ +note: required by a bound in `contract_check_requires_and_build_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + = note: this error originates in the macro `marker_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs index 4b2d4a80237fe..324d11d81113c 100644 --- a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs @@ -1,4 +1,3 @@ -//@ run-pass #![expect(incomplete_features)] #![feature(contracts)] @@ -6,6 +5,7 @@ extern crate core; use core::contracts::requires; #[requires(*x = 0; true)] +//~^ ERROR: the trait bound `&mut &mut u32: Copy` is not satisfied fn buggy_add(x: &mut u32, y: u32) { *x = *x + y; } diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr new file mode 100644 index 0000000000000..12c09abee1a87 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `&mut &mut u32: Copy` is not satisfied in `{closure@$DIR/contracts-disabled-side-effect-declarations.rs:7:12: 7:24}` + --> $DIR/contracts-disabled-side-effect-declarations.rs:7:12 + | +LL | #[requires(*x = 0; true)] + | ^^^^^^^^^^^^ + | | + | unsatisfied trait bound + | within this `{closure@$DIR/contracts-disabled-side-effect-declarations.rs:7:12: 7:24}` + | + = help: within `{closure@$DIR/contracts-disabled-side-effect-declarations.rs:7:12: 7:24}`, the trait `Copy` is not implemented for `&mut &mut u32` +help: the trait `Copy` is implemented for `u32` + --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation + = note: `Copy` is implemented for `&&mut u32`, but not for `&mut &mut u32` +note: required because it's used within this closure + --> $DIR/contracts-disabled-side-effect-declarations.rs:7:12 + | +LL | #[requires(*x = 0; true)] + | ^^^^^^^^^^^^ +note: required by a bound in `contract_check_requires` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL + = note: this error originates in the macro `marker_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.rs new file mode 100644 index 0000000000000..201c3c7bbc416 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.rs @@ -0,0 +1,18 @@ +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::{ensures, requires}; + +#[requires(true)] +#[ensures(*x = 0; |_ret| true)] +//~^ ERROR: the trait bound `&mut &mut u32: Copy` is not satisfied +fn buggy_add(x: &mut u32, y: u32) { + *x = *x + y; +} + +fn main() { + let mut x = 10; + buggy_add(&mut x, 100); + assert_eq!(x, 110); +} diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.stderr b/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.stderr new file mode 100644 index 0000000000000..9df76c01db668 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures-with-requires.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `&mut &mut u32: Copy` is not satisfied in `{closure@$DIR/contracts-disabled-side-effect-ensures-with-requires.rs:8:1: 8:32}` + --> $DIR/contracts-disabled-side-effect-ensures-with-requires.rs:8:1 + | +LL | #[ensures(*x = 0; |_ret| true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound + | within this `{closure@$DIR/contracts-disabled-side-effect-ensures-with-requires.rs:8:1: 8:32}` + | + = help: within `{closure@$DIR/contracts-disabled-side-effect-ensures-with-requires.rs:8:1: 8:32}`, the trait `Copy` is not implemented for `&mut &mut u32` +help: the trait `Copy` is implemented for `u32` + --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation + = note: `Copy` is implemented for `&&mut u32`, but not for `&mut &mut u32` +note: required because it's used within this closure + --> $DIR/contracts-disabled-side-effect-ensures-with-requires.rs:8:1 + | +LL | #[ensures(*x = 0; |_ret| true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `build_check_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + = note: this error originates in the macro `marker_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs index 1488b8f8d3fd5..e353b653e8ba4 100644 --- a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs @@ -1,4 +1,3 @@ -//@ run-pass #![expect(incomplete_features)] #![feature(contracts)] @@ -6,6 +5,7 @@ extern crate core; use core::contracts::ensures; #[ensures(*x = 0; |_ret| true)] +//~^ ERROR: the trait bound `&mut &mut u32: Copy` is not satisfied fn buggy_add(x: &mut u32, y: u32) { *x = *x + y; } diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr b/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr new file mode 100644 index 0000000000000..a61a2199e2b69 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `&mut &mut u32: Copy` is not satisfied in `{closure@$DIR/contracts-disabled-side-effect-ensures.rs:7:1: 7:32}` + --> $DIR/contracts-disabled-side-effect-ensures.rs:7:1 + | +LL | #[ensures(*x = 0; |_ret| true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound + | within this `{closure@$DIR/contracts-disabled-side-effect-ensures.rs:7:1: 7:32}` + | + = help: within `{closure@$DIR/contracts-disabled-side-effect-ensures.rs:7:1: 7:32}`, the trait `Copy` is not implemented for `&mut &mut u32` +help: the trait `Copy` is implemented for `u32` + --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation + = note: `Copy` is implemented for `&&mut u32`, but not for `&mut &mut u32` +note: required because it's used within this closure + --> $DIR/contracts-disabled-side-effect-ensures.rs:7:1 + | +LL | #[ensures(*x = 0; |_ret| true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `build_check_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + = note: this error originates in the macro `marker_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/early-return-requires-ensures.rs b/tests/ui/contracts/early-return-requires-ensures.rs new file mode 100644 index 0000000000000..ff1ef945de9e0 --- /dev/null +++ b/tests/ui/contracts/early-return-requires-ensures.rs @@ -0,0 +1,22 @@ +//@ dont-require-annotations: NOTE +//@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::{ensures, requires}; + +// Early return in requires takes precedence over ensures clause, +// but now we have two different closure types as candidates for the ensures +// closure, which is not allowed. +#[requires(return |_ret| { true }; true)] +#[ensures(|_ret| { false })] +//~^ ERROR: mismatched types [E0308] +//~| NOTE: no two closures, even if identical, have the same type +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/early-return-requires-ensures.stderr b/tests/ui/contracts/early-return-requires-ensures.stderr new file mode 100644 index 0000000000000..4c278f42ff29f --- /dev/null +++ b/tests/ui/contracts/early-return-requires-ensures.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/early-return-requires-ensures.rs:13:1 + | +LL | #[requires(return |_ret| { true }; true)] + | ------ the expected closure +LL | #[ensures(|_ret| { false })] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure + | + = note: expected closure `{closure@$DIR/early-return-requires-ensures.rs:12:19: 12:25}` + found closure `{closure@$DIR/early-return-requires-ensures.rs:13:11: 13:17}` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object +note: return type inferred to be `{closure@$DIR/early-return-requires-ensures.rs:12:19: 12:25}` here + --> $DIR/early-return-requires-ensures.rs:12:19 + | +LL | #[requires(return |_ret| { true }; true)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/contracts/early-return-requires-expr-ensures.rs b/tests/ui/contracts/early-return-requires-expr-ensures.rs new file mode 100644 index 0000000000000..29f7f5b20fe18 --- /dev/null +++ b/tests/ui/contracts/early-return-requires-expr-ensures.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::{ensures, requires}; + +// note that when we wrap requires in a block, the return is scoped just to +// requires, not the entire contract, making this early return valid +#[requires({if true { return true }; true})] +#[ensures(|_ret| { true })] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/empty-ensures.rs b/tests/ui/contracts/empty-ensures.rs index 0a52391117861..79521ebf07dc5 100644 --- a/tests/ui/contracts/empty-ensures.rs +++ b/tests/ui/contracts/empty-ensures.rs @@ -7,6 +7,7 @@ use core::contracts::ensures; #[ensures()] //~^ ERROR expected a `Fn(&_)` closure, found `()` [E0277] +//~| ERROR expected a `Fn(&_)` closure, found `()` [E0277] fn foo(x: u32) -> u32 { x * 2 } diff --git a/tests/ui/contracts/empty-ensures.stderr b/tests/ui/contracts/empty-ensures.stderr index 6a19d234b52c2..330bbf2065edd 100644 --- a/tests/ui/contracts/empty-ensures.stderr +++ b/tests/ui/contracts/empty-ensures.stderr @@ -2,15 +2,22 @@ error[E0277]: expected a `Fn(&_)` closure, found `()` --> $DIR/empty-ensures.rs:8:1 | LL | #[ensures()] - | ^^^^^^^^^^^^ - | | - | expected an `Fn(&_)` closure, found `()` - | required by a bound introduced by this call + | ^^^^^^^^^^^^ expected an `Fn(&_)` 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 1 previous error +error[E0277]: expected a `Fn(&_)` closure, found `()` + --> $DIR/empty-ensures.rs:8:1 + | +LL | #[ensures()] + | ^^^^^^^^^^^^ expected an `Fn(&_)` closure, found `()` + | + = help: the trait `for<'a> Fn(&'a _)` is not implemented for `()` +note: required by a bound in `contract_check_requires_and_build_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/explicit-return-ensures.rs b/tests/ui/contracts/explicit-return-ensures.rs new file mode 100644 index 0000000000000..b5572ad3b7d3e --- /dev/null +++ b/tests/ui/contracts/explicit-return-ensures.rs @@ -0,0 +1,16 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::ensures; + +#[ensures(return |_ret| { true })] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/explicit-return-requires.rs b/tests/ui/contracts/explicit-return-requires.rs new file mode 100644 index 0000000000000..7deda2cf13d40 --- /dev/null +++ b/tests/ui/contracts/explicit-return-requires.rs @@ -0,0 +1,16 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; +use core::contracts::requires; + +#[requires(return true)] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index d675601036447..50d35bf2ae121 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -10,7 +10,7 @@ #![feature(contracts_internals)] // to access check_requires lang item #![feature(core_intrinsics)] fn foo(x: Baz) -> i32 { - let injected_checker = Some(core::contracts::build_check_ensures(|ret| *ret > 100)); + let injected_checker = Some(core::contracts::build_check_ensures(|| |ret| *ret > 100)); let ret = x.baz + 50; core::intrinsics::contract_check_ensures(injected_checker, ret) diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs index 9d3765bc228db..9b02c5ef06882 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs @@ -7,7 +7,7 @@ fn main() { core::intrinsics::contract_check_ensures(Some(|_: &&u32| true), &1); //~^ ERROR use of unstable library feature `contracts_internals` - core::contracts::build_check_ensures(|_: &()| true); + core::contracts::build_check_ensures(|| |_: &()| true); //~^ ERROR use of unstable library feature `contracts_internals` // ast extensions are guarded by contracts_internals feature gate diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index 0010fca2f96c5..8ce2a967b26a2 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -41,7 +41,7 @@ LL | core::intrinsics::contract_check_ensures(Some(|_: &&u32| true), &1); error[E0658]: use of unstable library feature `contracts_internals` --> $DIR/internal-feature-gating.rs:10:5 | -LL | core::contracts::build_check_ensures(|_: &()| true); +LL | core::contracts::build_check_ensures(|| |_: &()| true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.rs b/tests/ui/contracts/internal_machinery/lowering/basics.rs index 7b3a769af8258..db35ffb6dcaba 100644 --- a/tests/ui/contracts/internal_machinery/lowering/basics.rs +++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs @@ -13,7 +13,7 @@ fn foo(x: u32) -> u32 { // call contract_check_requires here to avoid borrow checker issues // with variables declared in contract requires core::intrinsics::contract_check_requires(|| y > 0); - Some(core::contracts::build_check_ensures(move |ret| *ret == y)) + Some(core::contracts::build_check_ensures(|| move |ret| *ret == y)) }; core::intrinsics::contract_check_ensures(post, { 2 * x }) diff --git a/tests/ui/contracts/requires-non-const-stmt-with-ensures.rs b/tests/ui/contracts/requires-non-const-stmt-with-ensures.rs new file mode 100644 index 0000000000000..01349f833ce86 --- /dev/null +++ b/tests/ui/contracts/requires-non-const-stmt-with-ensures.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes + +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; + +use core::contracts::{ensures, requires}; + +pub fn foo() {} + +#[requires(foo(); true)] +#[ensures(|_| { true })] +pub const fn bar() {} + +fn main() {} diff --git a/tests/ui/contracts/requires-non-const-stmt.rs b/tests/ui/contracts/requires-non-const-stmt.rs new file mode 100644 index 0000000000000..e7da8da9aa347 --- /dev/null +++ b/tests/ui/contracts/requires-non-const-stmt.rs @@ -0,0 +1,16 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes + +#![expect(incomplete_features)] +#![feature(contracts)] + +extern crate core; + +use core::contracts::requires; + +pub fn foo() {} + +#[requires(foo(); true)] +pub const fn bar() {} + +fn main() {} 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 68346a00ae1a7..81d733f140cc0 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 @@ -5,6 +5,7 @@ struct T; impl T { #[core::contracts::ensures] //~ ERROR expected a `Fn(&_)` closure, found `()` + //~| ERROR expected a `Fn(&_)` closure, found `()` 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 f1ffda2a9bee6..f20a4e73b9128 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 @@ -1,5 +1,5 @@ error: expected `{`, found `)` - --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18 + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:9:18 | LL | fn b() {(loop)} | ----^ expected `{` @@ -7,7 +7,7 @@ LL | fn b() {(loop)} | while parsing this `loop` expression error: expected `{`, found `)` - --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18 + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:9:18 | LL | fn b() {(loop)} | ----^ expected `{` @@ -20,15 +20,22 @@ error[E0277]: expected a `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 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn(&_)` 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 3 previous errors +error[E0277]: expected a `Fn(&_)` closure, found `()` + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:7:5 + | +LL | #[core::contracts::ensures] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn(&_)` closure, found `()` + | + = help: the trait `for<'a> Fn(&'a _)` is not implemented for `()` +note: required by a bound in `contract_check_requires_and_build_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`.