about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2022-06-03 22:12:26 -0400
committerJason Newcomb <jsnewcomb@pm.me>2022-06-25 07:55:30 -0400
commit7cdaabc9b7898fec15ee197ea32977c0ab4fd476 (patch)
treeacfd6c5a2b09132ddd1b1bb3a255362ef9d656fd
parent93ebd0e2db0e7c316cca3d35b077d19a79b4e7b1 (diff)
downloadrust-7cdaabc9b7898fec15ee197ea32977c0ab4fd476.tar.gz
rust-7cdaabc9b7898fec15ee197ea32977c0ab4fd476.zip
Suggest `pointer::cast` when possible in `transmute_ptr_to_ref`
Defensively add a cast to any type with lifetimes.
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/transmute/mod.rs25
-rw-r--r--clippy_lints/src/transmute/transmute_ptr_to_ref.rs56
-rw-r--r--clippy_lints/src/transmute/utils.rs28
-rw-r--r--tests/ui/transmute_ptr_to_ref.fixed78
-rw-r--r--tests/ui/transmute_ptr_to_ref.rs39
-rw-r--r--tests/ui/transmute_ptr_to_ref.stderr102
7 files changed, 265 insertions, 65 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 70cf6be8b7c..172c08a8168 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -641,7 +641,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef));
     store.register_late_pass(|| Box::new(no_effect::NoEffect));
     store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
-    store.register_late_pass(|| Box::new(transmute::Transmute));
+    store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv)));
     let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
     store.register_late_pass(move || {
         Box::new(cognitive_complexity::CognitiveComplexity::new(
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index cbe1406728b..5f3e98144f4 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -16,9 +16,10 @@ mod wrong_transmute;
 
 use clippy_utils::in_constant;
 use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
@@ -385,7 +386,10 @@ declare_clippy_lint! {
     "transmute to or from a type with an undefined representation"
 }
 
-declare_lint_pass!(Transmute => [
+pub struct Transmute {
+    msrv: Option<RustcVersion>,
+}
+impl_lint_pass!(Transmute => [
     CROSSPOINTER_TRANSMUTE,
     TRANSMUTE_PTR_TO_REF,
     TRANSMUTE_PTR_TO_PTR,
@@ -401,13 +405,18 @@ declare_lint_pass!(Transmute => [
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
 ]);
-
+impl Transmute {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
 impl<'tcx> LateLintPass<'tcx> for Transmute {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Call(path_expr, [arg]) = e.kind;
-            if let ExprKind::Path(ref qpath) = path_expr.kind;
-            if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
+            if let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind;
+            if let Some(def_id) = path.res.opt_def_id();
             if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
             then {
                 // Avoid suggesting non-const operations in const contexts:
@@ -427,7 +436,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
 
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
-                    | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, qpath)
+                    | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
@@ -446,4 +455,6 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index f3653199b37..3ed5d5c6950 100644
--- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -1,11 +1,12 @@
-use super::utils::get_type_snippet;
 use super::TRANSMUTE_PTR_TO_REF;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{meets_msrv, msrvs, sugg};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, Mutability, QPath};
+use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_semver::RustcVersion;
 
 /// Checks for `transmute_ptr_to_ref` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -15,7 +16,8 @@ pub(super) fn check<'tcx>(
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
-    qpath: &'tcx QPath<'_>,
+    path: &'tcx Path<'_>,
+    msrv: Option<RustcVersion>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
@@ -34,19 +36,34 @@ pub(super) fn check<'tcx>(
                     } else {
                         ("&*", "*const")
                     };
+                    let mut app = Applicability::MachineApplicable;
 
-                    let arg = if from_ptr_ty.ty == *to_ref_ty {
-                        arg
+                    let sugg = if let Some(ty) = get_explicit_type(path) {
+                        let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
+                        if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                            format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip)
+                        } else if from_ptr_ty.has_erased_regions() {
+                            sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip)))
+                                .to_string()
+                        } else {
+                            sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string()
+                        }
+                    } else if from_ptr_ty.ty == *to_ref_ty {
+                        if from_ptr_ty.has_erased_regions() {
+                            if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                                format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty)
+                            } else {
+                                sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty)))
+                                    .to_string()
+                            }
+                        } else {
+                            sugg::make_unop(deref, arg).to_string()
+                        }
                     } else {
-                        arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, *to_ref_ty)))
+                        sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string()
                     };
 
-                    diag.span_suggestion(
-                        e.span,
-                        "try",
-                        sugg::make_unop(deref, arg).to_string(),
-                        Applicability::Unspecified,
-                    );
+                    diag.span_suggestion(e.span, "try", sugg, app);
                 },
             );
             true
@@ -54,3 +71,14 @@ pub(super) fn check<'tcx>(
         _ => false,
     }
 }
+
+/// Gets the type `Bar` in `…::transmute<Foo, &Bar>`.
+fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> {
+    if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)?
+        && let TyKind::Rptr(_, ty) = &ty.kind
+    {
+        Some(ty.ty)
+    } else {
+        None
+    }
+}
diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs
index 0cbf5ccefa6..74927570b40 100644
--- a/clippy_lints/src/transmute/utils.rs
+++ b/clippy_lints/src/transmute/utils.rs
@@ -1,35 +1,9 @@
-use clippy_utils::last_path_segment;
-use clippy_utils::source::snippet;
-use if_chain::if_chain;
-use rustc_hir::{Expr, GenericArg, QPath, TyKind};
+use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{cast::CastKind, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
 
-/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
-/// not available , use
-/// the type's `ToString` implementation. In weird cases it could lead to types
-/// with invalid `'_`
-/// lifetime, but it should be rare.
-pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String {
-    let seg = last_path_segment(path);
-    if_chain! {
-        if let Some(params) = seg.args;
-        if !params.parenthesized;
-        if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
-            GenericArg::Type(ty) => Some(ty),
-            _ => None,
-        }).nth(1);
-        if let TyKind::Rptr(_, ref to_ty) = to_ty.kind;
-        then {
-            return snippet(cx, to_ty.ty.span, &to_ref_ty.to_string()).to_string();
-        }
-    }
-
-    to_ref_ty.to_string()
-}
-
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
 pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed
new file mode 100644
index 00000000000..e5fe9133f97
--- /dev/null
+++ b/tests/ui/transmute_ptr_to_ref.fixed
@@ -0,0 +1,78 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::match_single_binding)]
+
+unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+    let _: &T = &*p;
+    let _: &T = &*p;
+
+    let _: &mut T = &mut *m;
+    let _: &mut T = &mut *m;
+
+    let _: &T = &*m;
+    let _: &T = &*m;
+
+    let _: &mut T = &mut *(p as *mut T);
+    let _ = &mut *(p as *mut T);
+
+    let _: &T = &*(o as *const T);
+    let _: &T = &*(o as *const T);
+
+    let _: &mut T = &mut *(om as *mut T);
+    let _: &mut T = &mut *(om as *mut T);
+
+    let _: &T = &*(om as *const T);
+    let _: &T = &*(om as *const T);
+}
+
+fn _issue1231() {
+    struct Foo<'a, T> {
+        bar: &'a T,
+    }
+
+    let raw = 42 as *const i32;
+    let _: &Foo<u8> = unsafe { &*raw.cast::<Foo<_>>() };
+
+    let _: &Foo<&u8> = unsafe { &*raw.cast::<Foo<&_>>() };
+
+    type Bar<'a> = &'a u8;
+    let raw = 42 as *const i32;
+    unsafe { &*(raw as *const u8) };
+}
+
+unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+    match 0 {
+        0 => &*x.cast::<&u32>(),
+        1 => &*y.cast::<&u32>(),
+        2 => &*x.cast::<&'b u32>(),
+        _ => &*y.cast::<&'b u32>(),
+    }
+}
+
+unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+    #![clippy::msrv = "1.38"]
+    let a = 0u32;
+    let a = &a as *const u32;
+    let _: &u32 = &*a;
+    let _: &u32 = &*a.cast::<u32>();
+    match 0 {
+        0 => &*x.cast::<&u32>(),
+        _ => &*x.cast::<&'b u32>(),
+    }
+}
+
+unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+    #![clippy::msrv = "1.37"]
+    let a = 0u32;
+    let a = &a as *const u32;
+    let _: &u32 = &*a;
+    let _: &u32 = &*(a as *const u32);
+    match 0 {
+        0 => &*(x as *const () as *const &u32),
+        _ => &*(x as *const () as *const &'b u32),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs
index ba35c6adc4d..fe49cdc324f 100644
--- a/tests/ui/transmute_ptr_to_ref.rs
+++ b/tests/ui/transmute_ptr_to_ref.rs
@@ -1,4 +1,8 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::match_single_binding)]
 
 unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = std::mem::transmute(p);
@@ -23,7 +27,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = &*(om as *const T);
 }
 
-fn issue1231() {
+fn _issue1231() {
     struct Foo<'a, T> {
         bar: &'a T,
     }
@@ -38,4 +42,37 @@ fn issue1231() {
     unsafe { std::mem::transmute::<_, Bar>(raw) };
 }
 
+unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+    match 0 {
+        0 => std::mem::transmute(x),
+        1 => std::mem::transmute(y),
+        2 => std::mem::transmute::<_, &&'b u32>(x),
+        _ => std::mem::transmute::<_, &&'b u32>(y),
+    }
+}
+
+unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+    #![clippy::msrv = "1.38"]
+    let a = 0u32;
+    let a = &a as *const u32;
+    let _: &u32 = std::mem::transmute(a);
+    let _: &u32 = std::mem::transmute::<_, &u32>(a);
+    match 0 {
+        0 => std::mem::transmute(x),
+        _ => std::mem::transmute::<_, &&'b u32>(x),
+    }
+}
+
+unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+    #![clippy::msrv = "1.37"]
+    let a = 0u32;
+    let a = &a as *const u32;
+    let _: &u32 = std::mem::transmute(a);
+    let _: &u32 = std::mem::transmute::<_, &u32>(a);
+    match 0 {
+        0 => std::mem::transmute(x),
+        _ => std::mem::transmute::<_, &&'b u32>(x),
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr
index df0598a58cd..2993e5e7b0c 100644
--- a/tests/ui/transmute_ptr_to_ref.stderr
+++ b/tests/ui/transmute_ptr_to_ref.stderr
@@ -1,5 +1,5 @@
 error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:4:17
+  --> $DIR/transmute_ptr_to_ref.rs:8:17
    |
 LL |     let _: &T = std::mem::transmute(p);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
@@ -7,58 +7,130 @@ LL |     let _: &T = std::mem::transmute(p);
    = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:7:21
+  --> $DIR/transmute_ptr_to_ref.rs:11:21
    |
 LL |     let _: &mut T = std::mem::transmute(m);
    |                     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:10:17
+  --> $DIR/transmute_ptr_to_ref.rs:14:17
    |
 LL |     let _: &T = std::mem::transmute(m);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:13:21
+  --> $DIR/transmute_ptr_to_ref.rs:17:21
    |
 LL |     let _: &mut T = std::mem::transmute(p as *mut T);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
 
 error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:16:17
+  --> $DIR/transmute_ptr_to_ref.rs:20:17
    |
 LL |     let _: &T = std::mem::transmute(o);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:19:21
+  --> $DIR/transmute_ptr_to_ref.rs:23:21
    |
 LL |     let _: &mut T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:22:17
+  --> $DIR/transmute_ptr_to_ref.rs:26:17
    |
 LL |     let _: &T = std::mem::transmute(om);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<u8>`)
-  --> $DIR/transmute_ptr_to_ref.rs:32:32
+error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<u8>`)
+  --> $DIR/transmute_ptr_to_ref.rs:36:32
    |
 LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)`
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<&u8>`)
-  --> $DIR/transmute_ptr_to_ref.rs:34:33
+error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<&u8>`)
+  --> $DIR/transmute_ptr_to_ref.rs:38:33
    |
 LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
-  --> $DIR/transmute_ptr_to_ref.rs:38:14
+  --> $DIR/transmute_ptr_to_ref.rs:42:14
    |
 LL |     unsafe { std::mem::transmute::<_, Bar>(raw) };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
 
-error: aborting due to 10 previous errors
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:47:14
+   |
+LL |         0 => std::mem::transmute(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:48:14
+   |
+LL |         1 => std::mem::transmute(y),
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:49:14
+   |
+LL |         2 => std::mem::transmute::<_, &&'b u32>(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:50:14
+   |
+LL |         _ => std::mem::transmute::<_, &&'b u32>(y),
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
+
+error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:58:19
+   |
+LL |     let _: &u32 = std::mem::transmute(a);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
+
+error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:59:19
+   |
+LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:61:14
+   |
+LL |         0 => std::mem::transmute(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:62:14
+   |
+LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
+
+error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:70:19
+   |
+LL |     let _: &u32 = std::mem::transmute(a);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
+
+error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:71:19
+   |
+LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:73:14
+   |
+LL |         0 => std::mem::transmute(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
+
+error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
+  --> $DIR/transmute_ptr_to_ref.rs:74:14
+   |
+LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
+
+error: aborting due to 22 previous errors