diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 0adf4f898ab6d..e5f20fc770780 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3700,6 +3700,9 @@ pub struct TraitImplHeader { #[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)] pub struct FnContract { + /// Declarations of variables accessible both in the `requires` and + /// `ensures` clauses. + pub declarations: ThinVec, pub requires: Option>, pub ensures: Option>, } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index f1e810a8b9ea9..5bfe63008516c 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -27,7 +27,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } - fn lower_stmts( + pub(super) fn lower_stmts( &mut self, mut ast_stmts: &[Stmt], ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) { diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 2f1c3d66d4e70..bafc49607f410 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -18,6 +18,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>, contract: &rustc_ast::FnContract, ) -> rustc_hir::Expr<'hir> { + // The order in which things are lowered is important! I.e to + // refer to variables in contract_decls from postcond/precond, + // we must lower it first! + let contract_decls = self.lower_stmts(&contract.declarations).0; + match (&contract.requires, &contract.ensures) { (Some(req), Some(ens)) => { // Lower the fn contract, which turns: @@ -27,6 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // into: // // let __postcond = if contract_checks { + // CONTRACT_DECLARATIONS; // contract_check_requires(PRECOND); // Some(|ret_val| POSTCOND) // } else { @@ -45,8 +51,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let precond = self.lower_precond(req); let postcond_checker = self.lower_postcond_checker(ens); - let contract_check = - self.lower_contract_check_with_postcond(Some(precond), postcond_checker); + let contract_check = self.lower_contract_check_with_postcond( + contract_decls, + Some(precond), + postcond_checker, + ); let wrapped_body = self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); @@ -68,15 +77,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // let ret = { body }; // // if contract_checks { + // CONTRACT_DECLARATIONS; // contract_check_ensures(__postcond, ret) // } else { // ret // } // } - let postcond_checker = self.lower_postcond_checker(ens); let contract_check = - self.lower_contract_check_with_postcond(None, postcond_checker); + self.lower_contract_check_with_postcond(contract_decls, None, postcond_checker); let wrapped_body = self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); @@ -91,12 +100,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // { // if contracts_checks { + // CONTRACT_DECLARATIONS; // contract_requires(PRECOND); // } // body // } let precond = self.lower_precond(req); - let precond_check = self.lower_contract_check_just_precond(precond); + let precond_check = self.lower_contract_check_just_precond(contract_decls, precond); let body = self.arena.alloc(body(self)); @@ -145,9 +155,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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([precond].into_iter()); + 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 then_block = self.arena.alloc(self.expr_block(&then_block_stmts)); @@ -164,10 +177,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_contract_check_with_postcond( &mut self, + contract_decls: &'hir [rustc_hir::Stmt<'hir>], precond: Option>, postcond_checker: &'hir rustc_hir::Expr<'hir>, ) -> &'hir rustc_hir::Expr<'hir> { - let stmts = self.arena.alloc_from_iter(precond.into_iter()); + 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, diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index 118efd15412e6..52ddfbaa99f9e 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -17,7 +17,7 @@ impl AttrProcMacro for ExpandRequires { annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_requires_tts(ecx, span, annotation, annotated) + expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractRequires) } } @@ -29,7 +29,7 @@ impl AttrProcMacro for ExpandEnsures { annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_ensures_tts(ecx, span, annotation, annotated) + expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractEnsures) } } @@ -130,42 +130,17 @@ fn expand_contract_clause( Ok(new_tts) } -fn expand_requires_tts( +fn expand_contract_clause_tts( ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, + clause_keyword: rustc_span::Symbol, ) -> Result { let feature_span = ecx.with_def_site_ctxt(attr_span); expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), - Spacing::Joint, - )); - new_tts.push_tree(TokenTree::Token( - token::Token::new(token::TokenKind::OrOr, attr_span), - Spacing::Alone, - )); - new_tts.push_tree(TokenTree::Delimited( - DelimSpan::from_single(attr_span), - DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden), - token::Delimiter::Brace, - annotation, - )); - Ok(()) - }) -} - -fn expand_ensures_tts( - ecx: &mut ExtCtxt<'_>, - attr_span: Span, - annotation: TokenStream, - annotated: TokenStream, -) -> Result { - let feature_span = ecx.with_def_site_ctxt(attr_span); - expand_contract_clause(ecx, attr_span, annotated, |new_tts| { - new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), + token::Token::from_ast_ident(Ident::new(clause_keyword, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Delimited( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 57bd0d500d5af..e7c89f0796224 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4036,6 +4036,30 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } + pub(crate) fn mk_unit_expr(&self, span: Span) -> Box { + 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 eb684c3a62f9f..2c76c0fe3583c 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -312,25 +312,48 @@ impl<'a> Parser<'a> { /// Parses an experimental fn contract /// (`contract_requires(WWW) contract_ensures(ZZZ)`) pub(super) fn parse_contract(&mut self) -> PResult<'a, Option>> { - let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { + let (declarations, requires) = self.parse_contract_requires()?; + let ensures = self.parse_contract_ensures()?; + + if requires.is_none() && ensures.is_none() { + Ok(None) + } else { + Ok(Some(Box::new(ast::FnContract { declarations, requires, ensures }))) + } + } + + fn parse_contract_requires( + &mut self, + ) -> PResult<'a, (ThinVec, Option>)> { + Ok(if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); - let precond = self.parse_expr()?; - Some(precond) + let mut decls_and_precond = self.parse_block()?; + + let precond = match decls_and_precond.stmts.pop() { + Some(precond) => match precond.kind { + rustc_ast::StmtKind::Expr(expr) => expr, + // Insert dummy node that will be rejected by typechecker to + // avoid reinventing an error + _ => self.mk_unit_expr(decls_and_precond.span), + }, + 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 { - None - }; - let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { + (Default::default(), None) + }) + } + + fn parse_contract_ensures(&mut self) -> PResult<'a, Option>> { + Ok(if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let postcond = self.parse_expr()?; Some(postcond) } else { None - }; - if requires.is_none() && ensures.is_none() { - Ok(None) - } else { - Ok(Some(Box::new(ast::FnContract { requires, ensures }))) - } + }) } /// Parses an optional where-clause. diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs new file mode 100644 index 0000000000000..fc07729e9132b --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs @@ -0,0 +1,17 @@ +//@ run-pass +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::requires; + +#[requires(*x = 0; 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.stderr b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr new file mode 100644 index 0000000000000..4c8a125384334 --- /dev/null +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contracts-disabled-side-effect-declarations.rs:2:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs index d234acb8268a1..a3a77b0de9a2b 100644 --- a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs @@ -5,7 +5,7 @@ extern crate core; use core::contracts::ensures; -#[ensures({*x = 0; |_ret| true})] +#[ensures(*x = 0; |_ret| true)] fn buggy_add(x: &mut u32, y: u32) { *x = *x + y; } diff --git a/tests/ui/contracts/declared-vars-referring-to-params.rs b/tests/ui/contracts/declared-vars-referring-to-params.rs new file mode 100644 index 0000000000000..52885da048e20 --- /dev/null +++ b/tests/ui/contracts/declared-vars-referring-to-params.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::{ensures, requires}; + +// checks that variable declarations are lowered properly, with the ability to +// access function parameters +#[requires(let y = 2 * x; true)] +#[ensures(move |ret| { *ret == y })] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/declared-vars-referring-to-params.stderr b/tests/ui/contracts/declared-vars-referring-to-params.stderr new file mode 100644 index 0000000000000..0ad9064e8606b --- /dev/null +++ b/tests/ui/contracts/declared-vars-referring-to-params.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/declared-vars-referring-to-params.rs:3:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.rs b/tests/ui/contracts/declared-vars-used-in-ensures.rs new file mode 100644 index 0000000000000..9703709e2b8e0 --- /dev/null +++ b/tests/ui/contracts/declared-vars-used-in-ensures.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::{ensures, requires}; + +#[requires(let y = 1; true)] +#[ensures(move |_ret| { y == 1 })] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-ensures.stderr new file mode 100644 index 0000000000000..000a1b239932c --- /dev/null +++ b/tests/ui/contracts/declared-vars-used-in-ensures.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/declared-vars-used-in-ensures.rs:3:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs new file mode 100644 index 0000000000000..e066a95314a98 --- /dev/null +++ b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::{ensures, requires}; + +// checks that variable declarations are lowered properly, with the ability to +// refer to them *both* in requires and ensures +#[requires(let y = 2 * x; y > 0)] +#[ensures(move |ret| { *ret == y })] +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr new file mode 100644 index 0000000000000..52b163553fba9 --- /dev/null +++ b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/declared-vars-used-in-requires-and-ensures.rs:3:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs index 4da0480f8bc10..faf0d80adaf31 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs @@ -19,8 +19,8 @@ #![feature(contracts_internals)] fn nest(x: Baz) -> i32 - contract_requires(|| x.baz > 0) - contract_ensures(|ret| *ret > 100) + contract_requires { x.baz > 0 } + contract_ensures { |ret| *ret > 100 } { loop { return x.baz + 50; diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs index f3cf5ce082c03..8095bdd2978be 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs @@ -19,8 +19,8 @@ #![feature(contracts_internals)] fn tail(x: Baz) -> i32 - contract_requires(|| x.baz > 0) - contract_ensures(|ret| *ret > 100) + contract_requires { x.baz > 0 } + contract_ensures { |ret| *ret > 100 } { x.baz + 50 } diff --git a/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs b/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs index 960ccaed3588a..6dd1fae5615a6 100644 --- a/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs +++ b/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs @@ -3,7 +3,7 @@ #![feature(contracts_internals)] fn outer() -> i32 - contract_ensures(|ret| *ret > 0) + contract_ensures { |ret| *ret > 0 } { let inner_closure = || -> i32 { 0 }; inner_closure(); diff --git a/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs b/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs index bee703de16a0b..42c665694e7ab 100644 --- a/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs +++ b/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs @@ -5,7 +5,7 @@ struct Outer { outer: std::cell::Cell } fn outer(x: Outer) - contract_requires(|| x.outer.get() > 0) + contract_requires { x.outer.get() > 0 } { let inner_closure = || { }; x.outer.set(0); diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs index 48bd376594f22..9d3765bc228db 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs @@ -11,8 +11,8 @@ fn main() { //~^ ERROR use of unstable library feature `contracts_internals` // ast extensions are guarded by contracts_internals feature gate - fn identity_1() -> i32 contract_requires(|| true) { 10 } + fn identity_1() -> i32 contract_requires { true } { 10 } //~^ ERROR contract internal machinery is for internal use only - fn identity_2() -> i32 contract_ensures(|_| true) { 10 } + fn identity_2() -> i32 contract_ensures { |_| true } { 10 } //~^ ERROR contract internal machinery is for internal use only } diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index c1318fc15a78d..0010fca2f96c5 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -1,7 +1,7 @@ error[E0658]: contract internal machinery is for internal use only --> $DIR/internal-feature-gating.rs:14:28 | -LL | fn identity_1() -> i32 contract_requires(|| true) { 10 } +LL | fn identity_1() -> i32 contract_requires { true } { 10 } | ^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information @@ -11,7 +11,7 @@ LL | fn identity_1() -> i32 contract_requires(|| true) { 10 } error[E0658]: contract internal machinery is for internal use only --> $DIR/internal-feature-gating.rs:16:28 | -LL | fn identity_2() -> i32 contract_ensures(|_| true) { 10 } +LL | fn identity_2() -> i32 contract_ensures { |_| true } { 10 } | ^^^^^^^^^^^^^^^^ | = 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 new file mode 100644 index 0000000000000..9160517a79322 --- /dev/null +++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs @@ -0,0 +1,24 @@ +//@ run-pass +#![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; + +// we check here if the "lowered" program behaves as expected before +// implementing the actual lowering in the compiler + +fn foo(x: u32) -> u32 { + let post = { + let y = 2 * x; + // 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)) + }; + + core::intrinsics::contract_check_ensures(post, { 2 * x }) +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.stderr b/tests/ui/contracts/internal_machinery/lowering/basics.stderr new file mode 100644 index 0000000000000..118229694a906 --- /dev/null +++ b/tests/ui/contracts/internal_machinery/lowering/basics.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basics.rs:2:12 + | +LL | #![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.rs b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs new file mode 100644 index 0000000000000..d0b3ed661ed69 --- /dev/null +++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs @@ -0,0 +1,18 @@ +//@ dont-require-annotations: NOTE +//@ compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::requires; + +#[requires(true;)] +//~^ ERROR mismatched types [E0308] +//~| NOTE expected `bool`, found `()` +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr new file mode 100644 index 0000000000000..fd38fa4edcf51 --- /dev/null +++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr @@ -0,0 +1,18 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/requires-bool-expr-with-semicolon.rs:3:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/requires-bool-expr-with-semicolon.rs:9:1 + | +LL | #[requires(true;)] + | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/contracts/requires-no-final-expression.rs b/tests/ui/contracts/requires-no-final-expression.rs new file mode 100644 index 0000000000000..474b29d63ba61 --- /dev/null +++ b/tests/ui/contracts/requires-no-final-expression.rs @@ -0,0 +1,18 @@ +//@ dont-require-annotations: NOTE +//@ compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::requires; + +#[requires(let y = 1;)] +//~^ ERROR mismatched types [E0308] +//~| NOTE expected `bool`, found `()` +fn foo(x: u32) -> u32 { + x * 2 +} + +fn main() { + foo(1); +} diff --git a/tests/ui/contracts/requires-no-final-expression.stderr b/tests/ui/contracts/requires-no-final-expression.stderr new file mode 100644 index 0000000000000..0db1648573945 --- /dev/null +++ b/tests/ui/contracts/requires-no-final-expression.stderr @@ -0,0 +1,18 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/requires-no-final-expression.rs:3:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/requires-no-final-expression.rs:9:1 + | +LL | #[requires(let y = 1;)] + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`.