diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 937031324f57f..080449c4fef10 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3246,11 +3246,19 @@ pub struct Impl {
     pub items: ThinVec<P<AssocItem>>,
 }
 
+#[derive(Clone, Encodable, Decodable, Debug, Default)]
+pub struct FnContract {
+    pub requires: Option<P<Expr>>,
+    pub captures: Vec<(Ident, P<Expr>)>,
+    pub ensures: Option<P<Expr>>,
+}
+
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Fn {
     pub defaultness: Defaultness,
     pub generics: Generics,
     pub sig: FnSig,
+    pub contract: Option<P<FnContract>>,
     pub body: Option<P<Block>>,
 }
 
@@ -3548,7 +3556,7 @@ mod size_asserts {
     static_assert_size!(Block, 32);
     static_assert_size!(Expr, 72);
     static_assert_size!(ExprKind, 40);
-    static_assert_size!(Fn, 160);
+    static_assert_size!(Fn, 168);
     static_assert_size!(ForeignItem, 88);
     static_assert_size!(ForeignItemKind, 16);
     static_assert_size!(GenericArg, 24);
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 1a7da46913d7e..90cfc17b52232 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -119,6 +119,10 @@ pub trait MutVisitor: Sized {
         walk_flat_map_item(self, i)
     }
 
+    fn visit_contract(&mut self, c: &mut P<FnContract>) {
+	walk_contract(self, c);
+    }
+
     fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
         walk_fn_decl(self, d);
     }
@@ -898,6 +902,20 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
     }
 }
 
+fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut P<FnContract>) {
+    let FnContract { requires, captures, ensures } = contract.deref_mut();
+    if let Some(pred) = requires {
+	vis.visit_expr(pred);
+    }
+    for (ident, expr) in captures.iter_mut() {
+	vis.visit_ident(ident);
+	vis.visit_expr(expr);
+    }
+    if let Some(pred) = ensures {
+	vis.visit_expr(pred);
+    }
+}
+
 fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
     let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
@@ -1100,8 +1118,9 @@ impl WalkItemKind for ItemKind {
             ItemKind::Const(item) => {
                 visit_const_item(item, vis);
             }
-            ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+            ItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => {
                 visit_defaultness(vis, defaultness);
+		if let Some(contract) = contract { vis.visit_contract(contract)};
                 vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             ItemKind::Mod(safety, mod_kind) => {
@@ -1206,8 +1225,9 @@ impl WalkItemKind for AssocItemKind {
             AssocItemKind::Const(item) => {
                 visit_const_item(item, visitor);
             }
-            AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+            AssocItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => {
                 visit_defaultness(visitor, defaultness);
+		if let Some(contract) = contract { visitor.visit_contract(contract); }
                 visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             AssocItemKind::Type(box TyAlias {
@@ -1311,8 +1331,9 @@ impl WalkItemKind for ForeignItemKind {
                 visitor.visit_ty(ty);
                 visit_opt(expr, |expr| visitor.visit_expr(expr));
             }
-            ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+            ForeignItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => {
                 visit_defaultness(visitor, defaultness);
+		if let Some(contract) = contract { visitor.visit_contract(contract); }
                 visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             ForeignItemKind::TyAlias(box TyAlias {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 4dcadb8517eb4..06ab8654344c9 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -66,7 +66,7 @@ impl BoundKind {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
+    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a FnContract>, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
     Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
@@ -75,7 +75,7 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
-            FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
+            FnKind::Fn(_, _, sig, _, _, _, _) => Some(&sig.header),
             FnKind::Closure(..) => None,
         }
     }
@@ -89,7 +89,7 @@ impl<'a> FnKind<'a> {
 
     pub fn decl(&self) -> &'a FnDecl {
         match self {
-            FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
+            FnKind::Fn(_, _, sig, _, _, _, _) => &sig.decl,
             FnKind::Closure(_, _, decl, _) => decl,
         }
     }
@@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result {
         walk_closure_binder(self, b)
     }
+    fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result {
+	walk_contract(self, c)
+    }
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
         walk_where_predicate(self, p)
     }
@@ -359,8 +362,10 @@ impl WalkItemKind for ItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
+            ItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => 
+
+{
+                let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, contract.as_deref(), body.as_deref());
                 try_visit!(visitor.visit_fn(kind, *span, *id));
             }
             ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
@@ -695,8 +700,8 @@ impl WalkItemKind for ForeignItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
+            ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => {
+                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, contract.as_deref(), body.as_deref());
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ForeignItemKind::TyAlias(box TyAlias {
@@ -784,6 +789,21 @@ pub fn walk_closure_binder<'a, V: Visitor<'a>>(
     V::Result::output()
 }
 
+pub fn walk_contract<'a, V:Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result {
+    let FnContract { requires, captures, ensures } = c;
+    if let Some(pred) = requires {
+	visitor.visit_expr(pred);
+    }
+    for (ident, expr) in captures {
+	visitor.visit_ident(*ident);
+	visitor.visit_expr(expr);
+    }
+    if let Some(pred) = ensures {
+	visitor.visit_expr(pred);
+    }
+    V::Result::output()
+}
+
 pub fn walk_where_predicate<'a, V: Visitor<'a>>(
     visitor: &mut V,
     predicate: &'a WherePredicate,
@@ -829,11 +849,12 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(
 
 pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result {
     match kind {
-        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => {
+        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, contract, body) => {
             // Identifier and visibility are visited as a part of the item.
             try_visit!(visitor.visit_fn_header(header));
             try_visit!(visitor.visit_generics(generics));
             try_visit!(walk_fn_decl(visitor, decl));
+	    visit_opt!(visitor, visit_contract, contract);
             visit_opt!(visitor, visit_block, body);
         }
         FnKind::Closure(binder, _coroutine_kind, decl, body) => {
@@ -859,9 +880,9 @@ impl WalkItemKind for AssocItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
+            AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => {
                 let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, contract.as_deref(), body.as_deref());
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             AssocItemKind::Type(box TyAlias {
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 3b85f1737bdd9..5199b2205bfe9 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -205,7 +205,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 abi: sig.abi,
             }
         };
-        hir::FnSig { decl, header, span }
+        hir::FnSig { decl, header, span, contract_info: None }
     }
 
     fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
@@ -376,7 +376,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         });
 
         let header = self.generate_header_error();
-        let sig = hir::FnSig { decl, header, span };
+        let sig = hir::FnSig { decl, header, span, contract_info: None };
 
         let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span)));
         DelegationResults { generics, body_id, sig }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 52372bbf991c9..4fe924aad8a2c 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2035,7 +2035,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.arena.alloc(self.expr_call_mut(span, e, args))
     }
 
-    fn expr_call_lang_item_fn_mut(
+    pub(super) fn expr_call_lang_item_fn_mut(
         &mut self,
         span: Span,
         lang_item: hir::LangItem,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1273b50dff816..c1e28660408d1 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -207,9 +207,159 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 sig: FnSig { decl, header, span: fn_sig_span },
                 generics,
                 body,
+                contract: _contract,
                 ..
             }) => {
-                self.with_new_scopes(*fn_sig_span, |this| {
+
+		// `fn foo<G, ...>(a: A, ...) -> RET requires(PRE) captures(o = OLD) ensures(|ret| POST) { ... }`
+		//
+		// ==>
+		//
+		// fn foo_with_contract<G, ...>(a: A, ...) -> RET {
+		//     check_requires(|| PRE); let o = OLD; let r = foo::<G, ...>(a, ...); check_ensures((|ret| POST)(&r)); r
+		// }
+		// fn foo<G, ...>(a: A, ...) -> RET { ... }
+		let _contract_ids = _contract
+		    .as_ref()
+		    .map(|_contract| {
+			let contract_node_id = self.next_node_id();
+			let contract_def_id = self.create_def(
+			    self.local_def_id(id),
+			    contract_node_id,
+			    kw::Empty,
+			    DefKind::Fn,
+			    *fn_sig_span,
+			);
+			let _lit_true = |this: &mut LoweringContext<'_, 'hir>| {
+			    this.expr(*fn_sig_span, hir::ExprKind::Lit(this.arena.alloc(hir::Lit {
+				span: *fn_sig_span,
+				node: ast::LitKind::Bool(true),
+			    })))
+			};
+			let lit_unit = |this: &mut LoweringContext<'_, 'hir>| {
+			    this.expr(*fn_sig_span, hir::ExprKind::Tup(&[]))
+			};
+
+			let contract_ast_fn_decl = {
+			    let inputs = decl.inputs.clone();
+			    FnDecl {
+				inputs,
+				// FIXME: at some point the wrapper should call
+				// to the wrapped function (perhaps passed as
+				// a parameter) and return its result. But
+				// lets hold off on that for now.
+				output: FnRetTy::Default(*fn_sig_span),
+			    }
+			};
+
+			let contract_hir_fn_decl = self.lower_fn_decl(
+			    &contract_ast_fn_decl,
+			    id,
+			    *fn_sig_span,
+			    FnDeclKind::Fn,
+			    None,
+			);
+								      
+			let contract_body_id = self.lower_fn_body(&contract_ast_fn_decl, |this| {
+			    // rustc_contract_requires(|| PRECOND);
+			    // let o = OLD;
+			    // let r = the_real_thing();
+			    // rustc_contract_ensures(o, r, |o, r| POSTCOND);
+			    // r
+
+			    // lit_true(this)
+			    lit_unit(this)
+			});
+			(contract_def_id, contract_hir_fn_decl, contract_body_id)
+		    });
+
+/*
+		let _contract_id = _contract.as_ref().map(|contract| {
+		    let body_id = self.with_new_scopes(*fn_sig_span, |this| {
+			this.lower_fn_body(decl, |this| {
+			    let lit_true = |this: &mut LoweringContext<'_, 'hir>| {
+				this.expr(*fn_sig_span, hir::ExprKind::Lit(this.arena.alloc(hir::Lit {
+				    span: *fn_sig_span,
+				    node: ast::LitKind::Bool(true),
+				})))
+			    };
+			    let req = if let Some(req) = &contract.requires {
+				this.lower_expr_mut(req)
+			    } else {
+				lit_true(this)
+			    };
+			    let _precond = this.arena.alloc(this.expr_call_lang_item_fn_mut(
+				req.span,
+				hir::LangItem::ContractCheckRequires,
+				arena_vec![this; req], // FIXME: needs to build closure around `req`
+			    ));
+
+			    // FIXME: need to construct `let o = OLD` and the inner call still.
+
+			    // FIXME: need to construct `let r = foo::<G, ...>(a, ...);`
+
+			    let _postcond = {
+				let ens = if let Some(ens) = &contract.ensures {
+				    this.lower_expr_mut(ens)
+				} else {
+				    lit_true(this) // FIXME: needs to build closure of `|old, ret| true` instead
+				};
+				this.arena.alloc(this.expr_call_lang_item_fn_mut(
+				    ens.span,
+				    hir::LangItem::ContractCheckEnsures,
+				    arena_vec![self; ens],
+				))
+			    };
+
+			    let contract_span = Span::new(
+				std::cmp::min(_precond.span.lo(), _postcond.span.lo()),
+				std::cmp::max(_precond.span.hi(), _postcond.span.hi()),
+				// FIXME: should this computed/inherited from the
+				// contexts attached to precond and postcond?
+				rustc_span::SyntaxContext::root(),
+				None,
+			    );
+            
+			    tracing::debug!("_precond: {:?}", &_precond);
+			    tracing::debug!("_postcond: {:?}", &_postcond);
+			    tracing::debug!("contract_span: {:?}", &contract_span);
+			    let _precond_span = _precond.span;
+			    let _precond = hir::StmtKind::Expr(_precond);
+			    let _postcond_span = _postcond.span;
+			    let _postcond = hir::StmtKind::Expr(_postcond);
+
+			    let stmts =
+				arena_vec![
+				    this;
+				    this.stmt(_precond_span, _precond),
+				    this.stmt(_postcond_span, _postcond)
+				];
+
+			    let block = this.block_all(
+				contract_span,
+				stmts,
+				None, // FIXME: this needs to be returning the let-bound `r` that holds the value returned by the wrapped call.
+			    );
+			    let block = hir::ExprKind::Block(block, None);
+			    let block = this.expr(contract_span, block);
+			    block
+			})
+			    
+			// let contract_body: hir::Body = unimplemented!();
+
+			// this.lower_maybe_coroutine_body(*fn_sig_span, , contract_span, fn_id, decl.clone(), None, body)
+
+		    });
+
+		    tracing::debug!("body_id: {:?}", body_id);
+		    body_id
+		});
+		 */
+
+		tracing::debug!("_contract_ids: {:?}", _contract_ids);
+
+	    
+                let fn_item = self.with_new_scopes(*fn_sig_span, |this| {
                     // Note: we don't need to change the return type from `T` to
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
@@ -235,14 +385,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                 coroutine_kind,
                             )
                         });
+		    let contract_info: Option<hir::FnContractInfo<'_>> = _contract_ids.map(|(_, wrapper_decl, wrapper_body_id)| hir::FnContractInfo { wrapper_decl, wrapper_body_id } );
                     let sig = hir::FnSig {
                         decl,
                         header: this.lower_fn_header(*header, hir::Safety::Safe),
                         span: this.lower_span(*fn_sig_span),
+			contract_info,
                     };
                     hir::ItemKind::Fn(sig, generics, body_id)
-                })
-            }
+                });
+
+		fn_item
+	    }
             ItemKind::Mod(_, mod_kind) => match mod_kind {
                 ModKind::Loaded(items, _, spans) => {
                     hir::ItemKind::Mod(self.lower_mod(items, spans))
@@ -253,7 +407,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 abi: fm.abi.map_or(abi::Abi::FALLBACK, |abi| self.lower_abi(abi)),
                 items: self
                     .arena
-                    .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
+		    .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
             },
             ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
             ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
@@ -681,7 +835,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe);
 
                     hir::ForeignItemKind::Fn(
-                        hir::FnSig { header, decl, span: self.lower_span(sig.span) },
+                        hir::FnSig { header, decl, span: self.lower_span(sig.span), opt_contract_id: None },
                         fn_args,
                         generics,
                     )
@@ -1382,7 +1536,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| {
                 this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
             });
-        (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
+        (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span), opt_contract_id: None })
     }
 
     pub(super) fn lower_fn_header(
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 87e3a6871b9e1..5b6de03972920 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -961,7 +961,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
             }
-            ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
+            ItemKind::Fn(box Fn { defaultness, sig, generics, contract, body }) => {
                 self.check_defaultness(item.span, *defaultness);
 
                 if body.is_none() {
@@ -990,7 +990,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
                 let kind =
-                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
+                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, contract.as_deref(), body.as_deref());
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1396,13 +1396,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             _,
             _,
             _,
+	    _,
         ) = fk
         {
             self.maybe_lint_missing_abi(*sig_span, id);
         }
 
         // Functions without bodies cannot have patterns.
-        if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
+        if let FnKind::Fn(ctxt, _, sig, _, _, _, None) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
                     if let Some(ident) = ident {
@@ -1436,7 +1437,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         .is_some();
 
         let disallowed = (!tilde_const_allowed).then(|| match fk {
-            FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
+            FnKind::Fn(_, ident, _, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
             FnKind::Closure(..) => TildeConstReason::Closure,
         });
         self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
@@ -1512,7 +1513,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
 
         match &item.kind {
-            AssocItemKind::Fn(box Fn { sig, generics, body, .. })
+            AssocItemKind::Fn(box Fn { sig, generics, contract, body, .. })
                 if parent_is_const
                     || ctxt == AssocCtxt::Trait
                     || matches!(sig.header.constness, Const::Yes(_)) =>
@@ -1525,6 +1526,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     sig,
                     &item.vis,
                     generics,
+		    contract.as_deref(),
                     body.as_deref(),
                 );
                 walk_list!(self, visit_attribute, &item.attrs);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 8217b6df5b470..8ae62da7df0eb 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -34,8 +34,8 @@ impl<'a> State<'a> {
         self.maybe_print_comment(span.lo());
         self.print_outer_attributes(attrs);
         match kind {
-            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, contract.as_deref(), body.as_deref(), attrs);
             }
             ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => {
                 self.print_safety(*safety);
@@ -195,13 +195,14 @@ impl<'a> State<'a> {
                     *defaultness,
                 );
             }
-            ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+            ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => {
                 self.print_fn_full(
                     sig,
                     item.ident,
                     generics,
                     &item.vis,
                     *defaultness,
+		    contract.as_deref(),
                     body.as_deref(),
                     &item.attrs,
                 );
@@ -538,8 +539,8 @@ impl<'a> State<'a> {
         self.maybe_print_comment(span.lo());
         self.print_outer_attributes(attrs);
         match kind {
-            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, contract.as_deref(), body.as_deref(), attrs);
             }
             ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
                 self.print_item_const(
@@ -653,6 +654,7 @@ impl<'a> State<'a> {
         generics: &ast::Generics,
         vis: &ast::Visibility,
         defaultness: ast::Defaultness,
+	contract: Option<&ast::FnContract>,
         body: Option<&ast::Block>,
         attrs: &[ast::Attribute],
     ) {
@@ -662,6 +664,10 @@ impl<'a> State<'a> {
         self.print_visibility(vis);
         self.print_defaultness(defaultness);
         self.print_fn(&sig.decl, sig.header, Some(name), generics);
+	if let Some(contract) = contract {
+            self.nbsp();
+	    self.print_contract(contract);
+	}
         if let Some(body) = body {
             self.nbsp();
             self.print_block_with_attrs(body, attrs);
@@ -670,6 +676,29 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_contract(&mut self, contract: &ast::FnContract) {
+	if let Some(pred) = &contract.requires {
+	    self.word("rustc_requires");
+	    self.popen();
+	    self.print_expr(pred, FixupContext::default());
+	    self.pclose();
+	}
+	for (ident, expr) in &contract.captures {
+	    self.word("rustc_captures");
+	    self.popen();
+	    self.print_ident(*ident);
+	    self.word_space("=");
+	    self.print_expr(expr, FixupContext::default());
+	    self.pclose();
+	}
+	if let Some(pred) = &contract.ensures {
+	    self.word("rustc_ensures");
+	    self.popen();
+	    self.print_expr(pred, FixupContext::default());
+	    self.pclose();
+	}
+    }
+
     pub(crate) fn print_fn(
         &mut self,
         decl: &ast::FnDecl,
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 0caad997b9df1..ba9730d72edde 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -86,6 +86,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
         defaultness: ast::Defaultness::Final,
         sig,
         generics: Generics::default(),
+	contract: None,
         body,
     }));
 
diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs
new file mode 100644
index 0000000000000..8dc0579e7dd5d
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/contracts.rs
@@ -0,0 +1,156 @@
+#![allow(unused_imports, unused_variables)]
+
+use rustc_ast::token;
+use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_errors::ErrorGuaranteed;
+use rustc_expand::base::{AttrProcMacro, ExtCtxt};
+use rustc_span::symbol::{kw, Ident, sym, Symbol};
+use rustc_span::Span;
+
+pub(crate) struct ExpandRequires;
+
+pub(crate) struct ExpandCaptures;
+
+pub(crate) struct ExpandEnsures;
+
+impl AttrProcMacro for ExpandRequires {
+    fn expand<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt<'_>,
+        span: Span,
+        annotation: TokenStream,
+        annotated: TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        expand_requires_tts(ecx, span, annotation, annotated)
+    }
+}
+
+impl AttrProcMacro for ExpandCaptures {
+    fn expand<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt<'_>,
+        span: Span,
+        annotation: TokenStream,
+        annotated: TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        todo!()
+    }
+}
+
+impl AttrProcMacro for ExpandEnsures {
+    fn expand<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt<'_>,
+        span: Span,
+        annotation: TokenStream,
+        annotated: TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        todo!()
+    }
+}
+
+fn expand_injecting_circa_where_clause(
+    _ecx: &mut ExtCtxt<'_>,
+    attr_span: Span,
+    annotated: TokenStream,
+    inject: impl FnOnce(&mut Vec<TokenTree>) -> Result<(), ErrorGuaranteed>,
+) -> Result<TokenStream, ErrorGuaranteed> {
+    let mut new_tts = Vec::with_capacity(annotated.len());
+    let mut cursor = annotated.into_trees();
+
+    // Find the `fn name<G,...>(x:X,...)` and inject the AST contract forms right after
+    // the formal parameters (and return type if any).
+    while let Some(tt) = cursor.next_ref() {
+        new_tts.push(tt.clone());
+        if let TokenTree::Token(tok, _) = tt && tok.is_ident_named(kw::Fn) {
+            break;
+        }
+    }
+
+    // Found the `fn` keyword, now find the formal parameters.
+    //
+    // FIXME: can this fail if you have parentheticals in a generics list, like `fn foo<F: Fn(X) -> Y>` ?
+    while let Some(tt) = cursor.next_ref() {
+        new_tts.push(tt.clone());
+
+        if let TokenTree::Delimited(_, _, token::Delimiter::Parenthesis, _) = tt {
+            break;
+        }
+        if let TokenTree::Token(token::Token { kind: token::TokenKind::Semi, .. }, _) = tt {
+            panic!("contract attribute applied to fn without parameter list.");
+        }
+    }
+
+    // There *might* be a return type declaration (and figuring out where that ends would require parsing an arbitrary type expression, e.g. `-> Foo<args ...>`
+    //
+    // Instead of trying to figure that out, scan ahead and look for the first occurence of a `where`, a `{ ... }`, or a `;`.
+    //
+    // FIXME: this might still fall into a trap for something like `-> Ctor<T, const { 0 }>`. I
+    // *think* such cases must be under a Delimited (e.g. `[T; { N }]` or have the braced form
+    // prefixed by e.g. `const`, so we should still be able to filter them out without having to
+    // parse the type expression itself. But rather than try to fix things with hacks like that,
+    // time might be better spent extending the attribute expander to suport tt-annotation atop
+    // ast-annotated, which would be an elegant way to sidestep all of this.
+    let mut opt_next_tt = cursor.next_ref();
+    while let Some(next_tt) = opt_next_tt {
+        if let TokenTree::Token(tok, _) = next_tt && tok.is_ident_named(kw::Where) {
+            break;
+        }
+        if let TokenTree::Delimited(_, _, token::Delimiter::Brace, _) = next_tt {
+            break;
+        }
+        if let TokenTree::Token(token::Token { kind: token::TokenKind::Semi, .. }, _) = next_tt {
+            break;
+        }
+
+        // for anything else, transcribe the tt and keep looking.
+        new_tts.push(next_tt.clone());
+        opt_next_tt = cursor.next_ref();
+        continue;
+    }
+
+    // At this point, we've transcribed everything from the `fn` through the formal parameter
+    // list and return type declaration, (if any), but `tt` itself has *not* been transcribed.
+    //
+    // Now inject the AST contract form.
+    //
+    // FIXME: this kind of manual token tree munging does not have significant precedent among rustc
+    // builtin macros, probably because most builtin macros use direct AST manipulation to accomplish
+    // similar goals. But since our attributes need to take arbitrary expressions, and our attribute
+    // infrastructure does not yet support mixing a token-tree annotation with an AST annotated, we
+    // end up doing token tree manipulation.
+    inject(&mut new_tts)?;
+
+    // Above we injected the internal AST requires contruct. Now copy over all the other token trees.
+    if let Some(tt) = opt_next_tt {
+	new_tts.push(tt.clone());
+    }
+    while let Some(tt) = cursor.next_ref() {
+	new_tts.push(tt.clone());
+    }
+
+    Ok(TokenStream::new(new_tts))
+}
+
+fn expand_requires_tts(
+    _ecx: &mut ExtCtxt<'_>,
+    attr_span: Span,
+    annotation: TokenStream,
+    annotated: TokenStream,
+) -> Result<TokenStream, ErrorGuaranteed> {
+    expand_injecting_circa_where_clause(
+	_ecx,
+	attr_span,
+	annotated,
+	|new_tts| {
+            new_tts.push(TokenTree::Token(token::Token::from_ast_ident(Ident::new(kw::RustcContractRequires, attr_span)),
+					  Spacing::Joint));
+	    new_tts.push(TokenTree::Delimited(DelimSpan::from_single(attr_span),
+					      DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden),
+					      token::Delimiter::Parenthesis,
+					      annotation));
+	    Ok(())
+	},
+    )
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 82baaca9a4641..a34f39ac2b204 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1043,6 +1043,7 @@ impl<'a> MethodDef<'a> {
                 defaultness,
                 sig,
                 generics: fn_generics,
+		contract: None,
                 body: Some(body_block),
             })),
             tokens: None,
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index b4b18409a18eb..fd9ea73bcec64 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -82,6 +82,7 @@ impl AllocFnFactory<'_, '_> {
             defaultness: ast::Defaultness::Final,
             sig,
             generics: Generics::default(),
+	    contract: None,
             body,
         }));
         let item = self.cx.item(
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index ebe5e2b544292..3adc5805c6c71 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -36,6 +36,7 @@ mod compile_error;
 mod concat;
 mod concat_bytes;
 mod concat_idents;
+mod contracts;
 mod derive;
 mod deriving;
 mod edition_panic;
@@ -135,4 +136,10 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
 
     let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
     register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
+    let requires = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandRequires));
+    register(sym::contracts_requires, requires);
+    let captures = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandCaptures));
+    register(sym::contracts_captures, captures);
+    let ensures = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandEnsures));
+    register(sym::contracts_ensures, ensures);
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 953484533087c..733a81e622b7d 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
         defaultness,
         sig,
         generics: ast::Generics::default(),
+	contract: None,
         body: Some(main_body),
     }));
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2ef6fa53f4edd..fb8bc4bf04284 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2306,6 +2306,12 @@ pub struct MutTy<'hir> {
     pub mutbl: Mutability,
 }
 
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub struct FnContractInfo<'hir> {
+    pub wrapper_decl: &'hir FnDecl<'hir>,
+    pub wrapper_body_id: BodyId,
+}
+
 /// Represents a function's signature in a trait declaration,
 /// trait implementation, or a free function.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2313,6 +2319,8 @@ pub struct FnSig<'hir> {
     pub header: FnHeader,
     pub decl: &'hir FnDecl<'hir>,
     pub span: Span,
+    // FIXME: turn this into a reference to save space
+    pub contract_info: Option<FnContractInfo<'hir>>,
 }
 
 // The bodies for items are stored "out of line", in a separate
@@ -4082,16 +4090,16 @@ mod size_asserts {
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 48);
     static_assert_size!(FnDecl<'_>, 40);
-    static_assert_size!(ForeignItem<'_>, 88);
-    static_assert_size!(ForeignItemKind<'_>, 56);
+    static_assert_size!(ForeignItem<'_>, 104);
+    static_assert_size!(ForeignItemKind<'_>, 72);
     static_assert_size!(GenericArg<'_>, 16);
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
-    static_assert_size!(ImplItem<'_>, 88);
-    static_assert_size!(ImplItemKind<'_>, 40);
-    static_assert_size!(Item<'_>, 88);
-    static_assert_size!(ItemKind<'_>, 56);
+    static_assert_size!(ImplItem<'_>, 104);
+    static_assert_size!(ImplItemKind<'_>, 56);
+    static_assert_size!(Item<'_>, 96);
+    static_assert_size!(ItemKind<'_>, 64);
     static_assert_size!(LetStmt<'_>, 64);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
@@ -4102,8 +4110,8 @@ mod size_asserts {
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    static_assert_size!(TraitItem<'_>, 88);
-    static_assert_size!(TraitItemKind<'_>, 48);
+    static_assert_size!(TraitItem<'_>, 104);
+    static_assert_size!(TraitItemKind<'_>, 64);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 58916d0586593..85ddd3ec4745a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -514,6 +514,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Fn(ref sig, ref generics, body_id) => {
+	    if let Some(contract_info) = sig.contract_info {
+		try_visit!(visitor.visit_nested_body(contract_info.wrapper_body_id));
+	    }
             try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_fn(
                 FnKind::ItemFn(item.ident, generics, sig.header),
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b161e6ba0fa51..d204980a423ac 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -423,6 +423,10 @@ language_item_table! {
     EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
     EffectsCompat,           sym::EffectsCompat,       effects_compat,             Target::Trait,          GenericRequirement::Exact(1);
     EffectsTyCompat,         sym::EffectsTyCompat,     effects_ty_compat,          Target::Trait,          GenericRequirement::Exact(1);
+
+    ContractCheckCaptures,   sym::contract_check_captures, contract_check_captures_fn, Target::Fn, GenericRequirement::None;
+    ContractCheckEnsures,    sym::contract_check_ensures,  contract_check_ensures_fn,  Target::Fn, GenericRequirement::None;
+    ContractCheckRequires,   sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 06317a3b3049c..5570e4752af7e 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -2,7 +2,7 @@
 //! intrinsics that the compiler exposes.
 
 use rustc_errors::codes::*;
-use rustc_errors::{DiagMessage, struct_span_code_err};
+use rustc_errors::{struct_span_code_err, DiagMessage};
 use rustc_hir as hir;
 use rustc_middle::bug;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
@@ -145,6 +145,10 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::fmul_algebraic
         | sym::fdiv_algebraic
         | sym::frem_algebraic
+        | sym::contract_check_requires
+        | sym::contract_check_ensures
+        | sym::contract_check_requires_2
+        | sym::contract_check_ensures_2
         | sym::const_eval_select => hir::Safety::Safe,
         _ => hir::Safety::Unsafe,
     };
@@ -164,15 +168,24 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
 
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
-pub fn check_intrinsic_type(
-    tcx: TyCtxt<'_>,
+pub fn check_intrinsic_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
     intrinsic_id: LocalDefId,
     span: Span,
     intrinsic_name: Symbol,
     abi: Abi,
 ) {
+    // Note: generics_of will include the early-bound lifetimes
+    // (e.g. lifetimes that are referenced in where-clauses), but not
+    // late-bound lifetimes.
     let generics = tcx.generics_of(intrinsic_id);
-    let param = |n| {
+
+    let ref_early_lt_param = #[track_caller] |n: u32, payload_ty: Ty<'tcx>| {
+	let p = generics.param_at(n as usize, tcx);
+	let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
+        Ty::new_imm_ref(tcx, r, payload_ty)
+    };
+    let param = #[track_caller] |n| {
         if let &ty::GenericParamDef { name, kind: ty::GenericParamDefKind::Type { .. }, .. } =
             generics.param_at(n as usize, tcx)
         {
@@ -226,6 +239,43 @@ pub fn check_intrinsic_type(
             }
         };
         (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
+    } else if name_str.starts_with("contract_check") {
+	let (n_tps, n_lts, inputs, output) = match intrinsic_name {
+            // `requires::<C>(c)`, where c is `|| pred()`
+            sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit),
+            // `requires2::<Old, C, O>(c, o)`, where c is `|| pred()` and o is `|| make_old()`
+            sym::contract_check_requires_2 => (3, 0, vec![param(1), param(2)], param(0)),
+            // `ensures::<Ret, C>(ret, c)` where ret: &Ret and c is `|ret| pred(ret)`.
+            sym::contract_check_ensures => {
+		// variant with late bound lifetime
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
+		let ref_ret = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
+                (2, 0, vec![ref_ret, param(1)], tcx.types.unit)
+            }
+            // `ensures::<'a, Ret, C>(ret, c)` where ret: &'a Ret and c is `|ret| pred(ret)`.
+	    sym::contract_check_ensures_lt => {
+		// variant with early bound lifetime
+                let ref_ret = ref_early_lt_param(0, param(1));
+                (2, 1, vec![ref_ret, param(2)], tcx.types.unit)
+            }
+            // `ensures2::<'r, Old, Ret, C>(old, ret, c)` where old: Old, ret: &'r Ret and c is `|old, ret| pred(old, ret)`
+            sym::contract_check_ensures_2 => {
+		// variant with late bound lifetime
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
+		let ref_ret = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(1));
+                (3, 0, vec![param(0), ref_ret, param(2)], tcx.types.unit)
+            }
+            sym::contract_check_ensures_lt_2 => {
+		// variant with early bound lifetime
+                let ref_ret = ref_early_lt_param(0, param(2));
+                (3, 1, vec![param(1), ref_ret, param(3)], tcx.types.unit)
+            }
+            other => {
+                tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
+                return;
+            }
+        };
+        (n_tps, n_lts, 0, inputs, output, hir::Safety::Safe)
     } else {
         let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
         let (n_tps, n_cts, inputs, output) = match intrinsic_name {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index f63e2d40e3906..105ecf6096bdc 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1338,7 +1338,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
         }
 
         TraitItem(hir::TraitItem {
-            kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
+            kind: TraitItemKind::Fn(FnSig { header, decl, span: _, opt_contract_id: _ }, _),
             generics,
             ..
         }) => {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 71ee77f8f6172..55f8d0ba44bb6 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -62,12 +62,14 @@ This API is completely unstable and subject to change.
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
+#![feature(closure_track_caller)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustdoc_internals)]
 #![feature(slice_partition_dedup)]
+#![feature(stmt_expr_attributes)]
 #![feature(try_blocks)]
 #![feature(unwrap_infallible)]
 #![warn(unreachable_pub)]
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6b0a897faba94..2bf3b4aa7258e 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -148,7 +148,7 @@ fn typeck_with_fallback<'tcx>(
     }
     let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
 
-    if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
+    if let Some(hir::FnSig { header, decl, opt_contract_id, .. }) = node.fn_sig() {
         let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
             fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl, None, None)
         } else {
@@ -161,6 +161,13 @@ fn typeck_with_fallback<'tcx>(
         let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
         let fn_sig = fcx.normalize(body.value.span, fn_sig);
 
+	if let Some(contract_id) = opt_contract_id {
+	    let contract_body = tcx.hir().body(*contract_id);
+	    // FIXME probably need to create a distinct fn_sig.
+	    check_fn(&mut fcx, fn_sig, None, decl, def_id, contract_body, tcx.features().unsized_fn_params);
+	}
+	
+
         check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params);
     } else {
         let expected_type = infer_type_if_missing(&fcx, node);
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8bd9c899a6286..fd127d57eb6b6 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -349,6 +349,7 @@ impl EarlyLintPass for UnsafeCode {
             ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
             _,
             _,
+	    _,
             body,
         ) = fk
         {
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 2285877c9ef26..3f8f5e7ef8bde 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -157,7 +157,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
 
         // Explicitly check for lints associated with 'closure_id', since
         // it does not have a corresponding AST node
-        if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
+        if let ast_visit::FnKind::Fn(_, _, sig, _, _, _, _) = fk {
             if let Some(coroutine_kind) = sig.header.coroutine_kind {
                 self.check_id(coroutine_kind.closure_id());
             }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 660686f4aa280..a8872be6264a9 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -228,9 +228,14 @@ impl<'tcx> Generics {
     }
 
     /// Returns the `GenericParamDef` with the given index.
+    #[track_caller]
     pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
         if let Some(index) = param_index.checked_sub(self.parent_count) {
-            &self.own_params[index]
+            &self.own_params.get(index)
+		.unwrap_or_else(#[track_caller] || {
+		    panic!("expected generic at own_params[index] but index is {index} and own_params are {:?}",
+			   &self.own_params)
+		})
         } else {
             tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
                 .param_at(param_index, tcx)
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 5aebe716b0a10..e8a8a3dd87f9f 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -295,6 +295,36 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parses an optional fn contract (`requires(WWW) captures(X = YYY) ensures(ZZZ)`)
+    pub(super) fn parse_contract(&mut self) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> {
+	let pre_cond = if self.eat_keyword(kw::RustcContractRequires) {
+	    Some(self.parse_expr()?)
+	} else {
+	    None
+	};
+	let captures = if self.eat_keyword(kw::RustcContractCaptures) {
+	    let ident = self.parse_ident()?;
+	    if self.eat(&token::Eq) {
+		vec![(ident, self.parse_expr()?)]
+	    } else {
+		// FIXME: replace this with a proper parse error.
+		panic!("Malformed captures clause on contract");
+	    }
+	} else {
+	    vec![]
+	};
+	let post_cond = if self.eat_keyword(kw::RustcContractEnsures) {
+	    Some(self.parse_expr()?)
+	} else {
+	    None
+	};
+	if pre_cond.is_none() && captures.is_empty() && post_cond.is_none() {
+	    Ok(None)
+	} else {
+	    Ok(Some(rustc_ast::ptr::P(ast::FnContract { requires: pre_cond, captures, ensures: post_cond })))
+	}
+    }
+
     /// Parses an optional where-clause.
     ///
     /// ```ignore (only-for-syntax-highlight)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 36733726564fb..b9ac5fb0ee1d3 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -197,9 +197,9 @@ impl<'a> Parser<'a> {
             self.parse_use_item()?
         } else if self.check_fn_front_matter(check_pub, case) {
             // FUNCTION ITEM
-            let (ident, sig, generics, body) =
+            let (ident, sig, generics, contract, body) =
                 self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
-            (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
+            (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })))
         } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
                 // EXTERN CRATE
@@ -2312,7 +2312,7 @@ impl<'a> Parser<'a> {
         sig_lo: Span,
         vis: &Visibility,
         case: Case,
-    ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
+    ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> {
         let fn_span = self.token.span;
         let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
@@ -2338,6 +2338,8 @@ impl<'a> Parser<'a> {
         // inside `parse_fn_body()`.
         let fn_params_end = self.prev_token.span.shrink_to_hi();
 
+	let contract = self.parse_contract()?;
+
         generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
 
         // `fn_params_end` is needed only when it's followed by a where clause.
@@ -2349,7 +2351,7 @@ impl<'a> Parser<'a> {
         let body =
             self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
         let fn_sig_span = sig_lo.to(sig_hi);
-        Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
+        Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, contract, body))
     }
 
     /// Provide diagnostics when function body is not found
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index f3174e7dea2d8..4ce683a750561 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -31,7 +31,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
     // Check input tokens for built-in and key-value attributes.
     match attr_info {
         // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
-        Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
+        Some(BuiltinAttribute { name, template, .. }) if input_restricted_by_parser(*name) => {
             match parse_meta(psess, attr) {
                 // Don't check safety again, we just did that
                 Ok(meta) => {
@@ -56,6 +56,10 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
     }
 }
 
+fn input_restricted_by_parser(name: Symbol) -> bool {
+    name != sym::rustc_dummy && name != sym::contracts_requires
+}
+
 pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
     let item = attr.get_normal_item();
     Ok(MetaItem {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 0047f2c4b51e9..dd5bde59dc0d3 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -240,11 +240,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         match fn_kind {
-            FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
+            FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, contract, body)
                 if let Some(coroutine_kind) = header.coroutine_kind =>
             {
                 self.visit_fn_header(header);
                 self.visit_generics(generics);
+		if let Some(contract) = contract { self.visit_contract(contract); }
 
                 // For async functions, we need to create their inner defs inside of a
                 // closure to match their desugared representation. Besides that,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 66c1ff93ce1ce..8aefb3d4afa0f 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -961,8 +961,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
         match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
-            FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
-            | FnKind::Fn(_, _, sig, _, generics, None) => {
+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _, _)
+            | FnKind::Fn(_, _, sig, _, generics, _, None) => {
                 self.visit_fn_header(&sig.header);
                 self.visit_generics(generics);
                 self.with_lifetime_rib(
@@ -1002,7 +1002,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
             // Create a label rib for the function.
             this.with_label_rib(RibKind::FnOrCoroutine, |this| {
                 match fn_kind {
-                    FnKind::Fn(_, _, sig, _, generics, body) => {
+                    FnKind::Fn(_, _, sig, _, generics, contract, body) => {
                         this.visit_generics(generics);
 
                         let declaration = &sig.decl;
@@ -1033,6 +1033,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                             },
                         );
 
+			if let Some(contract) = contract { this.visit_contract(contract); }
+
                         if let Some(body) = body {
                             // Ignore errors in function bodies if this is rustdoc
                             // Be sure not to set this until the function signature has been resolved.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index fce5ec36c661b..c6ffdd3b94fa8 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -3169,7 +3169,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     {
                         let pre = if lt.kind == MissingLifetimeKind::Ampersand
                             && let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, sig, _, _, _, _) = kind
                             && !sig.decl.inputs.is_empty()
                             && let sugg = sig
                                 .decl
@@ -3210,7 +3210,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                         } else if (lt.kind == MissingLifetimeKind::Ampersand
                             || lt.kind == MissingLifetimeKind::Underscore)
                             && let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, sig, _, _, _, _) = kind
                             && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
                             && !sig.decl.inputs.is_empty()
                             && let arg_refs = sig
@@ -3270,7 +3270,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                         let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
                         let mut sugg = vec![(lt.span, String::new())];
                         if let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, sig, _, _, _, _) = kind
                             && let ast::FnRetTy::Ty(ty) = &sig.decl.output
                         {
                             let mut lt_finder =
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cc3bda99a117b..70ef0d5179b14 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -103,6 +103,9 @@ symbols! {
         MacroRules:         "macro_rules",
         Raw:                "raw",
         Reuse:              "reuse",
+	RustcContractCaptures: "rustc_contract_captures",
+	RustcContractEnsures:  "rustc_contract_ensures",
+	RustcContractRequires: "rustc_contract_requires",
         Safe:               "safe",
         Union:              "union",
         Yeet:               "yeet",
@@ -650,6 +653,16 @@ symbols! {
         const_try,
         constant,
         constructor,
+        contract_check_captures, // FIXME we do not need this, do we?
+        contract_check_ensures,
+        contract_check_ensures_2,
+        contract_check_ensures_lt,
+        contract_check_ensures_lt_2,
+        contract_check_requires,
+        contract_check_requires_2,
+	contracts_captures,
+	contracts_ensures,
+	contracts_requires,
         convert_identity,
         copy,
         copy_closures,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index e3b4628e1846a..71c365d5ed157 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -3048,6 +3048,48 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
     // Runtime NOP
 }
 
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_requires<C: FnOnce() -> bool>(c: C) {
+    assert!(c());
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_requires_2<Old, C: FnOnce() -> bool, O: FnOnce() -> Old>(c: C, o: O) -> Old {
+    assert!(c()); o()
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_ensures<Ret, C: for<'a> FnOnce(&'a Ret) -> bool>(ret: &Ret, c: C) {
+    assert!(c(ret));
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_ensures_lt<'r, Ret, C: FnOnce(&'r Ret) -> bool>(ret: &'r Ret, c: C) {
+    assert!(c(ret));
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_ensures_2<Old, Ret, C: for<'a> FnOnce(Old, &'a Ret) -> bool>(old: Old, ret: &Ret, c: C) {
+    assert!(c(old, ret));
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)]
+#[rustc_intrinsic]
+pub fn contract_check_ensures_lt_2<'r, Old, Ret, C: FnOnce(Old, &'r Ret) -> bool>(old: Old, ret: &'r Ret, c: C) {
+    assert!(c(old, ret));
+}
+
 /// The intrinsic will return the size stored in that vtable.
 ///
 /// # Safety
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 08c0d6e34cd02..fe1c381d3cfe2 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -270,6 +270,15 @@ pub mod assert_matches {
     pub use crate::macros::{assert_matches, debug_assert_matches};
 }
 
+#[cfg(not(bootstrap))]
+/// Unstable module containin the unstable contracts attribute macros.
+#[unstable(feature = "rustc_contracts", issue = "none")]
+pub mod contracts {
+    pub use crate::macros::builtin::contracts_ensures;
+    pub use crate::macros::builtin::contracts_captures;
+    pub use crate::macros::builtin::contracts_requires;
+}
+
 #[unstable(feature = "cfg_match", issue = "115585")]
 pub use crate::macros::cfg_match;
 
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index aa0646846e43e..3f1839c507d76 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1695,6 +1695,45 @@ pub(crate) mod builtin {
         /* compiler built-in */
     }
 
+    #[cfg(not(bootstrap))]
+    /// Attribute macro applied to a function to compute and name state at entry that will be retained for evaluating the postcondition at exit.
+    ///
+    /// This one is not prefixed with rustc_ because pnkfelix is trying to
+    /// debug whether that name is ignored specially which can make things
+    /// hard to track down when adding a new feature like this.
+    #[unstable(feature = "rustc_contracts", issue = "none")]
+    #[allow_internal_unstable(core_intrinsics)]
+    #[rustc_builtin_macro]
+    pub macro contracts_captures($item:item) {
+        /* compiler built-in */
+    }
+
+    #[cfg(not(bootstrap))]
+    /// Attribute macro applied to a function to give it a postcondition.
+    ///
+    /// This one is not prefixed with rustc_ because pnkfelix is trying to
+    /// debug whether that name is ignored specially which can make things
+    /// hard to track down when adding a new feature like this.
+    #[unstable(feature = "rustc_contracts", issue = "none")]
+    #[allow_internal_unstable(core_intrinsics)]
+    #[rustc_builtin_macro]
+    pub macro contracts_ensures($item:item) {
+        /* compiler built-in */
+    }
+
+    #[cfg(not(bootstrap))]
+    /// Attribute macro applied to a function to give it a precondition.
+    ///
+    /// This one is not prefixed with rustc_ because pnkfelix is trying to
+    /// debug whether that name is ignored specially which can make things
+    /// hard to track down when adding a new feature like this.
+    #[unstable(feature = "rustc_contracts", issue = "none")]
+    #[allow_internal_unstable(core_intrinsics)]
+    #[rustc_builtin_macro]
+    pub macro contracts_requires($item:item) {
+        /* compiler built-in */
+    }
+
     /// Attribute macro applied to a function to register it as a handler for allocation failure.
     ///
     /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index d276e29bacecf..c76ffe862e703 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -39,7 +39,7 @@ declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]);
 
 impl EarlyLintPass for MultipleBoundLocations {
     fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, _, _, generics, _) = kind
+        if let FnKind::Fn(_, _, _, _, generics, _, _) = kind
             && !generics.params.is_empty()
             && !generics.where_clause.predicates.is_empty()
         {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 68f74e52ed7b7..3e02ad11b6e8e 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -291,7 +291,8 @@ pub fn eq_block(l: &Block, r: &Block) -> bool {
 }
 
 pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
-    use StmtKind::*;
+    
+use StmtKind::*;
     match (&l.kind, &r.kind) {
         (Let(l), Let(r)) => {
             eq_pat(&l.pat, &r.pat)
@@ -362,18 +363,21 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+		contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+		contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+		&& both(lc.as_ref(), rc.as_ref(), |l, r| eq_contract(l, r))
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (Mod(lu, lmk), Mod(ru, rmk)) => {
@@ -497,18 +501,21 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+		contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+		contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+		&& both(lc.as_ref(), rc.as_ref(), |l, r| eq_contract(l, r))
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -559,18 +566,21 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+		contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+		contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+		&& both(lc.as_ref(), rc.as_ref(), |l, r| eq_contract(l, r))
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -677,6 +687,34 @@ pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
     }
 }
 
+pub fn eq_contract(l: &FnContract, r: &FnContract) -> bool {
+    let req_cmp = match (&l.requires, &r.requires) {
+        (Some(l_expr), Some(r_expr)) => eq_expr(l_expr, r_expr),
+        (None, None) => true,
+        _ => return false,
+    };
+    { 
+	let mut lcap = l.captures.iter();
+	let mut rcap = r.captures.iter();
+	// if control breaks out of loop, then l and r have equal captures.
+	loop {
+	    let (li, le, ri, re) = match (lcap.next(), rcap.next()) {
+		(None, None) => break,
+		(Some((li, le)), Some((ri, re))) => (li, le, ri, re),
+		(Some(_), None) | (None, Some(_)) => return false,
+	    };
+	    if li != ri { return false; }
+	    if !eq_expr(le, re) { return false; }
+	}
+    };
+    let ens_cmp = match (&l.ensures, &r.ensures) {
+        (Some(l_expr), Some(r_expr)) => eq_expr(l_expr, r_expr),
+        (None, None) => true,
+        _ => return false,
+    };
+    req_cmp && ens_cmp
+}
+
 pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool {
     eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind)
 }
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index fc043a697e039..f9475372d4f90 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -333,12 +333,12 @@ impl<'a> FnSig<'a> {
         defaultness: ast::Defaultness,
     ) -> FnSig<'a> {
         match *fn_kind {
-            visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _) => {
+            visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _, _) => {
                 let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
                 fn_sig.defaultness = defaultness;
                 fn_sig
             }
-            visit::FnKind::Fn(_, _, fn_sig, vis, generics, _) => FnSig {
+            visit::FnKind::Fn(_, _, fn_sig, vis, generics, _, _) => FnSig {
                 decl,
                 generics,
                 ext: fn_sig.header.ext,
@@ -3432,6 +3432,7 @@ impl Rewrite for ast::ForeignItem {
                     defaultness,
                     ref sig,
                     ref generics,
+		    ref contract,
                     ref body,
                 } = **fn_kind;
                 if let Some(ref body) = body {
@@ -3447,6 +3448,8 @@ impl Rewrite for ast::ForeignItem {
                             sig,
                             &self.vis,
                             generics,
+			    contract.as_deref(),
+			    // contract.as_ref().map(|c: &ptr::P<ast::FnContract>| -> &ast::FnContract { &*c }),
                             Some(body),
                         ),
                         &sig.decl,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 8102fe7ad8f29..6fde2582ab890 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -386,7 +386,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         let indent = self.block_indent;
         let block;
         let rewrite = match fk {
-            visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
+            visit::FnKind::Fn(_, ident, _, _, _, _, Some(ref b)) => {
                 block = b;
                 self.rewrite_fn_before_block(
                     indent,
@@ -538,6 +538,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         defaultness,
                         ref sig,
                         ref generics,
+			ref contract,
                         ref body,
                     } = **fn_kind;
                     if let Some(ref body) = body {
@@ -553,6 +554,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                                 sig,
                                 &item.vis,
                                 generics,
+				contract.as_deref(),
                                 Some(body),
                             ),
                             &sig.decl,
@@ -646,13 +648,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     defaultness,
                     ref sig,
                     ref generics,
+		    ref contract,
                     ref body,
                 } = **fn_kind;
                 if let Some(ref body) = body {
                     let inner_attrs = inner_attributes(&ai.attrs);
                     let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
+                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, contract.as_deref(), Some(body)),
                         &sig.decl,
                         ai.span,
                         defaultness,