Auto merge of #32939 - eddyb:layout, r=nikomatsakis
Compute LLVM-agnostic type layouts in rustc. Layout for monomorphic types, and some polymorphic ones (e.g. `&T` where `T: Sized`), can now be computed by rustc without involving LLVM in the actual process. This gives rustc the ability to evaluate `size_of` or `align_of`, as well as obtain field offsets. MIR-based CTFE will eventually make use of these layouts, as will MIR trans, shortly. Layout computation also comes with a `[breaking-change]`, or two: * `"data-layout"` is now mandatory in custom target specifications, reverting the decision from #27076. This string is needed because it describes endianness, pointer size and alignments for various types. We have the first two and we could allow tweaking alignments in target specifications. Or we could also extract the data layout from LLVM and feed it back into rustc. However, that can vary with the LLVM version, which is fragile and undermines stability. For built-in targets, I've added a check that the hardcoded data-layout matches LLVM defaults. * `transmute` calls are checked in a stricter fashion, which fixes #32377 To expand on `transmute`, there are only 2 allowed patterns: between types with statically known sizes and between pointers with the same potentially-unsized "tail" (which determines the type of unsized metadata they use, if any). If you're affected, my suggestions are: * try to use casts (and raw pointer deref) instead of transmutes * *really* try to avoid `transmute` where possible * if you have a structure, try working on individual fields and unpack/repack the structure instead of transmuting it whole, e.g. `transmute::<RefCell<Box<T>>, RefCell<*mut T>>(x)` doesn't work, but `RefCell::new(Box::into_raw(x.into_inner()))` does (and `Box::into_raw` is just a `transmute`)
This commit is contained in:
commit
6ece1447f0
@ -71,7 +71,6 @@ pub enum DepNode<D: Clone + Debug> {
|
||||
DeadCheck,
|
||||
StabilityCheck,
|
||||
LateLintCheck,
|
||||
IntrinsicUseCheck,
|
||||
TransCrate,
|
||||
TransCrateItem(D),
|
||||
TransInlinedItem(D),
|
||||
@ -169,7 +168,6 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||
DeadCheck => Some(DeadCheck),
|
||||
StabilityCheck => Some(StabilityCheck),
|
||||
LateLintCheck => Some(LateLintCheck),
|
||||
IntrinsicUseCheck => Some(IntrinsicUseCheck),
|
||||
TransCrate => Some(TransCrate),
|
||||
TransWriteMetadata => Some(TransWriteMetadata),
|
||||
Hir(ref d) => op(d).map(Hir),
|
||||
|
@ -1410,6 +1410,32 @@ It is not possible to use stability attributes outside of the standard library.
|
||||
Also, for now, it is not possible to write deprecation messages either.
|
||||
"##,
|
||||
|
||||
E0512: r##"
|
||||
Transmute with two differently sized types was attempted. Erroneous code
|
||||
example:
|
||||
|
||||
```compile_fail
|
||||
fn takes_u8(_: u8) {}
|
||||
|
||||
fn main() {
|
||||
unsafe { takes_u8(::std::mem::transmute(0u16)); }
|
||||
// error: transmute called with differently sized types
|
||||
}
|
||||
```
|
||||
|
||||
Please use types with same size or use the expected type directly. Example:
|
||||
|
||||
```
|
||||
fn takes_u8(_: u8) {}
|
||||
|
||||
fn main() {
|
||||
unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok!
|
||||
// or:
|
||||
unsafe { takes_u8(0u8); } // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0517: r##"
|
||||
This error indicates that a `#[repr(..)]` attribute was placed on an
|
||||
unsupported item.
|
||||
|
@ -11,11 +11,10 @@
|
||||
use dep_graph::DepNode;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::DefId;
|
||||
use ty::subst::{Subst, Substs, EnumeratedItems};
|
||||
use ty::{TransmuteRestriction, TyCtxt};
|
||||
use ty::{self, Ty, TypeFoldable};
|
||||
|
||||
use std::fmt;
|
||||
use infer::{InferCtxt, new_infer_ctxt};
|
||||
use traits::ProjectionMode;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::layout::{LayoutError, Pointer, SizeSkeleton};
|
||||
|
||||
use syntax::abi::Abi::RustIntrinsic;
|
||||
use syntax::ast;
|
||||
@ -24,219 +23,148 @@ use hir::intravisit::{self, Visitor, FnKind};
|
||||
use hir;
|
||||
|
||||
pub fn check_crate(tcx: &TyCtxt) {
|
||||
let mut visitor = IntrinsicCheckingVisitor {
|
||||
tcx: tcx,
|
||||
param_envs: Vec::new(),
|
||||
dummy_sized_ty: tcx.types.isize,
|
||||
dummy_unsized_ty: tcx.mk_slice(tcx.types.isize),
|
||||
let mut visitor = ItemVisitor {
|
||||
tcx: tcx
|
||||
};
|
||||
tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor);
|
||||
}
|
||||
|
||||
struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a TyCtxt<'tcx>,
|
||||
|
||||
// As we traverse the AST, we keep a stack of the parameter
|
||||
// environments for each function we encounter. When we find a
|
||||
// call to `transmute`, we can check it in the context of the top
|
||||
// of the stack (which ought not to be empty).
|
||||
param_envs: Vec<ty::ParameterEnvironment<'a,'tcx>>,
|
||||
|
||||
// Dummy sized/unsized types that use to substitute for type
|
||||
// parameters in order to estimate how big a type will be for any
|
||||
// possible instantiation of the type parameters in scope. See
|
||||
// `check_transmute` for more details.
|
||||
dummy_sized_ty: Ty<'tcx>,
|
||||
dummy_unsized_ty: Ty<'tcx>,
|
||||
struct ItemVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a TyCtxt<'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
|
||||
fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
|
||||
let infcx = new_infer_ctxt(self.tcx, &self.tcx.tables,
|
||||
Some(param_env),
|
||||
ProjectionMode::Any);
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExprVisitor<'a, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
|
||||
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
|
||||
let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty {
|
||||
let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty {
|
||||
ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
|
||||
_ => return false
|
||||
};
|
||||
intrinsic && self.tcx.item_name(def_id).as_str() == "transmute"
|
||||
intrinsic && self.infcx.tcx.item_name(def_id).as_str() == "transmute"
|
||||
}
|
||||
|
||||
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
|
||||
// Find the parameter environment for the most recent function that
|
||||
// we entered.
|
||||
let sk_from = SizeSkeleton::compute(from, self.infcx);
|
||||
let sk_to = SizeSkeleton::compute(to, self.infcx);
|
||||
|
||||
let param_env = match self.param_envs.last() {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
span_bug!(
|
||||
span,
|
||||
"transmute encountered outside of any fn");
|
||||
// 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;
|
||||
}
|
||||
|
||||
match (&from.sty, sk_to) {
|
||||
(&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
|
||||
if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
|
||||
// FIXME #19925 Remove this warning after a release cycle.
|
||||
let msg = format!("`{}` is now zero-sized and has to be cast \
|
||||
to a pointer before transmuting to `{}`",
|
||||
from, to);
|
||||
self.infcx.tcx.sess.add_lint(
|
||||
::lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES, id, span, msg);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to display a sensible error with as much information as possible.
|
||||
let skeleton_string = |ty: Ty<'tcx>, sk| {
|
||||
match sk {
|
||||
Ok(SizeSkeleton::Known(size)) => {
|
||||
format!("{} bits", size.bits())
|
||||
}
|
||||
Ok(SizeSkeleton::Pointer { tail, .. }) => {
|
||||
format!("pointer to {}", tail)
|
||||
}
|
||||
Err(LayoutError::Unknown(bad)) => {
|
||||
if bad == ty {
|
||||
format!("size can vary")
|
||||
} else {
|
||||
format!("size can vary because of {}", bad)
|
||||
}
|
||||
}
|
||||
Err(err) => err.to_string()
|
||||
}
|
||||
};
|
||||
|
||||
// Simple case: no type parameters involved.
|
||||
if
|
||||
!from.has_param_types() && !from.has_self_ty() &&
|
||||
!to.has_param_types() && !to.has_self_ty()
|
||||
{
|
||||
let restriction = TransmuteRestriction {
|
||||
span: span,
|
||||
original_from: from,
|
||||
original_to: to,
|
||||
substituted_from: from,
|
||||
substituted_to: to,
|
||||
id: id,
|
||||
};
|
||||
self.push_transmute_restriction(restriction);
|
||||
return;
|
||||
}
|
||||
|
||||
// The rules around type parameters are a bit subtle. We are
|
||||
// checking these rules before monomorphization, so there may
|
||||
// be unsubstituted type parameters present in the
|
||||
// types. Obviously we cannot create LLVM types for those.
|
||||
// However, if a type parameter appears only indirectly (i.e.,
|
||||
// through a pointer), it does not necessarily affect the
|
||||
// size, so that should be allowed. The only catch is that we
|
||||
// DO want to be careful around unsized type parameters, since
|
||||
// fat pointers have a different size than a thin pointer, and
|
||||
// hence `&T` and `&U` have different sizes if `T : Sized` but
|
||||
// `U : Sized` does not hold.
|
||||
//
|
||||
// However, it's not as simple as checking whether `T :
|
||||
// Sized`, because even if `T : Sized` does not hold, that
|
||||
// just means that `T` *may* not be sized. After all, even a
|
||||
// type parameter `T: ?Sized` could be bound to a sized
|
||||
// type. (Issue #20116)
|
||||
//
|
||||
// To handle this, we first check for "interior" type
|
||||
// parameters, which are always illegal. If there are none of
|
||||
// those, then we know that the only way that all type
|
||||
// parameters `T` are referenced indirectly, e.g. via a
|
||||
// pointer type like `&T`. In that case, we only care whether
|
||||
// `T` is sized or not, because that influences whether `&T`
|
||||
// is a thin or fat pointer.
|
||||
//
|
||||
// One could imagine establishing a sophisticated constraint
|
||||
// system to ensure that the transmute is legal, but instead
|
||||
// we do something brutally dumb. We just substitute dummy
|
||||
// sized or unsized types for every type parameter in scope,
|
||||
// exhaustively checking all possible combinations. Here are some examples:
|
||||
//
|
||||
// ```
|
||||
// fn foo<T, U>() {
|
||||
// // T=int, U=int
|
||||
// }
|
||||
//
|
||||
// fn bar<T: ?Sized, U>() {
|
||||
// // T=int, U=int
|
||||
// // T=[int], U=int
|
||||
// }
|
||||
//
|
||||
// fn baz<T: ?Sized, U: ?Sized>() {
|
||||
// // T=int, U=int
|
||||
// // T=[int], U=int
|
||||
// // T=int, U=[int]
|
||||
// // T=[int], U=[int]
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// In all cases, we keep the original unsubstituted types
|
||||
// around for error reporting.
|
||||
|
||||
let from_tc = from.type_contents(self.tcx);
|
||||
let to_tc = to.type_contents(self.tcx);
|
||||
if from_tc.interior_param() || to_tc.interior_param() {
|
||||
span_err!(self.tcx.sess, span, E0139,
|
||||
"cannot transmute to or from a type that contains \
|
||||
unsubstituted type parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut substs = param_env.free_substs.clone();
|
||||
self.with_each_combination(
|
||||
span,
|
||||
param_env,
|
||||
param_env.free_substs.types.iter_enumerated(),
|
||||
&mut substs,
|
||||
&mut |substs| {
|
||||
let restriction = TransmuteRestriction {
|
||||
span: span,
|
||||
original_from: from,
|
||||
original_to: to,
|
||||
substituted_from: from.subst(self.tcx, substs),
|
||||
substituted_to: to.subst(self.tcx, substs),
|
||||
id: id,
|
||||
};
|
||||
self.push_transmute_restriction(restriction);
|
||||
});
|
||||
}
|
||||
|
||||
fn with_each_combination(&self,
|
||||
span: Span,
|
||||
param_env: &ty::ParameterEnvironment<'a,'tcx>,
|
||||
mut types_in_scope: EnumeratedItems<Ty<'tcx>>,
|
||||
substs: &mut Substs<'tcx>,
|
||||
callback: &mut FnMut(&Substs<'tcx>))
|
||||
{
|
||||
// This parameter invokes `callback` many times with different
|
||||
// substitutions that replace all the parameters in scope with
|
||||
// either `int` or `[int]`, depending on whether the type
|
||||
// parameter is known to be sized. See big comment above for
|
||||
// an explanation of why this is a reasonable thing to do.
|
||||
|
||||
match types_in_scope.next() {
|
||||
None => {
|
||||
debug!("with_each_combination(substs={:?})",
|
||||
substs);
|
||||
|
||||
callback(substs);
|
||||
}
|
||||
|
||||
Some((space, index, ¶m_ty)) => {
|
||||
debug!("with_each_combination: space={:?}, index={}, param_ty={:?}",
|
||||
space, index, param_ty);
|
||||
|
||||
if !param_ty.is_sized(param_env, span) {
|
||||
debug!("with_each_combination: param_ty is not known to be sized");
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
|
||||
self.with_each_combination(span, param_env, types_in_scope.clone(),
|
||||
substs, callback);
|
||||
}
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
|
||||
self.with_each_combination(span, param_env, types_in_scope,
|
||||
substs, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
|
||||
debug!("Pushing transmute restriction: {:?}", restriction);
|
||||
self.tcx.transmute_restrictions.borrow_mut().push(restriction);
|
||||
span_err!(self.infcx.tcx.sess, span, E0512,
|
||||
"transmute called with differently sized types: \
|
||||
{} ({}) to {} ({})",
|
||||
from, skeleton_string(from, sk_from),
|
||||
to, skeleton_string(to, sk_to));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
|
||||
// const, static and N in [T; N].
|
||||
fn visit_expr(&mut self, expr: &hir::Expr) {
|
||||
let infcx = new_infer_ctxt(self.tcx, &self.tcx.tables,
|
||||
None, ProjectionMode::Any);
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &hir::TraitItem) {
|
||||
if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
|
||||
self.visit_const(item.id, expr);
|
||||
} else {
|
||||
intravisit::walk_trait_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &hir::ImplItem) {
|
||||
if let hir::ImplItemKind::Const(_, ref expr) = item.node {
|
||||
self.visit_const(item.id, expr);
|
||||
} else {
|
||||
intravisit::walk_impl_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
|
||||
b: &'v hir::Block, s: Span, id: ast::NodeId) {
|
||||
match fk {
|
||||
FnKind::ItemFn(..) | FnKind::Method(..) => {
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
self.param_envs.push(param_env);
|
||||
intravisit::walk_fn(self, fk, fd, b, s);
|
||||
self.param_envs.pop();
|
||||
let infcx = new_infer_ctxt(self.tcx, &self.tcx.tables,
|
||||
Some(param_env),
|
||||
ProjectionMode::Any);
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_fn(fk, fd, b, s, id);
|
||||
}
|
||||
FnKind::Closure(..) => {
|
||||
intravisit::walk_fn(self, fk, fd, b, s);
|
||||
span_bug!(s, "intrinsicck: closure outside of function")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &hir::Expr) {
|
||||
if let hir::ExprPath(..) = expr.node {
|
||||
match self.tcx.resolve_expr(expr) {
|
||||
match self.infcx.tcx.resolve_expr(expr) {
|
||||
Def::Fn(did) if self.def_id_is_transmute(did) => {
|
||||
let typ = self.tcx.node_id_to_type(expr.id);
|
||||
let typ = self.infcx.tcx.node_id_to_type(expr.id);
|
||||
match typ.sty {
|
||||
ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
|
||||
if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
|
||||
@ -256,14 +184,3 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for TransmuteRestriction<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TransmuteRestriction(id={}, original=({:?},{:?}), substituted=({:?},{:?}))",
|
||||
self.id,
|
||||
self.original_from,
|
||||
self.original_to,
|
||||
self.substituted_from,
|
||||
self.substituted_to)
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ use hir::FreevarMap;
|
||||
use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
|
||||
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
|
||||
use ty::TypeVariants::*;
|
||||
use ty::layout::{Layout, TargetDataLayout};
|
||||
use ty::maps;
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
||||
@ -55,6 +56,7 @@ pub struct CtxtArenas<'tcx> {
|
||||
bare_fn: TypedArena<BareFnTy<'tcx>>,
|
||||
region: TypedArena<Region>,
|
||||
stability: TypedArena<attr::Stability>,
|
||||
layout: TypedArena<Layout>,
|
||||
|
||||
// references
|
||||
trait_defs: TypedArena<ty::TraitDef<'tcx>>,
|
||||
@ -69,6 +71,7 @@ impl<'tcx> CtxtArenas<'tcx> {
|
||||
bare_fn: TypedArena::new(),
|
||||
region: TypedArena::new(),
|
||||
stability: TypedArena::new(),
|
||||
layout: TypedArena::new(),
|
||||
|
||||
trait_defs: TypedArena::new(),
|
||||
adt_defs: TypedArena::new()
|
||||
@ -229,6 +232,7 @@ pub struct TyCtxt<'tcx> {
|
||||
bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
|
||||
region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
|
||||
stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
|
||||
layout_interner: RefCell<FnvHashMap<&'tcx Layout, &'tcx Layout>>,
|
||||
|
||||
pub dep_graph: DepGraph,
|
||||
|
||||
@ -353,11 +357,6 @@ pub struct TyCtxt<'tcx> {
|
||||
pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
|
||||
lint::LevelSource>>,
|
||||
|
||||
/// The types that must be asserted to be the same size for `transmute`
|
||||
/// to be valid. We gather up these restrictions in the intrinsicck pass
|
||||
/// and check them in trans.
|
||||
pub transmute_restrictions: RefCell<Vec<ty::TransmuteRestriction<'tcx>>>,
|
||||
|
||||
/// Maps any item's def-id to its stability index.
|
||||
pub stability: RefCell<stability::Index<'tcx>>,
|
||||
|
||||
@ -419,6 +418,12 @@ pub struct TyCtxt<'tcx> {
|
||||
/// The definite name of the current crate after taking into account
|
||||
/// attributes, commandline parameters, etc.
|
||||
pub crate_name: token::InternedString,
|
||||
|
||||
/// Data layout specification for the current target.
|
||||
pub data_layout: TargetDataLayout,
|
||||
|
||||
/// Cache for layouts computed from types.
|
||||
pub layout_cache: RefCell<FnvHashMap<Ty<'tcx>, &'tcx Layout>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
@ -500,6 +505,20 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
interned
|
||||
}
|
||||
|
||||
pub fn intern_layout(&self, layout: Layout) -> &'tcx Layout {
|
||||
if let Some(layout) = self.layout_interner.borrow().get(&layout) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
let interned = self.arenas.layout.alloc(layout);
|
||||
if let Some(prev) = self.layout_interner
|
||||
.borrow_mut()
|
||||
.insert(interned, interned) {
|
||||
bug!("Tried to overwrite interned Layout: {:?}", prev)
|
||||
}
|
||||
interned
|
||||
}
|
||||
|
||||
pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
|
||||
if self.free_region_maps.borrow_mut().insert(id, map).is_some() {
|
||||
bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id)
|
||||
@ -531,6 +550,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
f: F) -> R
|
||||
where F: FnOnce(&TyCtxt<'tcx>) -> R
|
||||
{
|
||||
let data_layout = TargetDataLayout::parse(s);
|
||||
let interner = RefCell::new(FnvHashMap());
|
||||
let common_types = CommonTypes::new(&arenas.type_, &interner);
|
||||
let dep_graph = map.dep_graph.clone();
|
||||
@ -542,6 +562,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
bare_fn_interner: RefCell::new(FnvHashMap()),
|
||||
region_interner: RefCell::new(FnvHashMap()),
|
||||
stability_interner: RefCell::new(FnvHashMap()),
|
||||
layout_interner: RefCell::new(FnvHashMap()),
|
||||
dep_graph: dep_graph.clone(),
|
||||
types: common_types,
|
||||
named_region_map: named_region_map,
|
||||
@ -579,7 +600,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
extern_const_statics: RefCell::new(DefIdMap()),
|
||||
extern_const_fns: RefCell::new(DefIdMap()),
|
||||
node_lint_levels: RefCell::new(FnvHashMap()),
|
||||
transmute_restrictions: RefCell::new(Vec::new()),
|
||||
stability: RefCell::new(stability),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
@ -589,6 +609,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
cast_kinds: RefCell::new(NodeMap()),
|
||||
fragment_infos: RefCell::new(DefIdMap()),
|
||||
crate_name: token::intern_and_get_ident(crate_name),
|
||||
data_layout: data_layout,
|
||||
layout_cache: RefCell::new(FnvHashMap()),
|
||||
}, f)
|
||||
}
|
||||
}
|
||||
@ -762,6 +784,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
|
||||
println!("Region interner: #{}", self.region_interner.borrow().len());
|
||||
println!("Stability interner: #{}", self.stability_interner.borrow().len());
|
||||
println!("Layout interner: #{}", self.layout_interner.borrow().len());
|
||||
}
|
||||
}
|
||||
|
||||
|
1336
src/librustc/ty/layout.rs
Normal file
1336
src/librustc/ty/layout.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -84,6 +84,7 @@ pub mod error;
|
||||
pub mod fast_reject;
|
||||
pub mod fold;
|
||||
pub mod item_path;
|
||||
pub mod layout;
|
||||
pub mod _match;
|
||||
pub mod maps;
|
||||
pub mod outlives;
|
||||
@ -479,37 +480,6 @@ pub struct CReaderCacheKey {
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
/// A restriction that certain types must be the same size. The use of
|
||||
/// `transmute` gives rise to these restrictions. These generally
|
||||
/// cannot be checked until trans; therefore, each call to `transmute`
|
||||
/// will push one or more such restriction into the
|
||||
/// `transmute_restrictions` vector during `intrinsicck`. They are
|
||||
/// then checked during `trans` by the fn `check_intrinsics`.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TransmuteRestriction<'tcx> {
|
||||
/// The span whence the restriction comes.
|
||||
pub span: Span,
|
||||
|
||||
/// The type being transmuted from.
|
||||
pub original_from: Ty<'tcx>,
|
||||
|
||||
/// The type being transmuted to.
|
||||
pub original_to: Ty<'tcx>,
|
||||
|
||||
/// The type being transmuted from, with all type parameters
|
||||
/// substituted for an arbitrary representative. Not to be shown
|
||||
/// to the end user.
|
||||
pub substituted_from: Ty<'tcx>,
|
||||
|
||||
/// The type being transmuted to, with all type parameters
|
||||
/// substituted for an arbitrary representative. Not to be shown
|
||||
/// to the end user.
|
||||
pub substituted_to: Ty<'tcx>,
|
||||
|
||||
/// NodeId of the transmute intrinsic.
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
/// Describes the fragment-state associated with a NodeId.
|
||||
///
|
||||
/// Currently only unfragmented paths have entries in the table,
|
||||
|
@ -18,6 +18,7 @@ use hir::pat_util;
|
||||
use traits::{self, ProjectionMode};
|
||||
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
||||
use ty::{Disr, ParameterEnvironment};
|
||||
use ty::layout::{Layout, LayoutError};
|
||||
use ty::TypeVariants::*;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
@ -597,6 +598,24 @@ impl<'tcx> ty::TyS<'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout<'a>(&'tcx self, infcx: &infer::InferCtxt<'a, 'tcx>)
|
||||
-> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
let can_cache = !self.has_param_types() && !self.has_self_ty();
|
||||
if can_cache {
|
||||
if let Some(&cached) = infcx.tcx.layout_cache.borrow().get(&self) {
|
||||
return Ok(cached);
|
||||
}
|
||||
}
|
||||
|
||||
let layout = Layout::compute_uncached(self, infcx)?;
|
||||
let layout = infcx.tcx.intern_layout(layout);
|
||||
if can_cache {
|
||||
infcx.tcx.layout_cache.borrow_mut().insert(self, layout);
|
||||
}
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
|
||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
||||
/// structural recursion. This check is needed for structs and enums.
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "arm64-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -15,6 +15,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "aarch64-linux-android".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -17,6 +17,7 @@ pub fn target() -> Target {
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "arm-linux-androideabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnueabi".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnueabihf".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "armv7-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnueabihf".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "armv7s-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -31,6 +31,7 @@ pub fn target() -> Target {
|
||||
target_os: "emscripten".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
|
||||
arch: "asmjs".to_string(),
|
||||
options: opts,
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i386-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-apple-darwin".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "macos".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-linux-android".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -22,6 +22,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-pc-windows-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -27,6 +27,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-pc-windows-msvc".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "msvc".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-unknown-dragonfly".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "dragonfly".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-unknown-freebsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "freebsd".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -37,6 +37,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "i686-unknown-linux-musl".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
|
@ -34,6 +34,7 @@ pub fn target() -> Target {
|
||||
target_os: "nacl".to_string(),
|
||||
target_env: "newlib".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
|
||||
arch: "le32".to_string(),
|
||||
options: opts,
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "mips-unknown-linux-gnu".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
|
||||
arch: "mips".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -15,6 +15,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "mips-unknown-linux-musl".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
|
||||
arch: "mips".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
|
@ -15,6 +15,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "mipsel-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
|
||||
arch: "mips".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -15,6 +15,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "mipsel-unknown-linux-musl".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
|
||||
arch: "mips".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
|
@ -39,10 +39,10 @@
|
||||
//! this module defines the format the JSON file should take, though each
|
||||
//! underscore in the field names should be replaced with a hyphen (`-`) in the
|
||||
//! JSON file. Some fields are required in every target specification, such as
|
||||
//! `llvm-target`, `target-endian`, `target-pointer-width`, `arch`, and
|
||||
//! `os`. In general, options passed to rustc with `-C` override the target's
|
||||
//! settings, though `target-feature` and `link-args` will *add* to the list
|
||||
//! specified by the target, rather than replace.
|
||||
//! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`,
|
||||
//! `arch`, and `os`. In general, options passed to rustc with `-C` override
|
||||
//! the target's settings, though `target-feature` and `link-args` will *add*
|
||||
//! to the list specified by the target, rather than replace.
|
||||
|
||||
use serialize::json::Json;
|
||||
use std::default::Default;
|
||||
@ -75,7 +75,8 @@ macro_rules! supported_targets {
|
||||
if false { }
|
||||
$(
|
||||
else if target == stringify!($module) {
|
||||
let t = $module::target();
|
||||
let mut t = $module::target();
|
||||
t.options.is_builtin = true;
|
||||
debug!("Got builtin target: {:?}", t);
|
||||
return Some(t);
|
||||
}
|
||||
@ -161,6 +162,8 @@ pub struct Target {
|
||||
/// Architecture to use for ABI considerations. Valid options: "x86",
|
||||
/// "x86_64", "arm", "aarch64", "mips", "powerpc", and "powerpc64".
|
||||
pub arch: String,
|
||||
/// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
|
||||
pub data_layout: String,
|
||||
/// Optional settings with defaults.
|
||||
pub options: TargetOptions,
|
||||
}
|
||||
@ -171,8 +174,9 @@ pub struct Target {
|
||||
/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TargetOptions {
|
||||
/// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
|
||||
pub data_layout: Option<String>,
|
||||
/// Whether the target is built-in or loaded from a custom target specification.
|
||||
pub is_builtin: bool,
|
||||
|
||||
/// Linker to invoke. Defaults to "cc".
|
||||
pub linker: String,
|
||||
/// Archive utility to use when managing archives. Defaults to "ar".
|
||||
@ -293,7 +297,7 @@ impl Default for TargetOptions {
|
||||
/// incomplete, and if used for compilation, will certainly not work.
|
||||
fn default() -> TargetOptions {
|
||||
TargetOptions {
|
||||
data_layout: None,
|
||||
is_builtin: false,
|
||||
linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
|
||||
ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(),
|
||||
pre_link_args: Vec::new(),
|
||||
@ -378,6 +382,7 @@ impl Target {
|
||||
llvm_target: get_req_field("llvm-target"),
|
||||
target_endian: get_req_field("target-endian"),
|
||||
target_pointer_width: get_req_field("target-pointer-width"),
|
||||
data_layout: get_req_field("data-layout"),
|
||||
arch: get_req_field("arch"),
|
||||
target_os: get_req_field("os"),
|
||||
target_env: get_opt_field("env", ""),
|
||||
@ -426,7 +431,6 @@ impl Target {
|
||||
key!(staticlib_prefix);
|
||||
key!(staticlib_suffix);
|
||||
key!(features);
|
||||
key!(data_layout, optional);
|
||||
key!(dynamic_linking, bool);
|
||||
key!(executables, bool);
|
||||
key!(disable_redzone, bool);
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "E-m:e-i64:64-n32:64".to_string(),
|
||||
arch: "powerpc64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-n32:64".to_string(),
|
||||
arch: "powerpc64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "powerpc-unknown-linux-gnu".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
|
||||
arch: "powerpc".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -20,6 +20,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-apple-darwin".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "macos".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -16,6 +16,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-pc-windows-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-pc-windows-msvc".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "msvc".to_string(),
|
||||
|
@ -27,6 +27,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-rumprun-netbsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "netbsd".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-pc-solaris".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "solaris".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-bitrig".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "bitrig".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-dragonfly".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "dragonfly".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-freebsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "freebsd".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
|
@ -73,6 +73,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-linux-musl".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
|
@ -18,6 +18,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-netbsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "netbsd".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||
llvm_target: "x86_64-unknown-openbsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
|
||||
arch: "x86_64".to_string(),
|
||||
target_os: "openbsd".to_string(),
|
||||
target_env: "".to_string(),
|
||||
|
@ -32,18 +32,7 @@ use rustc::ty::{self, Ty};
|
||||
use libc::c_uint;
|
||||
|
||||
pub use syntax::abi::Abi;
|
||||
|
||||
/// The first half of a fat pointer.
|
||||
/// - For a closure, this is the code address.
|
||||
/// - For an object or trait instance, this is the address of the box.
|
||||
/// - For a slice, this is the base address.
|
||||
pub const FAT_PTR_ADDR: usize = 0;
|
||||
|
||||
/// The second half of a fat pointer.
|
||||
/// - For a closure, this is the address of the environment.
|
||||
/// - For an object or trait instance, this is the address of the vtable.
|
||||
/// - For a slice, this is the length.
|
||||
pub const FAT_PTR_EXTRA: usize = 1;
|
||||
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum ArgKind {
|
||||
|
@ -78,7 +78,6 @@ use declare;
|
||||
use expr;
|
||||
use glue;
|
||||
use inline;
|
||||
use intrinsic;
|
||||
use machine;
|
||||
use machine::{llalign_of_min, llsize_of, llsize_of_real};
|
||||
use meth;
|
||||
@ -2750,13 +2749,9 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
|
||||
{
|
||||
let ccx = shared_ccx.get_ccx(0);
|
||||
|
||||
// First, verify intrinsics.
|
||||
intrinsic::check_intrinsics(&ccx);
|
||||
|
||||
collect_translation_items(&ccx);
|
||||
|
||||
// Next, translate all items. See `TransModVisitor` for
|
||||
// Translate all items. See `TransModVisitor` for
|
||||
// details on why we walk in this particular way.
|
||||
{
|
||||
let _icx = push_ctxt("text");
|
||||
|
@ -36,11 +36,12 @@ use session::Session;
|
||||
use util::sha2::Sha256;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token::InternedString;
|
||||
|
||||
@ -255,15 +256,28 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR
|
||||
let mod_name = CString::new(mod_name).unwrap();
|
||||
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
|
||||
|
||||
if let Some(ref custom_data_layout) = sess.target.target.options.data_layout {
|
||||
let data_layout = CString::new(&custom_data_layout[..]).unwrap();
|
||||
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||
} else {
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
if sess.target.target.options.is_builtin {
|
||||
let tm = ::back::write::create_target_machine(sess);
|
||||
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
|
||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
||||
|
||||
let data_layout = llvm::LLVMGetDataLayout(llmod);
|
||||
let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes())
|
||||
.ok().expect("got a non-UTF8 data-layout from LLVM");
|
||||
|
||||
if sess.target.target.data_layout != data_layout {
|
||||
bug!("data-layout for builtin `{}` target, `{}`, \
|
||||
differs from LLVM default, `{}`",
|
||||
sess.target.target.llvm_target,
|
||||
sess.target.target.data_layout,
|
||||
data_layout);
|
||||
}
|
||||
}
|
||||
|
||||
let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap();
|
||||
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||
|
||||
let llvm_target = sess.target.target.llvm_target.as_bytes();
|
||||
let llvm_target = CString::new(llvm_target).unwrap();
|
||||
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||
@ -770,23 +784,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
&self.local.trait_cache
|
||||
}
|
||||
|
||||
/// Return exclusive upper bound on object size.
|
||||
///
|
||||
/// The theoretical maximum object size is defined as the maximum positive `int` value. This
|
||||
/// ensures that the `offset` semantics remain well-defined by allowing it to correctly index
|
||||
/// every address within an object along with one byte past the end, along with allowing `int`
|
||||
/// to store the difference between any two pointers into an object.
|
||||
///
|
||||
/// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to
|
||||
/// represent object size in bits. It would need to be 1 << 61 to account for this, but is
|
||||
/// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
|
||||
/// address space on 64-bit ARMv8 and x86_64.
|
||||
pub fn obj_size_bound(&self) -> u64 {
|
||||
match &self.sess().target.target.target_pointer_width[..] {
|
||||
"32" => 1 << 31,
|
||||
"64" => 1 << 47,
|
||||
_ => bug!() // error handled by config::build_target_config
|
||||
}
|
||||
self.tcx().data_layout.obj_size_bound()
|
||||
}
|
||||
|
||||
pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! {
|
||||
|
@ -83,32 +83,6 @@ unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0512: r##"
|
||||
Transmute with two differently sized types was attempted. Erroneous code
|
||||
example:
|
||||
|
||||
```compile_fail
|
||||
fn takes_u8(_: u8) {}
|
||||
|
||||
fn main() {
|
||||
unsafe { takes_u8(::std::mem::transmute(0u16)); }
|
||||
// error: transmute called with differently sized types
|
||||
}
|
||||
```
|
||||
|
||||
Please use types with same size or use the expected type directly. Example:
|
||||
|
||||
```
|
||||
fn takes_u8(_: u8) {}
|
||||
|
||||
fn main() {
|
||||
unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok!
|
||||
// or:
|
||||
unsafe { takes_u8(0u8); } // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0515: r##"
|
||||
A constant index expression was out of bounds. Erroneous code example:
|
||||
|
||||
|
@ -36,16 +36,14 @@ use glue;
|
||||
use type_of;
|
||||
use machine;
|
||||
use type_::Type;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::{self, Ty};
|
||||
use Disr;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax::parse::token;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::session::Session;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
|
||||
@ -97,76 +95,6 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
|
||||
Some(ccx.get_intrinsic(&llvm_name))
|
||||
}
|
||||
|
||||
pub fn span_transmute_size_error(a: &Session, b: Span, msg: &str) {
|
||||
span_err!(a, b, E0512, "{}", msg);
|
||||
}
|
||||
|
||||
/// Performs late verification that intrinsics are used correctly. At present,
|
||||
/// the only intrinsic that needs such verification is `transmute`.
|
||||
pub fn check_intrinsics(ccx: &CrateContext) {
|
||||
let _task = ccx.tcx().dep_graph.in_task(DepNode::IntrinsicUseCheck);
|
||||
let mut last_failing_id = None;
|
||||
for transmute_restriction in ccx.tcx().transmute_restrictions.borrow().iter() {
|
||||
// Sometimes, a single call to transmute will push multiple
|
||||
// type pairs to test in order to exhaustively test the
|
||||
// possibility around a type parameter. If one of those fails,
|
||||
// there is no sense reporting errors on the others.
|
||||
if last_failing_id == Some(transmute_restriction.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!("transmute_restriction: {:?}", transmute_restriction);
|
||||
|
||||
assert!(!transmute_restriction.substituted_from.has_param_types());
|
||||
assert!(!transmute_restriction.substituted_to.has_param_types());
|
||||
|
||||
let llfromtype = type_of::sizing_type_of(ccx,
|
||||
transmute_restriction.substituted_from);
|
||||
let lltotype = type_of::sizing_type_of(ccx,
|
||||
transmute_restriction.substituted_to);
|
||||
let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
|
||||
let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
|
||||
|
||||
if let ty::TyFnDef(..) = transmute_restriction.substituted_from.sty {
|
||||
if to_type_size == machine::llbitsize_of_real(ccx, ccx.int_type()) {
|
||||
// FIXME #19925 Remove this warning after a release cycle.
|
||||
lint::raw_emit_lint(&ccx.tcx().sess,
|
||||
&ccx.tcx().sess.lint_store.borrow(),
|
||||
lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES,
|
||||
(lint::Warn, lint::LintSource::Default),
|
||||
Some(transmute_restriction.span),
|
||||
&format!("`{}` is now zero-sized and has to be cast \
|
||||
to a pointer before transmuting to `{}`",
|
||||
transmute_restriction.substituted_from,
|
||||
transmute_restriction.substituted_to));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if from_type_size != to_type_size {
|
||||
last_failing_id = Some(transmute_restriction.id);
|
||||
|
||||
if transmute_restriction.original_from != transmute_restriction.substituted_from {
|
||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||
&format!("transmute called with differently sized types: \
|
||||
{} (could be {} bits) to {} (could be {} bits)",
|
||||
transmute_restriction.original_from,
|
||||
from_type_size,
|
||||
transmute_restriction.original_to,
|
||||
to_type_size));
|
||||
} else {
|
||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||
&format!("transmute called with differently sized types: \
|
||||
{} ({} bits) to {} ({} bits)",
|
||||
transmute_restriction.original_from,
|
||||
from_type_size,
|
||||
transmute_restriction.original_to,
|
||||
to_type_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
ccx.sess().abort_if_errors();
|
||||
}
|
||||
|
||||
/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
|
||||
/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
|
||||
/// add them to librustc_trans/trans/context.rs
|
||||
|
@ -17,6 +17,7 @@ use abi::FnType;
|
||||
use adt;
|
||||
use common::*;
|
||||
use machine;
|
||||
use rustc::traits::ProjectionMode;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
|
||||
use type_::Type;
|
||||
@ -121,6 +122,37 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
||||
debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
|
||||
|
||||
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
|
||||
|
||||
// FIXME(eddyb) Temporary sanity check for ty::layout.
|
||||
let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables, ProjectionMode::Any);
|
||||
match t.layout(&infcx) {
|
||||
Ok(layout) => {
|
||||
if !type_is_sized(cx.tcx(), t) {
|
||||
if !layout.is_unsized() {
|
||||
bug!("layout should be unsized for type `{}` / {:#?}",
|
||||
t, layout);
|
||||
}
|
||||
|
||||
// Unsized types get turned into a fat pointer for LLVM.
|
||||
return llsizingty;
|
||||
}
|
||||
let r = layout.size(&cx.tcx().data_layout).bytes();
|
||||
let l = machine::llsize_of_alloc(cx, llsizingty);
|
||||
if r != l {
|
||||
bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
|
||||
r, l, t, layout);
|
||||
}
|
||||
let r = layout.align(&cx.tcx().data_layout).abi();
|
||||
let l = machine::llalign_of_min(cx, llsizingty) as u64;
|
||||
if r != l {
|
||||
bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
|
||||
r, l, t, layout);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
bug!("failed to get layout for `{}`: {}", t, e);
|
||||
}
|
||||
}
|
||||
llsizingty
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ trait Trait<'a> {
|
||||
|
||||
fn foo<'a, T: Trait<'a>>(value: T::A) {
|
||||
let new: T::B = unsafe { std::mem::transmute(value) };
|
||||
//~^ ERROR: cannot transmute to or from a type that contains unsubstituted type parameters [E0139]
|
||||
//~^ ERROR: transmute called with differently sized types
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
27
src/test/compile-fail/issue-32377.rs
Normal file
27
src/test/compile-fail/issue-32377.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::mem;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait Foo {
|
||||
type Error;
|
||||
}
|
||||
|
||||
struct Bar<U: Foo> {
|
||||
stream: PhantomData<U::Error>,
|
||||
}
|
||||
|
||||
fn foo<U: Foo>(x: [usize; 2]) -> Bar<U> {
|
||||
unsafe { mem::transmute(x) }
|
||||
//~^ ERROR transmute called with differently sized types
|
||||
}
|
||||
|
||||
fn main() {}
|
23
src/test/compile-fail/transmute-from-fn-item-types-error.rs
Normal file
23
src/test/compile-fail/transmute-from-fn-item-types-error.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::mem;
|
||||
|
||||
unsafe fn bar() {
|
||||
// Error, still, if the resulting type is not pointer-sized.
|
||||
mem::transmute::<_, u8>(main);
|
||||
//~^ ERROR transmute called with differently sized types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
bar();
|
||||
}
|
||||
}
|
@ -8,39 +8,37 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(transmute_from_fn_item_types)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
unsafe fn foo() -> (isize, *const (), Option<fn()>) {
|
||||
let i = mem::transmute(bar);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
//~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ ERROR was previously accepted
|
||||
|
||||
let p = mem::transmute(foo);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
//~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ ERROR was previously accepted
|
||||
|
||||
let of = mem::transmute(main);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
//~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ ERROR was previously accepted
|
||||
|
||||
(i, p, of)
|
||||
}
|
||||
|
||||
unsafe fn bar() {
|
||||
mem::transmute::<_, *mut ()>(foo);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
//~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ ERROR was previously accepted
|
||||
|
||||
mem::transmute::<_, fn()>(bar);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
//~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ ERROR was previously accepted
|
||||
|
||||
// No error if a coercion would otherwise occur.
|
||||
mem::transmute::<fn(), usize>(main);
|
||||
|
||||
// Error, still, if the resulting type is not pointer-sized.
|
||||
mem::transmute::<_, u8>(main);
|
||||
//~^ ERROR transmute called with differently sized types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -13,15 +13,18 @@
|
||||
use std::mem::transmute;
|
||||
|
||||
unsafe fn f<T>(x: T) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: T (size can vary) to isize
|
||||
}
|
||||
|
||||
unsafe fn g<T>(x: (T, isize)) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: (T, isize) (size can vary because of T) to isize
|
||||
}
|
||||
|
||||
unsafe fn h<T>(x: [T; 10]) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: [T; 10] (size can vary because of T) to isize
|
||||
}
|
||||
|
||||
struct Bad<T> {
|
||||
@ -29,7 +32,8 @@ struct Bad<T> {
|
||||
}
|
||||
|
||||
unsafe fn i<T>(x: Bad<T>) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: Bad<T> (size can vary because of T) to isize
|
||||
}
|
||||
|
||||
enum Worse<T> {
|
||||
@ -38,11 +42,13 @@ enum Worse<T> {
|
||||
}
|
||||
|
||||
unsafe fn j<T>(x: Worse<T>) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: Worse<T> (size can vary because of T) to isize
|
||||
}
|
||||
|
||||
unsafe fn k<T>(x: Option<T>) {
|
||||
let _: isize = transmute(x); //~ ERROR cannot transmute
|
||||
let _: isize = transmute(x);
|
||||
//~^ ERROR differently sized types: std::option::Option<T> (size can vary because of T) to isize
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
|
||||
"llvm-target": "i686-unknown-linux-gnu",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "32",
|
||||
|
Loading…
x
Reference in New Issue
Block a user