diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 16472c787572c..e68a6f52c73a2 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -821,9 +821,6 @@ pub struct LocalDecl<'tcx> {
     /// flag drop flags to avoid triggering this check as they are introduced
     /// after typeck.
     ///
-    /// Unsafety checking will also ignore dereferences of these locals,
-    /// so they can be used for raw pointers only used in a desugaring.
-    ///
     /// This should be sound because the drop flags are fully algebraic, and
     /// therefore don't affect the OIBIT or outlives properties of the
     /// generator.
@@ -1010,13 +1007,13 @@ impl<'tcx> LocalDecl<'tcx> {
     }
 
     /// Returns `Some` if this is a reference to a static item that is used to
-    /// access that static
+    /// access that static.
     pub fn is_ref_to_static(&self) -> bool {
         matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
     }
 
-    /// Returns `Some` if this is a reference to a static item that is used to
-    /// access that static
+    /// Returns `Some` if this is a reference to a thread-local static item that is used to
+    /// access that static.
     pub fn is_ref_to_thread_local(&self) -> bool {
         match self.local_info {
             Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index b9e4f6fb12eb1..f0bfdae261c64 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -152,10 +152,14 @@ impl<'tcx> Rvalue<'tcx> {
                 tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count))
             }
             Rvalue::ThreadLocalRef(did) => {
+                let static_ty = tcx.type_of(did);
                 if tcx.is_mutable_static(did) {
-                    tcx.mk_mut_ptr(tcx.type_of(did))
+                    tcx.mk_mut_ptr(static_ty)
+                } else if tcx.is_foreign_item(did) {
+                    tcx.mk_imm_ptr(static_ty)
                 } else {
-                    tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.type_of(did))
+                    // FIXME: These things don't *really* have 'static lifetime.
+                    tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
                 }
             }
             Rvalue::Ref(reg, bk, ref place) => {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index b0f0f0ba57fad..4a20e1c32f99e 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -529,8 +529,12 @@ impl<'tcx> TyCtxt<'tcx> {
         // Make sure that any constants in the static's type are evaluated.
         let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id));
 
+        // Make sure that accesses to unsafe statics end up using raw pointers.
+        // For thread-locals, this needs to be kept in sync with `Rvalue::ty`.
         if self.is_mutable_static(def_id) {
             self.mk_mut_ptr(static_ty)
+        } else if self.is_foreign_item(def_id) {
+            self.mk_imm_ptr(static_ty)
         } else {
             self.mk_imm_ref(self.lifetimes.re_erased, static_ty)
         }
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index 7309a4129e468..3d68b862df2d0 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -204,6 +204,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             if let [] = proj_base {
                 let decl = &self.body.local_decls[place.local];
                 if decl.internal {
+                    // If the projection root is an artifical local that we introduced when
+                    // desugaring `static`, give a more specific error message
+                    // (avoid the general "raw pointer" clause below, that would only be confusing).
                     if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                         if self.tcx.is_mutable_static(def_id) {
                             self.require_unsafe(
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
index 0d5760b4cd5c7..88d583b815adb 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
@@ -4,17 +4,17 @@ promoted[0] in FOO: &[&i32; 1] = {
     let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
     let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
     let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
-    let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+    let mut _3: *const i32;              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 
     bb0: {
-        _3 = const {alloc2: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+        _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
                                          // ty::Const
-                                         // + ty: &i32
+                                         // + ty: *const i32
                                          // + val: Value(Scalar(alloc2))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
-        _2 = _3;                         // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
+                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
+        _2 = &(*_3);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
         _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
         _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
         return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index a392334e0c955..82277b2a21cbe 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -7,7 +7,7 @@
       let mut _2: &[&i32; 1];              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       let _3: [&i32; 1];                   // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       let mut _4: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
-      let _5: &i32;                        // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+      let _5: *const i32;                  // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +     let mut _6: &[&i32; 1];              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       scope 1 {
       }
@@ -18,16 +18,16 @@
 -         StorageLive(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         StorageLive(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
 -         StorageLive(_5);                 // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
--         _5 = const {alloc2: &i32};       // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+-         _5 = const {alloc2: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +         _6 = const FOO::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
                                            // ty::Const
--                                          // + ty: &i32
+-                                          // + ty: *const i32
 -                                          // + val: Value(Scalar(alloc2))
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
--                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
+-                                          // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
 -         _4 = &(*_5);                     // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46