diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 8e339eb26b26c..ab3c26fac8338 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -66,7 +66,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     // Create the function context. This is either derived from scratch or,
     // in the case of closures, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
+    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
 
     let tcx = fcx.tcx;
     let sess = tcx.sess;
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 34ad8ec08984e..b2395b7bb2502 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1472,22 +1472,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 fn_output = Some(&fn_decl.output); // `impl Trait` return type
             }
         }
-        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
-            self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
+        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
+            self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
         }
 
-        if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
+        if let Some(sp) = fcx.ret_coercion_span.get() {
             // If the closure has an explicit return type annotation,
             // then a type error may occur at the first return expression we
             // see in the closure (if it conflicts with the declared
             // return type). Skip adding a note in this case, since it
             // would be incorrect.
-            if !err.span.primary_spans().iter().any(|span| span == sp) {
+            if !err.span.primary_spans().iter().any(|&span| span == sp) {
                 let hir = fcx.tcx.hir();
                 let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id));
                 if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
                     err.span_note(
-                        *sp,
+                        sp,
                         &format!(
                             "return type inferred to be `{}` here",
                             fcx.resolve_vars_if_possible(expected)
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 8f463af73c477..e37b4ff742bc6 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -680,14 +680,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if self.ret_coercion.is_none() {
             self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
         } else if let Some(ref e) = expr_opt {
-            if self.ret_coercion_span.borrow().is_none() {
-                *self.ret_coercion_span.borrow_mut() = Some(e.span);
+            if self.ret_coercion_span.get().is_none() {
+                self.ret_coercion_span.set(Some(e.span));
             }
             self.check_return_expr(e);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
-            if self.ret_coercion_span.borrow().is_none() {
-                *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+            if self.ret_coercion_span.get().is_none() {
+                self.ret_coercion_span.set(Some(expr.span));
             }
             let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
             if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 6df9e3ab7dbe8..fb6f9c03352b4 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -23,7 +23,6 @@ use rustc_span::{self, MultiSpan, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
 
 use crate::structured_errors::StructuredDiagnostic;
-use std::mem::replace;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -589,11 +588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         blk: &'tcx hir::Block<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let prev = {
-            let mut fcx_ps = self.ps.borrow_mut();
-            let unsafety_state = fcx_ps.recurse(blk);
-            replace(&mut *fcx_ps, unsafety_state)
-        };
+        let prev = self.ps.replace(self.ps.get().recurse(blk));
 
         // In some cases, blocks have just one exit, but other blocks
         // can be targeted by multiple breaks. This can happen both
@@ -709,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.write_ty(blk.hir_id, ty);
 
-        *self.ps.borrow_mut() = prev;
+        self.ps.set(prev);
         ty
     }
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 6d09043bd5033..e9223f700dcc7 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -66,11 +66,11 @@ pub struct FnCtxt<'a, 'tcx> {
     pub(super) in_tail_expr: bool,
 
     /// First span of a return site that we find. Used in error messages.
-    pub(super) ret_coercion_span: RefCell<Option<Span>>,
+    pub(super) ret_coercion_span: Cell<Option<Span>>,
 
     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
 
-    pub(super) ps: RefCell<UnsafetyState>,
+    pub(super) ps: Cell<UnsafetyState>,
 
     /// Whether the last checked node generates a divergence (e.g.,
     /// `return` will set this to `Always`). In general, when entering
@@ -127,9 +127,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ret_coercion_impl_trait: None,
             ret_type_span: None,
             in_tail_expr: false,
-            ret_coercion_span: RefCell::new(None),
+            ret_coercion_span: Cell::new(None),
             resume_yield_tys: None,
-            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+            ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
             diverges: Cell::new(Diverges::Maybe),
             has_errors: Cell::new(false),
             enclosing_breakables: RefCell::new(EnclosingBreakables {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 52276ed4beeaa..c8c6fa12fae08 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -184,14 +184,14 @@ impl UnsafetyState {
         UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true }
     }
 
-    pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState {
+    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
         use hir::BlockCheckMode;
         match self.unsafety {
             // If this unsafe, then if the outer function was already marked as
             // unsafe we shouldn't attribute the unsafe'ness to the block. This
             // way the block can be warned about instead of ignoring this
             // extraneous block (functions are never warned about).
-            hir::Unsafety::Unsafe if self.from_fn => *self,
+            hir::Unsafety::Unsafe if self.from_fn => self,
 
             unsafety => {
                 let (unsafety, def, count) = match blk.rules {