From b4e96a462e517100f2d7e470aac27e3a02db8884 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 16 Jun 2018 13:05:05 +0300 Subject: [PATCH 1/4] Implement a more strict transmute check This checks whether types being transmuted from and to have a specified layout. --- src/librustc/diagnostics.rs | 2 +- src/librustc/middle/intrinsicck.rs | 157 ++++++++++++++++++++++++++++- src/librustc_lint/types.rs | 38 +------ 3 files changed, 156 insertions(+), 41 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5fecf2b15359f..f0b4523ab363f 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2133,8 +2133,8 @@ register_diagnostics! { E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0697, // closures cannot be static - E0707, // multiple elided lifetimes used in arguments of `async fn` E0708, // `async` non-`move` closures with arguments are not currently supported E0709, // multiple different lifetimes used in arguments of `async fn` + E0912, // transmutation between types of unspecified layout } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 27f7dbf508db0..180080ed1a94e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -8,15 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir; use hir::def::Def; use hir::def_id::DefId; -use ty::{self, Ty, TyCtxt}; +use hir::intravisit::{self, Visitor, NestedVisitorMap}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; +use ty::{self, Ty, AdtKind, TyCtxt, TypeFoldable}; +use ty::subst::Substs; use rustc_target::spec::abi::Abi::RustIntrinsic; +use syntax_pos::DUMMY_SP; use syntax_pos::Span; -use hir::intravisit::{self, Visitor, NestedVisitorMap}; -use hir; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { @@ -64,17 +66,164 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty } +/// Check if this enum can be safely exported based on the +/// "nullable pointer optimization". Currently restricted +/// to function pointers and references, but could be +/// expanded to cover NonZero raw pointers and newtypes. +/// FIXME: This duplicates code in codegen. +pub fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def: &'tcx ty::AdtDef, + substs: &Substs<'tcx>) + -> bool { + if def.variants.len() == 2 { + let data_idx; + + if def.variants[0].fields.is_empty() { + data_idx = 1; + } else if def.variants[1].fields.is_empty() { + data_idx = 0; + } else { + return false; + } + + if def.variants[data_idx].fields.len() == 1 { + match def.variants[data_idx].fields[0].ty(tcx, substs).sty { + ty::TyFnPtr(_) => { + return true; + } + ty::TyRef(..) => { + return true; + } + _ => {} + } + } + } + false +} + impl<'a, 'tcx> ExprVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { self.tcx.fn_sig(def_id).abi() == RustIntrinsic && self.tcx.item_name(def_id) == "transmute" } + /// Calculate whether a type has a specified layout. + /// + /// The function returns `None` in indeterminate cases (such as `TyError`). + fn is_layout_specified(&self, ty: Ty<'tcx>) -> Option { + match ty.sty { + // These types have a specified layout + // Reference: Primitive type layout + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + // Reference: Pointers and references layout + ty::TyFnPtr(_) => Some(true), + // Reference: Array layout (depends on the contained type) + ty::TyArray(ty, _) => self.is_layout_specified(ty), + // Reference: Tuple layout (only specified if empty) + ty::TyTuple(ref tys) => Some(tys.is_empty()), + + // Cases with definitely unspecified layouts + ty::TyClosure(_, _) | + ty::TyGenerator(_, _, _) | + ty::TyGeneratorWitness(_) => Some(false), + // Currently ZST, but does not seem to be guaranteed + ty::TyFnDef(_, _) => Some(false), + // Unsized types + ty::TyForeign(_) | + ty::TyNever | + ty::TyStr | + ty::TySlice(_) | + ty::TyDynamic(_, _) => Some(false), + + // Indeterminate cases + ty::TyInfer(_) | + // should we report `Some(false)` for TyParam(_)? It this possible to reach this branch? + ty::TyParam(_) | + ty::TyError => None, + + // The “it’s complicated™” cases + // Reference: Pointers and references layout + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) => { + let pointee = self.tcx.normalize_erasing_regions(self.param_env, pointee); + // Pointers to unsized types have no specified layout. + Some(pointee.is_sized(self.tcx.at(DUMMY_SP), self.param_env)) + } + ty::TyProjection(_) | ty::TyAnon(_, _) => { + let normalized = self.tcx.normalize_erasing_regions(self.param_env, ty); + if ty == normalized { + None + } else { + self.is_layout_specified(normalized) + } + } + ty::TyAdt(def, substs) => { + // Documentation guarantees 0-size. + if def.is_phantom_data() { + return Some(true); + } + match def.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + if !def.repr.c() && !def.repr.transparent() && !def.repr.simd() { + return Some(false); + } + // FIXME: do we guarantee 0-sizedness for structs with 0 fields? + // If not, they should cause Some(false) here. + let mut seen_none = false; + for field in &def.non_enum_variant().fields { + let field_ty = field.ty(self.tcx, substs); + match self.is_layout_specified(field_ty) { + Some(true) => continue, + None => { + seen_none = true; + continue; + } + x => return x, + } + } + return if seen_none { None } else { Some(true) }; + } + AdtKind::Enum => { + if !def.repr.c() && def.repr.int.is_none() { + if !is_repr_nullable_ptr(self.tcx, def, substs) { + return Some(false); + } + } + return Some(true); + } + } + } + } + } + fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { + // Check for unspecified types before checking for same size. + assert!(!from.has_infer_types()); + assert!(!to.has_infer_types()); + + let unspecified_layout = |msg, ty| { + struct_span_err!(self.tcx.sess, span, E0912, "{}", msg) + .note(&format!("{} has an unspecified layout", ty)) + .note("this will become a hard error in the future") + .emit(); + }; + + if self.is_layout_specified(from) == Some(false) { + unspecified_layout("transmutation from a type with an unspecified layout", from); + } + + if self.is_layout_specified(to) == Some(false) { + unspecified_layout("transmutation to a type with an unspecified layout", to); + } + + // Check for same size using the skeletons. let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env); let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env); - // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { if sk_from.same_size(sk_to) { return; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 50492ae073720..b7c9e129ac8d0 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] use rustc::hir::map as hir_map; -use rustc::ty::subst::Substs; -use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, ParamEnv, Ty}; use rustc::ty::layout::{self, IntegerExt, LayoutOf}; +use rustc::middle::intrinsicck::is_repr_nullable_ptr; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -428,40 +428,6 @@ enum FfiResult<'tcx> { }, } -/// Check if this enum can be safely exported based on the -/// "nullable pointer optimization". Currently restricted -/// to function pointers and references, but could be -/// expanded to cover NonZero raw pointers and newtypes. -/// FIXME: This duplicates code in codegen. -fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def: &'tcx ty::AdtDef, - substs: &Substs<'tcx>) - -> bool { - if def.variants.len() == 2 { - let data_idx; - - if def.variants[0].fields.is_empty() { - data_idx = 1; - } else if def.variants[1].fields.is_empty() { - data_idx = 0; - } else { - return false; - } - - if def.variants[data_idx].fields.len() == 1 { - match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyFnPtr(_) => { - return true; - } - ty::TyRef(..) => { - return true; - } - _ => {} - } - } - } - false -} impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined From 4ca4a2c416e73122a5ba28dc9d0c5cc8d4dc31ec Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 16 Jun 2018 16:44:46 +0300 Subject: [PATCH 2/4] =?UTF-8?q?Wipe=20the=20transmutes=20off=20the=20libst?= =?UTF-8?q?d=E2=80=99s=20face?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/liballoc/sync.rs | 7 +++++++ src/liballoc/task.rs | 13 +++++-------- src/libcore/str/lossy.rs | 3 +-- src/libpanic_unwind/lib.rs | 5 +++-- src/libstd/error.rs | 5 ++--- src/libstd/panicking.rs | 4 ++-- src/libstd/sync/mpsc/blocking.rs | 5 ++--- src/libstd/sys/unix/ext/ffi.rs | 3 +-- src/libstd/sys/unix/ext/net.rs | 2 +- src/libstd/sys/unix/os_str.rs | 13 ++++++------- src/libstd/sys_common/wtf8.rs | 13 ++++++------- 11 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 2abd9c85c5754..7ff0dd6e827d0 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -517,6 +517,13 @@ impl Arc { unsafe { self.ptr.as_ref() } } + #[inline] + pub(crate) unsafe fn into_ptr(self) -> NonNull { + let ptr = self.ptr; + mem::forget(self); + ptr.cast() + } + // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index f14fe3a20da93..2d6292c939a49 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -19,9 +19,8 @@ pub use self::if_arc::*; mod if_arc { use super::*; use core::marker::PhantomData; - use core::mem; - use core::ptr::{self, NonNull}; use sync::Arc; + use core::ptr; /// A way of waking up a specific task. /// @@ -83,9 +82,9 @@ mod if_arc { { fn from(rc: Arc) -> Self { unsafe { - let ptr = mem::transmute::, NonNull>>(rc); - Waker::new(ptr) + Waker::new(rc.into_ptr::>()) } + } } @@ -96,8 +95,7 @@ mod if_arc { /// will call `wake.wake()` if awoken after being converted to a `Waker`. #[inline] pub unsafe fn local_waker(wake: Arc) -> LocalWaker { - let ptr = mem::transmute::, NonNull>>(wake); - LocalWaker::new(ptr) + LocalWaker::new(wake.into_ptr::>()) } struct NonLocalAsLocal(ArcWrapped); @@ -133,8 +131,7 @@ mod if_arc { #[inline] pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { unsafe { - let ptr = mem::transmute::, NonNull>>(wake); - LocalWaker::new(ptr) + LocalWaker::new(wake.into_ptr::>()) } } } diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs index 5cfb36d3b195b..80f24e3bfef21 100644 --- a/src/libcore/str/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -12,7 +12,6 @@ use char; use str as core_str; use fmt; use fmt::Write; -use mem; /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "0")] @@ -26,7 +25,7 @@ impl Utf8Lossy { } pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { - unsafe { mem::transmute(bytes) } + unsafe { &*(bytes as *const [u8] as *const Utf8Lossy) } } pub fn chunks(&self) -> Utf8LossyChunksIter { diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 6c52c0fa10cc0..7107a69b4a831 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -51,7 +51,7 @@ extern crate unwind; use alloc::boxed::Box; use core::intrinsics; -use core::mem; +use core::any::Any; use core::raw; use core::panic::BoxMeUp; @@ -105,7 +105,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 { 0 } else { - let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload)); + let raw = &Box::into_raw(imp::cleanup(payload)); + let obj = *(raw as *const *mut (Any + Send) as *const raw::TraitObject); *data_ptr = obj.data as usize; *vtable_ptr = obj.vtable as usize; 1 diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 1958915602f83..11c8997ed9489 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -30,7 +30,6 @@ use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use mem::transmute; use num; use str; use string; @@ -483,7 +482,7 @@ impl Error + Send { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // reapply the Send marker - transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (Error + Send)) }) } } @@ -497,7 +496,7 @@ impl Error + Send + Sync { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // reapply the Send+Sync marker - transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (Error + Send + Sync)) }) } } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 46b6cf60705c1..879c8eb19b96a 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -297,10 +297,10 @@ pub unsafe fn try R>(f: F) -> Result> { } else { update_panic_count(-1); debug_assert!(update_panic_count(0) == 0); - Err(mem::transmute(raw::TraitObject { + Err(Box::from_raw(*(&raw::TraitObject { data: any_data as *mut _, vtable: any_vtable as *mut _, - })) + } as *const _ as *const *mut _))) }; fn do_call R, R>(data: *mut u8) { diff --git a/src/libstd/sync/mpsc/blocking.rs b/src/libstd/sync/mpsc/blocking.rs index c08bd6d133d06..efdc8fe010c72 100644 --- a/src/libstd/sync/mpsc/blocking.rs +++ b/src/libstd/sync/mpsc/blocking.rs @@ -13,7 +13,6 @@ use thread::{self, Thread}; use sync::atomic::{AtomicBool, Ordering}; use sync::Arc; -use mem; use time::Instant; struct Inner { @@ -64,14 +63,14 @@ impl SignalToken { /// flag. #[inline] pub unsafe fn cast_to_usize(self) -> usize { - mem::transmute(self.inner) + Arc::into_raw(self.inner) as usize } /// Convert from an unsafe usize value. Useful for retrieving a pipe's state /// flag. #[inline] pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken { - SignalToken { inner: mem::transmute(signal_ptr) } + SignalToken { inner: Arc::from_raw(signal_ptr as *const _) } } } diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index 8347145db5aaf..74b3ac7c8497e 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -13,7 +13,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use ffi::{OsStr, OsString}; -use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; @@ -111,7 +110,7 @@ pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] impl OsStrExt for OsStr { fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } + unsafe { &*(slice as *const [u8] as *const OsStr) } } fn as_bytes(&self) -> &[u8] { &self.as_inner().inner diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index e277b1aa7b5f9..b077730ced8e9 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -211,7 +211,7 @@ impl SocketAddr { fn address<'a>(&'a self) -> AddressKind<'a> { let len = self.len as usize - sun_path_offset(); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + let path = unsafe { &*(&self.addr.sun_path as *const [libc::c_char] as *const [u8]) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses if len == 0 diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 01c0fb830aadd..8f0da2ac89f18 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -14,7 +14,6 @@ use borrow::Cow; use fmt; use str; -use mem; use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; @@ -110,7 +109,7 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } + Slice::from_u8_slice(&*self.inner) } pub fn into_string(self) -> Result { @@ -123,12 +122,12 @@ impl Buf { #[inline] pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } + unsafe { Box::from_raw(Box::into_raw(self.inner.into_boxed_slice()) as *mut Slice) } } #[inline] pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + let inner: Box<[u8]> = unsafe { Box::from_raw(&mut (*Box::into_raw(boxed)).inner) }; Buf { inner: inner.into_vec() } } @@ -145,7 +144,7 @@ impl Buf { impl Slice { fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } + unsafe { &*(s as *const _ as *const Slice) } } pub fn from_str(s: &str) -> &Slice { @@ -167,12 +166,12 @@ impl Slice { #[inline] pub fn into_box(&self) -> Box { let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut Slice) } } pub fn empty_box() -> Box { let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut Slice) } } #[inline] diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index bbb5980bd9da6..9617bdc17eac5 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -32,7 +32,6 @@ use char; use fmt; use hash::{Hash, Hasher}; use iter::FromIterator; -use mem; use ops; use rc::Rc; use slice; @@ -366,12 +365,12 @@ impl Wtf8Buf { /// Converts this `Wtf8Buf` into a boxed `Wtf8`. #[inline] pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.bytes.into_boxed_slice()) } + unsafe { Box::from_raw(Box::into_raw(self.bytes.into_boxed_slice()) as *mut Wtf8) } } /// Converts a `Box` into a `Wtf8Buf`. pub fn from_box(boxed: Box) -> Wtf8Buf { - let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; + let bytes: Box<[u8]> = unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [u8]) }; Wtf8Buf { bytes: bytes.into_vec() } } } @@ -493,7 +492,7 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - mem::transmute(value) + &*(value as *const _ as *const Wtf8) } /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. @@ -502,7 +501,7 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - mem::transmute(value) + &mut *(value as *mut _ as *mut Wtf8) } /// Returns the length, in WTF-8 bytes. @@ -651,13 +650,13 @@ impl Wtf8 { #[inline] pub fn into_box(&self) -> Box { let boxed: Box<[u8]> = self.bytes.into(); - unsafe { mem::transmute(boxed) } + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut Wtf8) } } /// Creates a boxed, empty `Wtf8`. pub fn empty_box() -> Box { let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut Wtf8) } } #[inline] From a5cc7c73eefe280c5a4e19dc1ad7dc56028018d4 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 2 Jul 2018 21:35:34 +0300 Subject: [PATCH 3/4] Only error when not bootstrapping for easier crater --- src/librustc/middle/intrinsicck.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 180080ed1a94e..8145aed2aced3 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -206,10 +206,17 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx> { assert!(!to.has_infer_types()); let unspecified_layout = |msg, ty| { - struct_span_err!(self.tcx.sess, span, E0912, "{}", msg) - .note(&format!("{} has an unspecified layout", ty)) - .note("this will become a hard error in the future") - .emit(); + if ::std::env::var("RUSTC_BOOTSTRAP").is_ok() { + struct_span_warn!(self.tcx.sess, span, E0912, "{}", msg) + .note(&format!("{} has an unspecified layout", ty)) + .note("this will become a hard error in the future") + .emit(); + } else { + struct_span_err!(self.tcx.sess, span, E0912, "{}", msg) + .note(&format!("{} has an unspecified layout", ty)) + .note("this will become a hard error in the future") + .emit(); + } }; if self.is_layout_specified(from) == Some(false) { From 18d1459f758301af7dc1fd0ac972831e6fe67ebb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 2 Jul 2018 22:20:14 +0300 Subject: [PATCH 4/4] error -> warning --- src/test/compile-fail/issue-28625.rs | 4 +- src/test/compile-fail/issue-32377.rs | 3 +- src/test/compile-fail/issue-35570.rs | 2 + .../compile-fail/transmute-fat-pointers.rs | 20 +++- src/test/compile-fail/transmute-impl.rs | 4 +- src/test/ui/transmute/main.rs | 8 +- src/test/ui/transmute/main.stderr | 27 ++++- .../transmute-from-fn-item-types-error.rs | 27 +++-- .../transmute-from-fn-item-types-error.stderr | 99 +++++++++++++++++-- .../ui/transmute/transmute-type-parameters.rs | 12 ++- .../transmute-type-parameters.stderr | 47 ++++++++- 11 files changed, 213 insertions(+), 40 deletions(-) diff --git a/src/test/compile-fail/issue-28625.rs b/src/test/compile-fail/issue-28625.rs index dc9155ed66c6e..75598445e706d 100644 --- a/src/test/compile-fail/issue-28625.rs +++ b/src/test/compile-fail/issue-28625.rs @@ -17,7 +17,9 @@ struct ArrayPeano { } fn foo(a: &ArrayPeano) -> &[T] where T: Bar { - unsafe { std::mem::transmute(a) } //~ ERROR transmute called with types of different sizes + unsafe { std::mem::transmute(a) } + //~^ WARN transmutation to a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } impl Bar for () { diff --git a/src/test/compile-fail/issue-32377.rs b/src/test/compile-fail/issue-32377.rs index 5091ba4ee1aa4..b1d230c7f162b 100644 --- a/src/test/compile-fail/issue-32377.rs +++ b/src/test/compile-fail/issue-32377.rs @@ -21,7 +21,8 @@ struct Bar { fn foo(x: [usize; 2]) -> Bar { unsafe { mem::transmute(x) } - //~^ ERROR transmute called with types of different sizes + //~^ WARN transmutation to a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn main() {} diff --git a/src/test/compile-fail/issue-35570.rs b/src/test/compile-fail/issue-35570.rs index 092bf00ddd6a4..14067b3a9a556 100644 --- a/src/test/compile-fail/issue-35570.rs +++ b/src/test/compile-fail/issue-35570.rs @@ -19,6 +19,8 @@ trait Trait2<'a> { fn _ice(param: Box Trait1<<() as Trait2<'a>>::Ty>>) { let _e: (usize, usize) = unsafe{mem::transmute(param)}; + //~^ WARN transmutation to a type with an unspecified layout + //~| WARN transmutation from a type with an unspecified layout } trait Lifetime<'a> { diff --git a/src/test/compile-fail/transmute-fat-pointers.rs b/src/test/compile-fail/transmute-fat-pointers.rs index 59027fc7787f8..ae695666f9e2f 100644 --- a/src/test/compile-fail/transmute-fat-pointers.rs +++ b/src/test/compile-fail/transmute-fat-pointers.rs @@ -15,11 +15,17 @@ use std::mem::transmute; fn a(x: &[T]) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes + unsafe { transmute(x) } + //~^ WARN transmutation to a type with an unspecified layout + //~| WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn b(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes + unsafe { transmute(x) } + //~^ WARN transmutation to a type with an unspecified layout + //~| WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn c(x: &T) -> &U { @@ -28,14 +34,20 @@ fn c(x: &T) -> &U { fn d(x: &[T]) -> &[U] { unsafe { transmute(x) } + //~^ WARN transmutation to a type with an unspecified layout + //~| WARN transmutation from a type with an unspecified layout } fn e(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes + unsafe { transmute(x) } + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn f(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes + unsafe { transmute(x) } + //~^ WARN transmutation to a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn main() { } diff --git a/src/test/compile-fail/transmute-impl.rs b/src/test/compile-fail/transmute-impl.rs index 2f8f9e46e1aee..15781b90b7f2d 100644 --- a/src/test/compile-fail/transmute-impl.rs +++ b/src/test/compile-fail/transmute-impl.rs @@ -26,7 +26,9 @@ impl Foo { fn n(x: &T) -> &isize { // Not OK here, because T : Sized is not in scope. - unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes + unsafe { transmute(x) } + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } } diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs index 285b079cf96c8..728dfdb84de6a 100644 --- a/src/test/ui/transmute/main.rs +++ b/src/test/ui/transmute/main.rs @@ -31,12 +31,16 @@ unsafe fn sizes() { } unsafe fn ptrs() { - let x: u8 = transmute("test"); //~ ERROR transmute called with types of different sizes + let x: u8 = transmute("test"); + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } union Foo { x: () } unsafe fn vary() { - let x: Foo = transmute(10); //~ ERROR transmute called with types of different sizes + let x: Foo = transmute(10); + //~^ WARN transmutation to a type with an unspecified layout + //~| ERROR transmute called with types of different sizes } fn main() {} diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index 7f6ee749c4fd5..3d724eda57fd5 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -16,19 +16,37 @@ LL | let x: u8 = transmute(10u16); //~ ERROR transmute called with types of = note: source type: u16 (16 bits) = note: target type: u8 (8 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/main.rs:34:17 + | +LL | let x: u8 = transmute("test"); + | ^^^^^^^^^ + | + = note: &str has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes --> $DIR/main.rs:34:17 | -LL | let x: u8 = transmute("test"); //~ ERROR transmute called with types of different sizes +LL | let x: u8 = transmute("test"); | ^^^^^^^^^ | = note: source type: &str ($STR bits) = note: target type: u8 (8 bits) +warning[E0912]: transmutation to a type with an unspecified layout + --> $DIR/main.rs:41:18 + | +LL | let x: Foo = transmute(10); + | ^^^^^^^^^ + | + = note: Foo has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes - --> $DIR/main.rs:39:18 + --> $DIR/main.rs:41:18 | -LL | let x: Foo = transmute(10); //~ ERROR transmute called with types of different sizes +LL | let x: Foo = transmute(10); | ^^^^^^^^^ | = note: source type: i32 (32 bits) @@ -36,4 +54,5 @@ LL | let x: Foo = transmute(10); //~ ERROR transmute called with types of di error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0512`. +Some errors occurred: E0512, E0912. +For more information about an error, try `rustc --explain E0512`. diff --git a/src/test/ui/transmute/transmute-from-fn-item-types-error.rs b/src/test/ui/transmute/transmute-from-fn-item-types-error.rs index 0a0214a24ff2d..56008a5763ad0 100644 --- a/src/test/ui/transmute/transmute-from-fn-item-types-error.rs +++ b/src/test/ui/transmute/transmute-from-fn-item-types-error.rs @@ -12,15 +12,18 @@ use std::mem; unsafe fn foo() -> (i8, *const (), Option) { let i = mem::transmute(bar); - //~^ ERROR transmute called with types of different sizes + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes let p = mem::transmute(foo); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type let of = mem::transmute(main); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type (i, p, of) @@ -29,15 +32,18 @@ unsafe fn foo() -> (i8, *const (), Option) { unsafe fn bar() { // Error as usual if the resulting type is not pointer-sized. mem::transmute::<_, u8>(main); - //~^ ERROR transmute called with types of different sizes + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR transmute called with types of different sizes mem::transmute::<_, *mut ()>(foo); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type mem::transmute::<_, fn()>(bar); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type // No error if a coercion would otherwise occur. @@ -46,15 +52,18 @@ unsafe fn bar() { unsafe fn baz() { mem::transmute::<_, *mut ()>(Some(foo)); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type mem::transmute::<_, fn()>(Some(bar)); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type mem::transmute::<_, Option>(Some(baz)); - //~^ ERROR can't transmute zero-sized type + //~^ WARN transmutation from a type with an unspecified layout + //~| ERROR can't transmute zero-sized type // No error if a coercion would otherwise occur. diff --git a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr index 1591b06f3ac5b..df09952451ee2 100644 --- a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr +++ b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr @@ -1,3 +1,12 @@ +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:14:13 + | +LL | let i = mem::transmute(bar); + | ^^^^^^^^^^^^^^ + | + = note: unsafe fn() {bar} has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes --> $DIR/transmute-from-fn-item-types-error.rs:14:13 | @@ -7,8 +16,17 @@ LL | let i = mem::transmute(bar); = note: source type: unsafe fn() {bar} (0 bits) = note: target type: i8 (8 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:19:13 + | +LL | let p = mem::transmute(foo); + | ^^^^^^^^^^^^^^ + | + = note: unsafe fn() -> (i8, *const (), std::option::Option) {foo} has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:18:13 + --> $DIR/transmute-from-fn-item-types-error.rs:19:13 | LL | let p = mem::transmute(foo); | ^^^^^^^^^^^^^^ @@ -17,8 +35,17 @@ LL | let p = mem::transmute(foo); = note: target type: *const () = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:24:14 + | +LL | let of = mem::transmute(main); + | ^^^^^^^^^^^^^^ + | + = note: fn() {main} has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:22:14 + --> $DIR/transmute-from-fn-item-types-error.rs:24:14 | LL | let of = mem::transmute(main); | ^^^^^^^^^^^^^^ @@ -27,8 +54,17 @@ LL | let of = mem::transmute(main); = note: target type: std::option::Option = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:34:5 + | +LL | mem::transmute::<_, u8>(main); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: fn() {main} has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes - --> $DIR/transmute-from-fn-item-types-error.rs:31:5 + --> $DIR/transmute-from-fn-item-types-error.rs:34:5 | LL | mem::transmute::<_, u8>(main); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,8 +72,17 @@ LL | mem::transmute::<_, u8>(main); = note: source type: fn() {main} (0 bits) = note: target type: u8 (8 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:39:5 + | +LL | mem::transmute::<_, *mut ()>(foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsafe fn() -> (i8, *const (), std::option::Option) {foo} has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:35:5 + --> $DIR/transmute-from-fn-item-types-error.rs:39:5 | LL | mem::transmute::<_, *mut ()>(foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,8 +91,17 @@ LL | mem::transmute::<_, *mut ()>(foo); = note: target type: *mut () = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:44:5 + | +LL | mem::transmute::<_, fn()>(bar); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsafe fn() {bar} has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:39:5 + --> $DIR/transmute-from-fn-item-types-error.rs:44:5 | LL | mem::transmute::<_, fn()>(bar); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,8 +110,17 @@ LL | mem::transmute::<_, fn()>(bar); = note: target type: fn() = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:54:5 + | +LL | mem::transmute::<_, *mut ()>(Some(foo)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: std::option::Option (i8, *const (), std::option::Option) {foo}> has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:48:5 + --> $DIR/transmute-from-fn-item-types-error.rs:54:5 | LL | mem::transmute::<_, *mut ()>(Some(foo)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,8 +129,17 @@ LL | mem::transmute::<_, *mut ()>(Some(foo)); = note: target type: *mut () = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:59:5 + | +LL | mem::transmute::<_, fn()>(Some(bar)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: std::option::Option has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:52:5 + --> $DIR/transmute-from-fn-item-types-error.rs:59:5 | LL | mem::transmute::<_, fn()>(Some(bar)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,8 +148,17 @@ LL | mem::transmute::<_, fn()>(Some(bar)); = note: target type: fn() = help: cast with `as` to a pointer instead +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-from-fn-item-types-error.rs:64:5 + | +LL | mem::transmute::<_, Option>(Some(baz)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: std::option::Option has an unspecified layout + = note: this will become a hard error in the future + error[E0591]: can't transmute zero-sized type - --> $DIR/transmute-from-fn-item-types-error.rs:56:5 + --> $DIR/transmute-from-fn-item-types-error.rs:64:5 | LL | mem::transmute::<_, Option>(Some(baz)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,5 +169,5 @@ LL | mem::transmute::<_, Option>(Some(baz)); error: aborting due to 9 previous errors -Some errors occurred: E0512, E0591. +Some errors occurred: E0512, E0591, E0912. For more information about an error, try `rustc --explain E0512`. diff --git a/src/test/ui/transmute/transmute-type-parameters.rs b/src/test/ui/transmute/transmute-type-parameters.rs index fe340295f74c7..1b65c4056e19f 100644 --- a/src/test/ui/transmute/transmute-type-parameters.rs +++ b/src/test/ui/transmute/transmute-type-parameters.rs @@ -24,7 +24,8 @@ unsafe fn f(x: T) { unsafe fn g(x: (T, i32)) { let _: i32 = transmute(x); -//~^ ERROR transmute called with types of different sizes +//~^ WARN transmutation from a type with an unspecified layout +//~| ERROR transmute called with types of different sizes } unsafe fn h(x: [T; 10]) { @@ -38,7 +39,8 @@ struct Bad { unsafe fn i(x: Bad) { let _: i32 = transmute(x); -//~^ ERROR transmute called with types of different sizes +//~^ WARN transmutation from a type with an unspecified layout +//~| ERROR transmute called with types of different sizes } enum Worse { @@ -48,12 +50,14 @@ enum Worse { unsafe fn j(x: Worse) { let _: i32 = transmute(x); -//~^ ERROR transmute called with types of different sizes +//~^ WARN transmutation from a type with an unspecified layout +//~| ERROR transmute called with types of different sizes } unsafe fn k(x: Option) { let _: i32 = transmute(x); -//~^ ERROR transmute called with types of different sizes +//~^ WARN transmutation from a type with an unspecified layout +//~| ERROR transmute called with types of different sizes } fn main() {} diff --git a/src/test/ui/transmute/transmute-type-parameters.stderr b/src/test/ui/transmute/transmute-type-parameters.stderr index ab0bd8fe2d81f..ec55d961831b0 100644 --- a/src/test/ui/transmute/transmute-type-parameters.stderr +++ b/src/test/ui/transmute/transmute-type-parameters.stderr @@ -7,6 +7,15 @@ LL | let _: i32 = transmute(x); = note: source type: T (this type's size can vary) = note: target type: i32 (32 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-type-parameters.rs:26:18 + | +LL | let _: i32 = transmute(x); + | ^^^^^^^^^ + | + = note: (T, i32) has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes --> $DIR/transmute-type-parameters.rs:26:18 | @@ -17,7 +26,7 @@ LL | let _: i32 = transmute(x); = note: target type: i32 (32 bits) error[E0512]: transmute called with types of different sizes - --> $DIR/transmute-type-parameters.rs:31:18 + --> $DIR/transmute-type-parameters.rs:32:18 | LL | let _: i32 = transmute(x); | ^^^^^^^^^ @@ -25,8 +34,17 @@ LL | let _: i32 = transmute(x); = note: source type: [T; 10] (size can vary because of T) = note: target type: i32 (32 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-type-parameters.rs:41:18 + | +LL | let _: i32 = transmute(x); + | ^^^^^^^^^ + | + = note: Bad has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes - --> $DIR/transmute-type-parameters.rs:40:18 + --> $DIR/transmute-type-parameters.rs:41:18 | LL | let _: i32 = transmute(x); | ^^^^^^^^^ @@ -34,8 +52,17 @@ LL | let _: i32 = transmute(x); = note: source type: Bad (size can vary because of T) = note: target type: i32 (32 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-type-parameters.rs:52:18 + | +LL | let _: i32 = transmute(x); + | ^^^^^^^^^ + | + = note: Worse has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes - --> $DIR/transmute-type-parameters.rs:50:18 + --> $DIR/transmute-type-parameters.rs:52:18 | LL | let _: i32 = transmute(x); | ^^^^^^^^^ @@ -43,8 +70,17 @@ LL | let _: i32 = transmute(x); = note: source type: Worse (size can vary because of T) = note: target type: i32 (32 bits) +warning[E0912]: transmutation from a type with an unspecified layout + --> $DIR/transmute-type-parameters.rs:58:18 + | +LL | let _: i32 = transmute(x); + | ^^^^^^^^^ + | + = note: std::option::Option has an unspecified layout + = note: this will become a hard error in the future + error[E0512]: transmute called with types of different sizes - --> $DIR/transmute-type-parameters.rs:55:18 + --> $DIR/transmute-type-parameters.rs:58:18 | LL | let _: i32 = transmute(x); | ^^^^^^^^^ @@ -54,4 +90,5 @@ LL | let _: i32 = transmute(x); error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0512`. +Some errors occurred: E0512, E0912. +For more information about an error, try `rustc --explain E0512`.