about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <andersrb@gmail.com>2016-05-04 11:35:08 -0700
committerBrian Anderson <andersrb@gmail.com>2016-05-04 11:35:08 -0700
commit87cb733048f0072199b66bb3c0efe61d52623900 (patch)
tree2d4809584f7cfa432c54a1fa619b3cf37d506916
parentd8d51ac19c42b07246fe0e5e8a4cae935b50d338 (diff)
parent4497b73051a87dd3595a478ea6854a22b671ca62 (diff)
downloadrust-87cb733048f0072199b66bb3c0efe61d52623900.tar.gz
rust-87cb733048f0072199b66bb3c0efe61d52623900.zip
Merge pull request #33407 from alexcrichton/beta-next
Merge beta-accepted into beta
-rw-r--r--RELEASES.md288
-rw-r--r--mk/main.mk2
-rw-r--r--src/librustc/dep_graph/dep_node.rs2
-rw-r--r--src/librustc/diagnostics.rs26
-rw-r--r--src/librustc/middle/intrinsicck.rs289
-rw-r--r--src/librustc/ty/context.rs35
-rw-r--r--src/librustc/ty/layout.rs1336
-rw-r--r--src/librustc/ty/mod.rs32
-rw-r--r--src/librustc/ty/util.rs19
-rw-r--r--src/librustc_back/target/aarch64_apple_ios.rs1
-rw-r--r--src/librustc_back/target/aarch64_linux_android.rs1
-rw-r--r--src/librustc_back/target/aarch64_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs1
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs1
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs1
-rw-r--r--src/librustc_back/target/armv7_apple_ios.rs1
-rw-r--r--src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs1
-rw-r--r--src/librustc_back/target/armv7s_apple_ios.rs1
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/i386_apple_ios.rs1
-rw-r--r--src/librustc_back/target/i686_apple_darwin.rs1
-rw-r--r--src/librustc_back/target/i686_linux_android.rs1
-rw-r--r--src/librustc_back/target/i686_pc_windows_gnu.rs1
-rw-r--r--src/librustc_back/target/i686_pc_windows_msvc.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_dragonfly.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_freebsd.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/le32_unknown_nacl.rs1
-rw-r--r--src/librustc_back/target/mips_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/mips_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/mipsel_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/mipsel_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/mod.rs22
-rw-r--r--src/librustc_back/target/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/powerpc_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_apple_darwin.rs1
-rw-r--r--src/librustc_back/target/x86_64_apple_ios.rs1
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_msvc.rs1
-rw-r--r--src/librustc_back/target/x86_64_rumprun_netbsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_sun_solaris.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_bitrig.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_dragonfly.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_freebsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_netbsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_openbsd.rs1
-rw-r--r--src/librustc_resolve/lib.rs36
-rw-r--r--src/librustc_resolve/resolve_imports.rs37
-rw-r--r--src/librustc_trans/abi.rs13
-rw-r--r--src/librustc_trans/base.rs7
-rw-r--r--src/librustc_trans/callee.rs8
-rw-r--r--src/librustc_trans/context.rs41
-rw-r--r--src/librustc_trans/diagnostics.rs26
-rw-r--r--src/librustc_trans/intrinsic.rs74
-rw-r--r--src/librustc_trans/type_of.rs32
-rw-r--r--src/test/auxiliary/foreign_lib.rs27
-rw-r--r--src/test/compile-fail/glob-cycles.rs26
-rw-r--r--src/test/compile-fail/issue-21174.rs2
-rw-r--r--src/test/compile-fail/issue-32377.rs27
-rw-r--r--src/test/compile-fail/issue-32797.rs21
-rw-r--r--src/test/compile-fail/transmute-from-fn-item-types-error.rs23
-rw-r--r--src/test/compile-fail/transmute-from-fn-item-types-lint.rs26
-rw-r--r--src/test/compile-fail/transmute-type-parameters.rs18
-rw-r--r--src/test/run-make/target-specs/my-awesome-platform.json1
-rw-r--r--src/test/run-pass/foreign-dupe.rs40
69 files changed, 2122 insertions, 454 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 5682960709f..b19f4b07a31 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,291 @@
+Version 1.9.0 (2016-05-26)
+==========================
+
+Language
+--------
+
+* The `#[deprecated]` attribute when applied to an API will generate
+  warnings when used. The warnings may be suppressed with
+  `#[allow(deprecated)]`. [RFC 1270].
+* [`fn` item types are zero sized, and each `fn` names a unique
+  type][1.9fn]. This will break code that transmutes `fn`s, so calling
+  `transmute` on a `fn` type will generate a warning for a few cycles,
+  then will be converted to an error.
+* [Field and method resolution understand visibility, so private
+  fields and methods cannot prevent the proper use of public fields
+  and methods][1.9fv].
+* [The parser considers unicode codepoints in the
+  `PATTERN_WHITE_SPACE` category to be whitespace][1.9ws].
+
+Stabilized APIs
+---------------
+
+* [`std::panic`]
+* [`std::panic::catch_unwind`][] (renamed from `recover`)
+* [`std::panic::resume_unwind`][] (renamed from `propagate`)
+* [`std::panic::AssertUnwindSafe`][] (renamed from `AssertRecoverSafe`)
+* [`std::panic::UnwindSafe`][] (renamed from `RecoverSafe`)
+* [`str::is_char_boundary`]
+* [`<*const T>::as_ref`]
+* [`<*mut T>::as_ref`]
+* [`<*mut T>::as_mut`]
+* [`AsciiExt::make_ascii_uppercase`]
+* [`AsciiExt::make_ascii_lowercase`]
+* [`char::decode_utf16`]
+* [`char::DecodeUtf16`]
+* [`char::DecodeUtf16Error`]
+* [`char::DecodeUtf16Error::unpaired_surrogate`]
+* [`BTreeSet::take`]
+* [`BTreeSet::replace`]
+* [`BTreeSet::get`]
+* [`HashSet::take`]
+* [`HashSet::replace`]
+* [`HashSet::get`]
+* [`OsString::with_capacity`]
+* [`OsString::clear`]
+* [`OsString::capacity`]
+* [`OsString::reserve`]
+* [`OsString::reserve_exact`]
+* [`OsStr::is_empty`]
+* [`OsStr::len`]
+* [`std::os::unix::thread`]
+* [`RawPthread`]
+* [`JoinHandleExt`]
+* [`JoinHandleExt::as_pthread_t`]
+* [`JoinHandleExt::into_pthread_t`]
+* [`HashSet::hasher`]
+* [`HashMap::hasher`]
+* [`CommandExt::exec`]
+* [`File::try_clone`]
+* [`SocketAddr::set_ip`]
+* [`SocketAddr::set_port`]
+* [`SocketAddrV4::set_ip`]
+* [`SocketAddrV4::set_port`]
+* [`SocketAddrV6::set_ip`]
+* [`SocketAddrV6::set_port`]
+* [`SocketAddrV6::set_flowinfo`]
+* [`SocketAddrV6::set_scope_id`]
+* [`slice::copy_from_slice`]
+* [`ptr::read_volatile`]
+* [`ptr::write_volatile`]
+* [`OpenOptions::create_new`]
+* [`TcpStream::set_nodelay`]
+* [`TcpStream::nodelay`]
+* [`TcpStream::set_ttl`]
+* [`TcpStream::ttl`]
+* [`TcpStream::set_only_v6`]
+* [`TcpStream::only_v6`]
+* [`TcpStream::take_error`]
+* [`TcpStream::set_nonblocking`]
+* [`TcpListener::set_ttl`]
+* [`TcpListener::ttl`]
+* [`TcpListener::set_only_v6`]
+* [`TcpListener::only_v6`]
+* [`TcpListener::take_error`]
+* [`TcpListener::set_nonblocking`]
+* [`UdpSocket::set_broadcast`]
+* [`UdpSocket::broadcast`]
+* [`UdpSocket::set_multicast_loop_v4`]
+* [`UdpSocket::multicast_loop_v4`]
+* [`UdpSocket::set_multicast_ttl_v4`]
+* [`UdpSocket::multicast_ttl_v4`]
+* [`UdpSocket::set_multicast_loop_v6`]
+* [`UdpSocket::multicast_loop_v6`]
+* [`UdpSocket::set_multicast_ttl_v6`]
+* [`UdpSocket::multicast_ttl_v6`]
+* [`UdpSocket::set_ttl`]
+* [`UdpSocket::ttl`]
+* [`UdpSocket::set_only_v6`]
+* [`UdpSocket::only_v6`]
+* [`UdpSocket::join_multicast_v4`]
+* [`UdpSocket::join_multicast_v6`]
+* [`UdpSocket::leave_multicast_v4`]
+* [`UdpSocket::leave_multicast_v6`]
+* [`UdpSocket::take_error`]
+* [`UdpSocket::connect`]
+* [`UdpSocket::send`]
+* [`UdpSocket::recv`]
+* [`UdpSocket::set_nonblocking`]
+
+Libraries
+---------
+
+* [`std::sync::Once` is poisoned if its initialization function
+  fails][1.9o].
+* [`cell::Ref` and `cell::RefMut` can contain unsized types][1.9cu].
+* [Most types implement `fmt::Debug`][1.9db].
+* [The default buffer size used by `BufReader` and `BufWriter` was
+  reduced to 8K, from 64K][1.9bf]. This is in line with the buffer size
+  used by other languages.
+* [`Instant`, `SystemTime` and `Duration` implement `+=` and `-=`.
+  `Duration` additionally implements `*=` and `/=`][1.9ta].
+* [`Skip` is a `DoubleEndedIterator`][1.9sk].
+* [`From<[u8; 4]>` is implemented for `Ipv4Addr`][1.9fi].
+* [`Chain` implements `BufRead`][1.9ch].
+* [`HashMap`, `HashSet` and iterators are covariant][1.9hc].
+
+Cargo
+-----
+
+* [Cargo can now run concurrently][1.9cc].
+* [Top-level overrides allow specific revisions of crates to be
+  overridden through the entire crate graph][1.9ct].  This is intended
+  to make upgrades easier for large projects, by allowing crates to be
+  forked temporarily until they've been upgraded and republished.
+* [Cargo exports a `CARGO_PKG_AUTHORS` environment variable][1.9cp].
+* [Cargo will pass the contents of the `RUSTFLAGS` variable to `rustc`
+  on the commandline][1.9cf]. `rustc` arguments can also be specified
+  in the `build.rustflags` configuration key.
+
+Performance
+-----------
+
+* [During type unification, the complexity of comparing variables for
+  equivalance was reduced from `O(n!)` to `O(n)`][1.9tu]. This leads
+  to major compile-time improvements in some scenarios.
+* [`ToString` is specialized for `str`, giving it the same performance
+  as `to_owned`][1.9ts].
+* [Spawning processes with `Command::output` no longer creates extra
+  threads][1.9sp].
+* [`#[derive(PartialEq)]` and `#[derive(PartialOrd)]` emit less code
+  for C-like enums][1.9cl].
+
+Misc
+----
+
+* [Passing the `--quiet` flag to a test runner will produce
+  much-abbreviated output][1.9q].
+* The Rust Project now publishes std binaries for the
+  `mips-unknown-linux-musl`, `mipsel-unknown-linux-musl`, and
+  `i586-pc-windows-msvc` targets.
+
+Compatibility Notes
+-------------------
+
+* [`std::sync::Once` is poisoned if its initialization function
+  fails][1.9o].
+* [It is illegal to define methods with the same name in overlapping
+  inherent `impl` blocks][1.9sn].
+* [`fn` item types are zero sized, and each `fn` names a unique
+  type][1.9fn]. This will break code that transmutes `fn`s, so calling
+  `transmute` on a `fn` type will generate a warning for a few cycles,
+  then will be converted to an error.
+* [Improvements to const evaluation may trigger new errors when integer
+  literals are out of range][1.9ce].
+
+
+[1.9bf]: https://github.com/rust-lang/rust/pull/32695
+[1.9cc]: https://github.com/rust-lang/cargo/pull/2486
+[1.9ce]: https://github.com/rust-lang/rust/pull/30587
+[1.9cf]: https://github.com/rust-lang/cargo/pull/2241
+[1.9ch]: https://github.com/rust-lang/rust/pull/32541
+[1.9cl]: https://github.com/rust-lang/rust/pull/31977
+[1.9cp]: https://github.com/rust-lang/cargo/pull/2465
+[1.9ct]: https://github.com/rust-lang/cargo/pull/2385
+[1.9cu]: https://github.com/rust-lang/rust/pull/32652
+[1.9db]: https://github.com/rust-lang/rust/pull/32054
+[1.9fi]: https://github.com/rust-lang/rust/pull/32050
+[1.9fn]: https://github.com/rust-lang/rust/pull/31710
+[1.9fv]: https://github.com/rust-lang/rust/pull/31938
+[1.9hc]: https://github.com/rust-lang/rust/pull/32635
+[1.9o]: https://github.com/rust-lang/rust/pull/32325
+[1.9q]: https://github.com/rust-lang/rust/pull/31887
+[1.9sk]: https://github.com/rust-lang/rust/pull/31700
+[1.9sn]: https://github.com/rust-lang/rust/pull/31925
+[1.9sp]: https://github.com/rust-lang/rust/pull/31618
+[1.9ta]: https://github.com/rust-lang/rust/pull/32448
+[1.9ts]: https://github.com/rust-lang/rust/pull/32586
+[1.9tu]: https://github.com/rust-lang/rust/pull/32062
+[1.9ws]: https://github.com/rust-lang/rust/pull/29734
+[RFC 1270]: https://github.com/rust-lang/rfcs/blob/master/text/1270-deprecation.md
+[`<*const T>::as_ref`]: http://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.as_ref
+[`<*mut T>::as_mut`]: http://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.as_mut
+[`<*mut T>::as_ref`]: http://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.as_ref
+[`slice::copy_from_slice`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.copy_from_slice
+[`AsciiExt::make_ascii_lowercase`]: http://doc.rust-lang.org/nightly/std/ascii/trait.AsciiExt.html#tymethod.make_ascii_lowercase
+[`AsciiExt::make_ascii_uppercase`]: http://doc.rust-lang.org/nightly/std/ascii/trait.AsciiExt.html#tymethod.make_ascii_uppercase
+[`BTreeSet::get`]: http://doc.rust-lang.org/nightly/collections/btree/set/struct.BTreeSet.html#method.get
+[`BTreeSet::replace`]: http://doc.rust-lang.org/nightly/collections/btree/set/struct.BTreeSet.html#method.replace
+[`BTreeSet::take`]: http://doc.rust-lang.org/nightly/collections/btree/set/struct.BTreeSet.html#method.take
+[`CommandExt::exec`]: http://doc.rust-lang.org/nightly/std/os/unix/process/trait.CommandExt.html#tymethod.exec
+[`File::try_clone`]: http://doc.rust-lang.org/nightly/std/fs/struct.File.html#method.try_clone
+[`HashMap::hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashMap.html#method.hasher
+[`HashSet::get`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.get
+[`HashSet::hasher`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.hasher
+[`HashSet::replace`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.replace
+[`HashSet::take`]: http://doc.rust-lang.org/nightly/std/collections/struct.HashSet.html#method.take
+[`JoinHandleExt::as_pthread_t`]: http://doc.rust-lang.org/nightly/std/os/unix/thread/trait.JoinHandleExt.html#tymethod.as_pthread_t
+[`JoinHandleExt::into_pthread_t`]: http://doc.rust-lang.org/nightly/std/os/unix/thread/trait.JoinHandleExt.html#tymethod.into_pthread_t
+[`JoinHandleExt`]: http://doc.rust-lang.org/nightly/std/os/unix/thread/trait.JoinHandleExt.html
+[`OpenOptions::create_new`]: http://doc.rust-lang.org/nightly/std/fs/struct.OpenOptions.html#method.create_new
+[`OsStr::is_empty`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsStr.html#method.is_empty
+[`OsStr::len`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsStr.html#method.len
+[`OsString::capacity`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.capacity
+[`OsString::clear`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.clear
+[`OsString::reserve_exact`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.reserve_exact
+[`OsString::reserve`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.reserve
+[`OsString::with_capacity`]: http://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.with_capacity
+[`RawPthread`]: http://doc.rust-lang.org/nightly/std/os/unix/thread/type.RawPthread.html
+[`SocketAddr::set_ip`]: http://doc.rust-lang.org/nightly/std/net/enum.SocketAddr.html#method.set_ip
+[`SocketAddr::set_port`]: http://doc.rust-lang.org/nightly/std/net/enum.SocketAddr.html#method.set_port
+[`SocketAddrV4::set_ip`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV4.html#method.set_ip
+[`SocketAddrV4::set_port`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV4.html#method.set_port
+[`SocketAddrV6::set_flowinfo`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_flowinfo
+[`SocketAddrV6::set_ip`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_ip
+[`SocketAddrV6::set_port`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_port
+[`SocketAddrV6::set_scope_id`]: http://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_scope_id
+[`TcpListener::only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.only_v6
+[`TcpListener::set_nonblocking`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_nonblocking
+[`TcpListener::set_only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_only_v6
+[`TcpListener::set_ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_ttl
+[`TcpListener::take_error`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.take_error
+[`TcpListener::ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.ttl
+[`TcpStream::nodelay`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.nodelay
+[`TcpStream::only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.only_v6
+[`TcpStream::set_nodelay`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_nodelay
+[`TcpStream::set_nonblocking`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_nonblocking
+[`TcpStream::set_only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_only_v6
+[`TcpStream::set_ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_ttl
+[`TcpStream::take_error`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.take_error
+[`TcpStream::ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.ttl
+[`UdpSocket::broadcast`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.broadcast
+[`UdpSocket::connect`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.connect
+[`UdpSocket::join_multicast_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.join_multicast_v4
+[`UdpSocket::join_multicast_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.join_multicast_v6
+[`UdpSocket::leave_multicast_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.leave_multicast_v4
+[`UdpSocket::leave_multicast_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.leave_multicast_v6
+[`UdpSocket::multicast_loop_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.multicast_loop_v4
+[`UdpSocket::multicast_loop_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.multicast_loop_v6
+[`UdpSocket::multicast_ttl_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.multicast_ttl_v4
+[`UdpSocket::multicast_ttl_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.multicast_ttl_v6
+[`UdpSocket::only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.only_v6
+[`UdpSocket::recv`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.recv
+[`UdpSocket::send`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.send
+[`UdpSocket::set_broadcast`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_broadcast
+[`UdpSocket::set_multicast_loop_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_multicast_loop_v4
+[`UdpSocket::set_multicast_loop_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_multicast_loop_v6
+[`UdpSocket::set_multicast_ttl_v4`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_multicast_ttl_v4
+[`UdpSocket::set_multicast_ttl_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_multicast_ttl_v6
+[`UdpSocket::set_nonblocking`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_nonblocking
+[`UdpSocket::set_only_v6`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_only_v6
+[`UdpSocket::set_ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_ttl
+[`UdpSocket::take_error`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.take_error
+[`UdpSocket::ttl`]: http://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.ttl
+[`char::DecodeUtf16Error::unpaired_surrogate`]: http://doc.rust-lang.org/nightly/std/char/struct.DecodeUtf16Error.html#method.unpaired_surrogate
+[`char::DecodeUtf16Error`]: http://doc.rust-lang.org/nightly/std/char/struct.DecodeUtf16Error.html
+[`char::DecodeUtf16`]: http://doc.rust-lang.org/nightly/std/char/struct.DecodeUtf16.html
+[`char::decode_utf16`]: http://doc.rust-lang.org/nightly/std/char/fn.decode_utf16.html
+[`ptr::read_volatile`]: http://doc.rust-lang.org/nightly/std/ptr/fn.read_volatile.html
+[`ptr::write_volatile`]: http://doc.rust-lang.org/nightly/std/ptr/fn.write_volatile.html
+[`std::os::unix::thread`]: http://doc.rust-lang.org/nightly/std/os/unix/thread/index.html
+[`std::panic::AssertUnwindSafe`]: http://doc.rust-lang.org/nightly/std/panic/struct.AssertUnwindSafe.html
+[`std::panic::UnwindSafe`]: http://doc.rust-lang.org/nightly/std/panic/trait.UnwindSafe.html
+[`std::panic::catch_unwind`]: http://doc.rust-lang.org/nightly/std/panic/fn.catch_unwind.html
+[`std::panic::resume_unwind`]: http://doc.rust-lang.org/nightly/std/panic/fn.resume_unwind.html
+[`std::panic`]: http://doc.rust-lang.org/nightly/std/panic/index.html
+[`str::is_char_boundary`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_char_boundary
+
+
 Version 1.8.0 (2016-04-14)
 ==========================
 
diff --git a/mk/main.mk b/mk/main.mk
index 9b8080f9661..204de6067c4 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.9.0
 # An optional number to put after the label, e.g. '.2' -> '-beta.2'
 # NB Make sure it starts with a dot to conform to semver pre-release
 # versions (section 9)
-CFG_PRERELEASE_VERSION=.1
+CFG_PRERELEASE_VERSION=.2
 
 # Append a version-dependent hash to each library, so we can install different
 # versions in the same place
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 446313f7037..536c739bf16 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -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),
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 4abb1c8b98a..0ef130127a4 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -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.
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 767c5adc81e..e84be7e4560 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -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>,
+struct ItemVisitor<'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>>,
+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);
+    }
+}
 
-    // 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 ExprVisitor<'a, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx> IntrinsicCheckingVisitor<'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;
             }
-        };
-
-        // 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;
+            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;
+                }
+                _ => {}
+            }
         }
 
-        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);
+        // 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()
             }
+        };
 
-            Some((space, index, &param_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");
+        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));
+    }
+}
 
-                    substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
-                    self.with_each_combination(span, param_env, types_in_scope.clone(),
-                                               substs, callback);
-                }
+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);
+    }
 
-                substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
-                self.with_each_combination(span, param_env, types_in_scope,
-                                           substs, callback);
-            }
+    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 push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
-        debug!("Pushing transmute restriction: {:?}", restriction);
-        self.tcx.transmute_restrictions.borrow_mut().push(restriction);
+    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);
+        }
     }
-}
 
-impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
     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)
-    }
-}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index bdba700f49a..8b07a97b1a1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -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());
     }
 }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
new file mode 100644
index 00000000000..3ea691b4dc7
--- /dev/null
+++ b/src/librustc/ty/layout.rs
@@ -0,0 +1,1336 @@
+// 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.
+
+pub use self::Integer::*;
+pub use self::Layout::*;
+pub use self::Primitive::*;
+
+use infer::{InferCtxt, drain_fulfillment_cx_or_panic};
+use session::Session;
+use traits;
+use ty::{self, Ty, TyCtxt, TypeFoldable};
+
+use syntax::ast::{FloatTy, IntTy, UintTy};
+use syntax::attr;
+use syntax::codemap::DUMMY_SP;
+
+use std::cmp;
+use std::fmt;
+use std::i64;
+
+/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
+/// for a target, which contains everything needed to compute layouts.
+pub struct TargetDataLayout {
+    pub endian: Endian,
+    pub i1_align: Align,
+    pub i8_align: Align,
+    pub i16_align: Align,
+    pub i32_align: Align,
+    pub i64_align: Align,
+    pub f32_align: Align,
+    pub f64_align: Align,
+    pub pointer_size: Size,
+    pub pointer_align: Align,
+    pub aggregate_align: Align,
+
+    /// Alignments for vector types.
+    pub vector_align: Vec<(Size, Align)>
+}
+
+impl Default for TargetDataLayout {
+    fn default() -> TargetDataLayout {
+        TargetDataLayout {
+            endian: Endian::Big,
+            i1_align: Align::from_bits(8, 8).unwrap(),
+            i8_align: Align::from_bits(8, 8).unwrap(),
+            i16_align: Align::from_bits(16, 16).unwrap(),
+            i32_align: Align::from_bits(32, 32).unwrap(),
+            i64_align: Align::from_bits(32, 64).unwrap(),
+            f32_align: Align::from_bits(32, 32).unwrap(),
+            f64_align: Align::from_bits(64, 64).unwrap(),
+            pointer_size: Size::from_bits(64),
+            pointer_align: Align::from_bits(64, 64).unwrap(),
+            aggregate_align: Align::from_bits(0, 64).unwrap(),
+            vector_align: vec![
+                (Size::from_bits(64), Align::from_bits(64, 64).unwrap()),
+                (Size::from_bits(128), Align::from_bits(128, 128).unwrap())
+            ]
+        }
+    }
+}
+
+impl TargetDataLayout {
+    pub fn parse(sess: &Session) -> TargetDataLayout {
+        // Parse a bit count from a string.
+        let parse_bits = |s: &str, kind: &str, cause: &str| {
+            s.parse::<u64>().unwrap_or_else(|err| {
+                sess.err(&format!("invalid {} `{}` for `{}` in \"data-layout\": {}",
+                                  kind, s, cause, err));
+                0
+            })
+        };
+
+        // Parse a size string.
+        let size = |s: &str, cause: &str| {
+            Size::from_bits(parse_bits(s, "size", cause))
+        };
+
+        // Parse an alignment string.
+        let align = |s: &[&str], cause: &str| {
+            if s.is_empty() {
+                sess.err(&format!("missing alignment for `{}` in \"data-layout\"", cause));
+            }
+            let abi = parse_bits(s[0], "alignment", cause);
+            let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, "alignment", cause));
+            Align::from_bits(abi, pref).unwrap_or_else(|err| {
+                sess.err(&format!("invalid alignment for `{}` in \"data-layout\": {}",
+                                  cause, err));
+                Align::from_bits(8, 8).unwrap()
+            })
+        };
+
+        let mut dl = TargetDataLayout::default();
+        for spec in sess.target.target.data_layout.split("-") {
+            match &spec.split(":").collect::<Vec<_>>()[..] {
+                ["e"] => dl.endian = Endian::Little,
+                ["E"] => dl.endian = Endian::Big,
+                ["a", a..] => dl.aggregate_align = align(a, "a"),
+                ["f32", a..] => dl.f32_align = align(a, "f32"),
+                ["f64", a..] => dl.f64_align = align(a, "f64"),
+                [p @ "p", s, a..] | [p @ "p0", s, a..] => {
+                    dl.pointer_size = size(s, p);
+                    dl.pointer_align = align(a, p);
+                }
+                [s, a..] if s.starts_with("i") => {
+                    let ty_align = match s[1..].parse::<u64>() {
+                        Ok(1) => &mut dl.i8_align,
+                        Ok(8) => &mut dl.i8_align,
+                        Ok(16) => &mut dl.i16_align,
+                        Ok(32) => &mut dl.i32_align,
+                        Ok(64) => &mut dl.i64_align,
+                        Ok(_) => continue,
+                        Err(_) => {
+                            size(&s[1..], "i"); // For the user error.
+                            continue;
+                        }
+                    };
+                    *ty_align = align(a, s);
+                }
+                [s, a..] if s.starts_with("v") => {
+                    let v_size = size(&s[1..], "v");
+                    let a = align(a, s);
+                    if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
+                        v.1 = a;
+                        continue;
+                    }
+                    // No existing entry, add a new one.
+                    dl.vector_align.push((v_size, a));
+                }
+                _ => {} // Ignore everything else.
+            }
+        }
+
+        // Perform consistency checks against the Target information.
+        let endian_str = match dl.endian {
+            Endian::Little => "little",
+            Endian::Big => "big"
+        };
+        if endian_str != sess.target.target.target_endian {
+            sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
+                               architecture is {}-endian, while \"target-endian\" is `{}`",
+                              endian_str, sess.target.target.target_endian));
+        }
+
+        if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width {
+            sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
+                               pointers are {}-bit, while \"target-pointer-width\" is `{}`",
+                              dl.pointer_size.bits(), sess.target.target.target_pointer_width));
+        }
+
+        dl
+    }
+
+    /// Return exclusive upper bound on object size.
+    ///
+    /// The theoretical maximum object size is defined as the maximum positive `isize` 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
+    /// `isize` 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.pointer_size.bits() {
+            32 => 1 << 31,
+            64 => 1 << 47,
+            bits => bug!("obj_size_bound: unknown pointer bit size {}", bits)
+        }
+    }
+
+    pub fn ptr_sized_integer(&self) -> Integer {
+        match self.pointer_size.bits() {
+            32 => I32,
+            64 => I64,
+            bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits)
+        }
+    }
+}
+
+/// Endianness of the target, which must match cfg(target-endian).
+#[derive(Copy, Clone)]
+pub enum Endian {
+    Little,
+    Big
+}
+
+/// Size of a type in bytes.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct Size {
+    raw: u64
+}
+
+impl Size {
+    pub fn from_bits(bits: u64) -> Size {
+        Size::from_bytes((bits + 7) / 8)
+    }
+
+    pub fn from_bytes(bytes: u64) -> Size {
+        if bytes >= (1 << 61) {
+            bug!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes)
+        }
+        Size {
+            raw: bytes
+        }
+    }
+
+    pub fn bytes(self) -> u64 {
+        self.raw
+    }
+
+    pub fn bits(self) -> u64 {
+        self.bytes() * 8
+    }
+
+    pub fn abi_align(self, align: Align) -> Size {
+        let mask = align.abi() - 1;
+        Size::from_bytes((self.bytes() + mask) & !mask)
+    }
+
+    pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
+        // Each Size is less than dl.obj_size_bound(), so the sum is
+        // also less than 1 << 62 (and therefore can't overflow).
+        let bytes = self.bytes() + offset.bytes();
+
+        if bytes < dl.obj_size_bound() {
+            Some(Size::from_bytes(bytes))
+        } else {
+            None
+        }
+    }
+
+    pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {
+        // Each Size is less than dl.obj_size_bound(), so the sum is
+        // also less than 1 << 62 (and therefore can't overflow).
+        match self.bytes().checked_mul(count) {
+            Some(bytes) if bytes < dl.obj_size_bound() => {
+                Some(Size::from_bytes(bytes))
+            }
+            _ => None
+        }
+    }
+}
+
+/// Alignment of a type in bytes, both ABI-mandated and preferred.
+/// Since alignments are always powers of 2, we can pack both in one byte,
+/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Align {
+    raw: u8
+}
+
+impl Align {
+    pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {
+        Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)
+    }
+
+    pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
+        let pack = |align: u64| {
+            // Treat an alignment of 0 bytes like 1-byte alignment.
+            if align == 0 {
+                return Ok(0);
+            }
+
+            let mut bytes = align;
+            let mut pow: u8 = 0;
+            while (bytes & 1) == 0 {
+                pow += 1;
+                bytes >>= 1;
+            }
+            if bytes != 1 {
+                Err(format!("`{}` is not a power of 2", align))
+            } else if pow > 0x0f {
+                Err(format!("`{}` is too large", align))
+            } else {
+                Ok(pow)
+            }
+        };
+
+        Ok(Align {
+            raw: pack(abi)? | (pack(pref)? << 4)
+        })
+    }
+
+    pub fn abi(self) -> u64 {
+        1 << (self.raw & 0xf)
+    }
+
+    pub fn pref(self) -> u64 {
+        1 << (self.raw >> 4)
+    }
+
+    pub fn min(self, other: Align) -> Align {
+        let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);
+        let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);
+        Align {
+            raw: abi | pref
+        }
+    }
+
+    pub fn max(self, other: Align) -> Align {
+        let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);
+        let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);
+        Align {
+            raw: abi | pref
+        }
+    }
+}
+
+/// Integers, also used for enum discriminants.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Integer {
+    I1,
+    I8,
+    I16,
+    I32,
+    I64
+}
+
+impl Integer {
+    /// Find the smallest Integer type which can represent the signed value.
+    pub fn fit_signed(x: i64) -> Integer {
+        match x {
+            -0x0000_0001...0x0000_0000 => I1,
+            -0x0000_0080...0x0000_007f => I8,
+            -0x0000_8000...0x0000_7fff => I16,
+            -0x8000_0000...0x7fff_ffff => I32,
+            _ => I64
+        }
+    }
+
+    /// Find the smallest Integer type which can represent the unsigned value.
+    pub fn fit_unsigned(x: u64) -> Integer {
+        match x {
+            0...0x0000_0001 => I1,
+            0...0x0000_00ff => I8,
+            0...0x0000_ffff => I16,
+            0...0xffff_ffff => I32,
+            _ => I64
+        }
+    }
+
+    /// Get the Integer type from an attr::IntType.
+    pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {
+        match ity {
+            attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
+            attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
+            attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32,
+            attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64,
+            attr::SignedInt(IntTy::Is) | attr::UnsignedInt(UintTy::Us) => {
+                dl.ptr_sized_integer()
+            }
+        }
+    }
+
+    /// Find the appropriate Integer type and signedness for the given
+    /// signed discriminant range and #[repr] attribute.
+    /// N.B.: u64 values above i64::MAX will be treated as signed, but
+    /// that shouldn't affect anything, other than maybe debuginfo.
+    pub fn repr_discr(tcx: &TyCtxt, hint: attr::ReprAttr, min: i64, max: i64)
+                      -> (Integer, bool) {
+        // Theoretically, negative values could be larger in unsigned representation
+        // than the unsigned representation of the signed minimum. However, if there
+        // are any negative values, the only valid unsigned representation is u64
+        // which can fit all i64 values, so the result remains unaffected.
+        let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
+        let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
+
+        let at_least = match hint {
+            attr::ReprInt(span, ity) => {
+                let discr = Integer::from_attr(&tcx.data_layout, ity);
+                let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
+                if discr < fit {
+                    span_bug!(span, "representation hint insufficient for discriminant range")
+                }
+                return (discr, ity.is_signed());
+            }
+            attr::ReprExtern => {
+                match &tcx.sess.target.target.arch[..] {
+                    // WARNING: the ARM EABI has two variants; the one corresponding
+                    // to `at_least == I32` appears to be used on Linux and NetBSD,
+                    // but some systems may use the variant corresponding to no
+                    // lower bound.  However, we don't run on those yet...?
+                    "arm" => I32,
+                    _ => I32,
+                }
+            }
+            attr::ReprAny => I8,
+            attr::ReprPacked => {
+                bug!("Integer::repr_discr: found #[repr(packed)] on an enum");
+            }
+            attr::ReprSimd => {
+                bug!("Integer::repr_discr: found #[repr(simd)] on an enum");
+            }
+        };
+
+        // If there are no negative values, we can use the unsigned fit.
+        if min >= 0 {
+            (cmp::max(unsigned_fit, at_least), false)
+        } else {
+            (cmp::max(signed_fit, at_least), true)
+        }
+    }
+}
+
+/// Fundamental unit of memory access and layout.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum Primitive {
+    Int(Integer),
+    F32,
+    F64,
+    Pointer
+}
+
+impl Primitive {
+    pub fn size(self, dl: &TargetDataLayout) -> Size {
+        match self {
+            Int(I1) | Int(I8) => Size::from_bits(8),
+            Int(I16) => Size::from_bits(16),
+            Int(I32) | F32 => Size::from_bits(32),
+            Int(I64) | F64 => Size::from_bits(64),
+            Pointer => dl.pointer_size
+        }
+    }
+
+    pub fn align(self, dl: &TargetDataLayout) -> Align {
+        match self {
+            Int(I1) => dl.i1_align,
+            Int(I8) => dl.i8_align,
+            Int(I16) => dl.i16_align,
+            Int(I32) => dl.i32_align,
+            Int(I64) => dl.i64_align,
+            F32 => dl.f32_align,
+            F64 => dl.f64_align,
+            Pointer => dl.pointer_align
+        }
+    }
+}
+
+/// Path through fields of nested structures.
+// FIXME(eddyb) use small vector optimization for the common case.
+pub type FieldPath = Vec<u32>;
+
+/// A structure, a product type in ADT terms.
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub struct Struct {
+    pub align: Align,
+
+    /// If true, no alignment padding is used.
+    pub packed: bool,
+
+    /// If true, the size is exact, otherwise it's only a lower bound.
+    pub sized: bool,
+
+    /// Offsets for the first byte after each field.
+    /// That is, field_offset(i) = offset_after_field[i - 1] and the
+    /// whole structure's size is the last offset, excluding padding.
+    // FIXME(eddyb) use small vector optimization for the common case.
+    pub offset_after_field: Vec<Size>
+}
+
+impl Struct {
+    pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
+        Struct {
+            align: if packed { dl.i8_align } else { dl.aggregate_align },
+            packed: packed,
+            sized: true,
+            offset_after_field: vec![]
+        }
+    }
+
+    /// Extend the Struct with more fields.
+    pub fn extend<'a, 'tcx, I>(&mut self, dl: &TargetDataLayout,
+                               fields: I,
+                               scapegoat: Ty<'tcx>)
+                               -> Result<(), LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
+        self.offset_after_field.reserve(fields.size_hint().0);
+
+        for field in fields {
+            if !self.sized {
+                bug!("Struct::compute: field #{} of `{}` comes after unsized field",
+                     self.offset_after_field.len(), scapegoat);
+            }
+
+            let field = field?;
+            if field.is_unsized() {
+                self.sized = false;
+            }
+
+            // Invariant: offset < dl.obj_size_bound() <= 1<<61
+            let mut offset = if !self.packed {
+                let align = field.align(dl);
+                self.align = self.align.max(align);
+                self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {
+                    *last = last.abi_align(align);
+                    *last
+                })
+            } else {
+                self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
+            };
+
+            offset = offset.checked_add(field.size(dl), dl)
+                           .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
+
+            self.offset_after_field.push(offset);
+        }
+
+        Ok(())
+    }
+
+    /// Get the size without trailing alignment padding.
+    pub fn min_size(&self) -> Size {
+        self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
+    }
+
+    /// Get the size with trailing aligment padding.
+    pub fn stride(&self) -> Size {
+        self.min_size().abi_align(self.align)
+    }
+
+    /// Determine whether a structure would be zero-sized, given its fields.
+    pub fn would_be_zero_sized<'a, 'tcx, I>(dl: &TargetDataLayout, fields: I)
+                                            -> Result<bool, LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
+        for field in fields {
+            let field = field?;
+            if field.is_unsized() || field.size(dl).bytes() > 0 {
+                return Ok(false);
+            }
+        }
+        Ok(true)
+    }
+
+    /// Find the path leading to a non-zero leaf field, starting from
+    /// the given type and recursing through aggregates.
+    // FIXME(eddyb) track value ranges and traverse already optimized enums.
+    pub fn non_zero_field_in_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                            ty: Ty<'tcx>)
+                                            -> Result<Option<FieldPath>, LayoutError<'tcx>> {
+        let tcx = infcx.tcx;
+        match (ty.layout(infcx)?, &ty.sty) {
+            (&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])),
+            (&FatPointer { non_zero: true, .. }, _) => {
+                Ok(Some(vec![FAT_PTR_ADDR as u32]))
+            }
+
+            // Is this the NonZero lang item wrapping a pointer or integer type?
+            (&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => {
+                let fields = &def.struct_variant().fields;
+                assert_eq!(fields.len(), 1);
+                let ty = normalize_associated_type(infcx, fields[0].ty(tcx, substs));
+                match *ty.layout(infcx)? {
+                    // FIXME(eddyb) also allow floating-point types here.
+                    Scalar { value: Int(_), non_zero: false } |
+                    Scalar { value: Pointer, non_zero: false } => {
+                        Ok(Some(vec![0]))
+                    }
+                    FatPointer { non_zero: false, .. } => {
+                        Ok(Some(vec![FAT_PTR_ADDR as u32, 0]))
+                    }
+                    _ => Ok(None)
+                }
+            }
+
+            // Perhaps one of the fields of this struct is non-zero
+            // let's recurse and find out
+            (_, &ty::TyStruct(def, substs)) => {
+                Struct::non_zero_field_path(infcx, def.struct_variant().fields
+                                                      .iter().map(|field| {
+                    normalize_associated_type(infcx, field.ty(tcx, substs))
+                }))
+            }
+
+            // Perhaps one of the upvars of this closure is non-zero
+            // Let's recurse and find out!
+            (_, &ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. })) |
+            // Can we use one of the fields in this tuple?
+            (_, &ty::TyTuple(ref tys)) => {
+                Struct::non_zero_field_path(infcx, tys.iter().cloned())
+            }
+
+            // Is this a fixed-size array of something non-zero
+            // with at least one element?
+            (_, &ty::TyArray(ety, d)) if d > 0 => {
+                Struct::non_zero_field_path(infcx, Some(ety).into_iter())
+            }
+
+            // Anything else is not a non-zero type.
+            _ => Ok(None)
+        }
+    }
+
+    /// Find the path leading to a non-zero leaf field, starting from
+    /// the given set of fields and recursing through aggregates.
+    pub fn non_zero_field_path<'a, 'tcx, I>(infcx: &InferCtxt<'a, 'tcx>,
+                                            fields: I)
+                                            -> Result<Option<FieldPath>, LayoutError<'tcx>>
+    where I: Iterator<Item=Ty<'tcx>> {
+        for (i, ty) in fields.enumerate() {
+            if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
+                path.push(i as u32);
+                return Ok(Some(path));
+            }
+        }
+        Ok(None)
+    }
+}
+
+/// The first half of a fat pointer.
+/// - For a trait object, 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 trait object, this is the address of the vtable.
+/// - For a slice, this is the length.
+pub const FAT_PTR_EXTRA: usize = 1;
+
+/// Type layout, from which size and alignment can be cheaply computed.
+/// For ADTs, it also includes field placement and enum optimizations.
+/// NOTE: Because Layout is interned, redundant information should be
+/// kept to a minimum, e.g. it includes no sub-component Ty or Layout.
+#[derive(Debug, PartialEq, Eq, Hash)]
+pub enum Layout {
+    /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
+    Scalar {
+        value: Primitive,
+        // If true, the value cannot represent a bit pattern of all zeroes.
+        non_zero: bool
+    },
+
+    /// SIMD vectors, from TyStruct marked with #[repr(simd)].
+    Vector {
+        element: Primitive,
+        count: u64
+    },
+
+    /// TyArray, TySlice or TyStr.
+    Array {
+        /// If true, the size is exact, otherwise it's only a lower bound.
+        sized: bool,
+        align: Align,
+        size: Size
+    },
+
+    /// TyRawPtr or TyRef with a !Sized pointee.
+    FatPointer {
+        metadata: Primitive,
+        // If true, the pointer cannot be null.
+        non_zero: bool
+    },
+
+    // Remaining variants are all ADTs such as TyStruct, TyEnum or TyTuple.
+
+    /// C-like enums; basically an integer.
+    CEnum {
+        discr: Integer,
+        signed: bool,
+        // Inclusive discriminant range.
+        // If min > max, it represents min...u64::MAX followed by 0...max.
+        // FIXME(eddyb) always use the shortest range, e.g. by finding
+        // the largest space between two consecutive discriminants and
+        // taking everything else as the (shortest) discriminant range.
+        min: u64,
+        max: u64
+    },
+
+    /// Single-case enums, and structs/tuples.
+    Univariant {
+        variant: Struct,
+        // If true, the structure is NonZero.
+        // FIXME(eddyb) use a newtype Layout kind for this.
+        non_zero: bool
+    },
+
+    /// General-case enums: for each case there is a struct, and they
+    /// all start with a field for the discriminant.
+    General {
+        discr: Integer,
+        variants: Vec<Struct>,
+        size: Size,
+        align: Align
+    },
+
+    /// Two cases distinguished by a nullable pointer: the case with discriminant
+    /// `nndiscr` must have single field which is known to be nonnull due to its type.
+    /// The other case is known to be zero sized. Hence we represent the enum
+    /// as simply a nullable pointer: if not null it indicates the `nndiscr` variant,
+    /// otherwise it indicates the other case.
+    ///
+    /// For example, `std::option::Option` instantiated at a safe pointer type
+    /// is represented such that `None` is a null pointer and `Some` is the
+    /// identity function.
+    RawNullablePointer {
+        nndiscr: u64,
+        value: Primitive
+    },
+
+    /// Two cases distinguished by a nullable pointer: the case with discriminant
+    /// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
+    /// field is known to be nonnull due to its type; if that field is null, then
+    /// it represents the other case, which is known to be zero sized.
+    StructWrappedNullablePointer {
+        nndiscr: u64,
+        nonnull: Struct,
+        // N.B. There is a 0 at the start, for LLVM GEP through a pointer.
+        discrfield: FieldPath
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum LayoutError<'tcx> {
+    Unknown(Ty<'tcx>),
+    SizeOverflow(Ty<'tcx>)
+}
+
+impl<'tcx> fmt::Display for LayoutError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LayoutError::Unknown(ty) => {
+                write!(f, "the type `{:?}` has an unknown layout", ty)
+            }
+            LayoutError::SizeOverflow(ty) => {
+                write!(f, "the type `{:?}` is too big for the current architecture", ty)
+            }
+        }
+    }
+}
+
+/// Helper function for normalizing associated types in an inference context.
+fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                       ty: Ty<'tcx>)
+                                       -> Ty<'tcx> {
+    if !ty.has_projection_types() {
+        return ty;
+    }
+
+    let mut selcx = traits::SelectionContext::new(infcx);
+    let cause = traits::ObligationCause::dummy();
+    let traits::Normalized { value: result, obligations } =
+        traits::normalize(&mut selcx, cause, &ty);
+
+    let mut fulfill_cx = traits::FulfillmentContext::new();
+
+    for obligation in obligations {
+        fulfill_cx.register_predicate_obligation(infcx, obligation);
+    }
+
+    drain_fulfillment_cx_or_panic(DUMMY_SP, infcx, &mut fulfill_cx, &result)
+}
+
+impl Layout {
+    pub fn compute_uncached<'a, 'tcx>(ty: Ty<'tcx>,
+                                      infcx: &InferCtxt<'a, 'tcx>)
+                                      -> Result<Layout, LayoutError<'tcx>> {
+        let tcx = infcx.tcx;
+        let dl = &tcx.data_layout;
+        assert!(!ty.has_infer_types());
+
+        let layout = match ty.sty {
+            // Basic scalars.
+            ty::TyBool => Scalar { value: Int(I1), non_zero: false },
+            ty::TyChar => Scalar { value: Int(I32), non_zero: false },
+            ty::TyInt(ity) => {
+                Scalar {
+                    value: Int(Integer::from_attr(dl, attr::SignedInt(ity))),
+                    non_zero: false
+                }
+            }
+            ty::TyUint(ity) => {
+                Scalar {
+                    value: Int(Integer::from_attr(dl, attr::UnsignedInt(ity))),
+                    non_zero: false
+                }
+            }
+            ty::TyFloat(FloatTy::F32) => Scalar { value: F32, non_zero: false },
+            ty::TyFloat(FloatTy::F64) => Scalar { value: F64, non_zero: false },
+            ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
+
+            // Potentially-fat pointers.
+            ty::TyBox(pointee) |
+            ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
+            ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                let non_zero = !ty.is_unsafe_ptr();
+                if pointee.is_sized(&infcx.parameter_environment, DUMMY_SP) {
+                    Scalar { value: Pointer, non_zero: non_zero }
+                } else {
+                    let unsized_part = tcx.struct_tail(pointee);
+                    let meta = match unsized_part.sty {
+                        ty::TySlice(_) | ty::TyStr => {
+                            Int(dl.ptr_sized_integer())
+                        }
+                        ty::TyTrait(_) => Pointer,
+                        _ => return Err(LayoutError::Unknown(unsized_part))
+                    };
+                    FatPointer { metadata: meta, non_zero: non_zero }
+                }
+            }
+
+            // Arrays and slices.
+            ty::TyArray(element, count) => {
+                let element = element.layout(infcx)?;
+                Array {
+                    sized: true,
+                    align: element.align(dl),
+                    size: element.size(dl).checked_mul(count as u64, dl)
+                                 .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
+                }
+            }
+            ty::TySlice(element) => {
+                Array {
+                    sized: false,
+                    align: element.layout(infcx)?.align(dl),
+                    size: Size::from_bytes(0)
+                }
+            }
+            ty::TyStr => {
+                Array {
+                    sized: false,
+                    align: dl.i8_align,
+                    size: Size::from_bytes(0)
+                }
+            }
+
+            // Odd unit types.
+            ty::TyFnDef(..) => {
+                Univariant {
+                    variant: Struct::new(dl, false),
+                    non_zero: false
+                }
+            }
+            ty::TyTrait(_) => {
+                let mut unit = Struct::new(dl, false);
+                unit.sized = false;
+                Univariant { variant: unit, non_zero: false }
+            }
+
+            // Tuples.
+            ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. }) |
+            ty::TyTuple(ref tys) => {
+                let mut st = Struct::new(dl, false);
+                st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
+                Univariant { variant: st, non_zero: false }
+            }
+
+            // ADTs.
+            ty::TyStruct(def, substs) => {
+                if ty.is_simd() {
+                    // SIMD vector types.
+                    let element = ty.simd_type(tcx);
+                    match *element.layout(infcx)? {
+                        Scalar { value, .. } => {
+                            return Ok(Vector {
+                                element: value,
+                                count: ty.simd_size(tcx) as u64
+                            });
+                        }
+                        _ => {
+                            tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
+                                                     a non-machine element type `{}`",
+                                                    ty, element));
+                        }
+                    }
+                }
+                let fields = def.struct_variant().fields.iter().map(|field| {
+                    normalize_associated_type(infcx, field.ty(tcx, substs))
+                        .layout(infcx)
+                });
+                let packed = tcx.lookup_packed(def.did);
+                let mut st = Struct::new(dl, packed);
+                st.extend(dl, fields, ty)?;
+
+                // FIXME(16758) don't add a drop flag to unsized structs, as it
+                // won't actually be in the location we say it is because it'll be after
+                // the unsized field. Several other pieces of code assume that the unsized
+                // field is definitely the last one.
+                if def.dtor_kind().has_drop_flag() &&
+                   ty.is_sized(&infcx.parameter_environment, DUMMY_SP) {
+                    st.extend(dl, Some(Ok(&Scalar {
+                        value: Int(I8),
+                        non_zero: false
+                    })).into_iter(), ty)?;
+                }
+                Univariant {
+                    variant: st,
+                    non_zero: Some(def.did) == tcx.lang_items.non_zero()
+                }
+            }
+            ty::TyEnum(def, substs) => {
+                let hint = *tcx.lookup_repr_hints(def.did).get(0)
+                    .unwrap_or(&attr::ReprAny);
+
+                let dtor = def.dtor_kind().has_drop_flag();
+                let drop_flag = if dtor {
+                    Some(Scalar { value: Int(I8), non_zero: false })
+                } else {
+                    None
+                };
+
+                if def.variants.is_empty() {
+                    // Uninhabitable; represent as unit
+                    // (Typechecking will reject discriminant-sizing attrs.)
+                    assert_eq!(hint, attr::ReprAny);
+
+                    let mut st = Struct::new(dl, false);
+                    st.extend(dl, drop_flag.iter().map(Ok), ty)?;
+                    return Ok(Univariant { variant: st, non_zero: false });
+                }
+
+                if !dtor && def.variants.iter().all(|v| v.fields.is_empty()) {
+                    // All bodies empty -> intlike
+                    let (mut min, mut max) = (i64::MAX, i64::MIN);
+                    for v in &def.variants {
+                        let x = v.disr_val.to_u64_unchecked() as i64;
+                        if x < min { min = x; }
+                        if x > max { max = x; }
+                    }
+
+                    let (discr, signed) = Integer::repr_discr(tcx, hint, min, max);
+                    return Ok(CEnum {
+                        discr: discr,
+                        signed: signed,
+                        min: min as u64,
+                        max: max as u64
+                    });
+                }
+
+                // Since there's at least one
+                // non-empty body, explicit discriminants should have
+                // been rejected by a checker before this point.
+                for (i, v) in def.variants.iter().enumerate() {
+                    if i as u64 != v.disr_val.to_u64_unchecked() {
+                        bug!("non-C-like enum {} with specified discriminants",
+                             tcx.item_path_str(def.did));
+                    }
+                }
+
+                if def.variants.len() == 1 {
+                    // Equivalent to a struct/tuple/newtype.
+                    // (Typechecking will reject discriminant-sizing attrs.)
+                    assert_eq!(hint, attr::ReprAny);
+                    let fields = def.variants[0].fields.iter().map(|field| {
+                        normalize_associated_type(infcx, field.ty(tcx, substs))
+                            .layout(infcx)
+                    });
+                    let mut st = Struct::new(dl, false);
+                    st.extend(dl, fields.chain(drop_flag.iter().map(Ok)), ty)?;
+                    return Ok(Univariant { variant: st, non_zero: false });
+                }
+
+                // Cache the substituted and normalized variant field types.
+                let variants = def.variants.iter().map(|v| {
+                    v.fields.iter().map(|field| {
+                        normalize_associated_type(infcx, field.ty(tcx, substs))
+                    }).collect::<Vec<_>>()
+                }).collect::<Vec<_>>();
+
+                if !dtor && variants.len() == 2 && hint == attr::ReprAny {
+                    // Nullable pointer optimization
+                    for discr in 0..2 {
+                        let other_fields = variants[1 - discr].iter().map(|ty| {
+                            ty.layout(infcx)
+                        });
+                        if !Struct::would_be_zero_sized(dl, other_fields)? {
+                            continue;
+                        }
+                        let path = Struct::non_zero_field_path(infcx,
+                            variants[discr].iter().cloned())?;
+                        let mut path = if let Some(p) = path { p } else { continue };
+
+                        // FIXME(eddyb) should take advantage of a newtype.
+                        if path == &[0] && variants[discr].len() == 1 {
+                            match *variants[discr][0].layout(infcx)? {
+                                Scalar { value, .. } => {
+                                    return Ok(RawNullablePointer {
+                                        nndiscr: discr as u64,
+                                        value: value
+                                    });
+                                }
+                                _ => {
+                                    bug!("Layout::compute: `{}`'s non-zero \
+                                          `{}` field not scalar?!",
+                                         ty, variants[discr][0])
+                                }
+                            }
+                        }
+
+                        path.push(0); // For GEP through a pointer.
+                        path.reverse();
+                        let mut st = Struct::new(dl, false);
+                        st.extend(dl, variants[discr].iter().map(|ty| {
+                            ty.layout(infcx)
+                        }), ty)?;
+                        return Ok(StructWrappedNullablePointer {
+                            nndiscr: discr as u64,
+                            nonnull: st,
+                            discrfield: path
+                        });
+                    }
+                }
+
+                // The general case.
+                let discr_max = (variants.len() - 1) as i64;
+                assert!(discr_max >= 0);
+                let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max);
+
+                let mut align = dl.aggregate_align;
+                let mut size = Size::from_bytes(0);
+
+                // We're interested in the smallest alignment, so start large.
+                let mut start_align = Align::from_bytes(256, 256).unwrap();
+
+                // Create the set of structs that represent each variant
+                // Use the minimum integer type we figured out above
+                let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
+                let mut variants = variants.into_iter().map(|fields| {
+                    let mut found_start = false;
+                    let fields = fields.into_iter().map(|field| {
+                        let field = field.layout(infcx)?;
+                        if !found_start {
+                            // Find the first field we can't move later
+                            // to make room for a larger discriminant.
+                            let field_align = field.align(dl);
+                            if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
+                                start_align = start_align.min(field_align);
+                                found_start = true;
+                            }
+                        }
+                        Ok(field)
+                    });
+                    let mut st = Struct::new(dl, false);
+                    st.extend(dl, discr.iter().map(Ok).chain(fields)
+                                              .chain(drop_flag.iter().map(Ok)), ty)?;
+                    size = cmp::max(size, st.min_size());
+                    align = align.max(st.align);
+                    Ok(st)
+                }).collect::<Result<Vec<_>, _>>()?;
+
+                // Align the maximum variant size to the largest alignment.
+                size = size.abi_align(align);
+
+                if size.bytes() >= dl.obj_size_bound() {
+                    return Err(LayoutError::SizeOverflow(ty));
+                }
+
+                // Check to see if we should use a different type for the
+                // discriminant. We can safely use a type with the same size
+                // as the alignment of the first field of each variant.
+                // We increase the size of the discriminant to avoid LLVM copying
+                // padding when it doesn't need to. This normally causes unaligned
+                // load/stores and excessive memcpy/memset operations. By using a
+                // bigger integer size, LLVM can be sure about it's contents and
+                // won't be so conservative.
+
+                // Use the initial field alignment
+                let wanted = start_align.abi();
+                let mut ity = min_ity;
+                for &candidate in &[I16, I32, I64] {
+                    let ty = Int(candidate);
+                    if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
+                        ity = candidate;
+                        break;
+                    }
+                }
+
+                // FIXME(eddyb) conservative only to avoid diverging from trans::adt.
+                if align.abi() != start_align.abi() {
+                    ity = min_ity;
+                }
+
+                // If the alignment is not larger than the chosen discriminant size,
+                // don't use the alignment as the final size.
+                if ity <= min_ity {
+                    ity = min_ity;
+                } else {
+                    // Patch up the variants' first few fields.
+                    let old_ity_size = Int(min_ity).size(dl);
+                    let new_ity_size = Int(ity).size(dl);
+                    for variant in &mut variants {
+                        for offset in &mut variant.offset_after_field {
+                            if *offset > old_ity_size {
+                                break;
+                            }
+                            *offset = new_ity_size;
+                        }
+                    }
+                }
+
+                General {
+                    discr: ity,
+                    variants: variants,
+                    size: size,
+                    align: align
+                }
+            }
+
+            // Types with no meaningful known layout.
+            ty::TyProjection(_) | ty::TyParam(_) => {
+                return Err(LayoutError::Unknown(ty));
+            }
+            ty::TyInfer(_) | ty::TyError => {
+                bug!("Layout::compute: unexpected type `{}`", ty)
+            }
+        };
+
+        Ok(layout)
+    }
+
+    /// Returns true if the layout corresponds to an unsized type.
+    pub fn is_unsized(&self) -> bool {
+        match *self {
+            Scalar {..} | Vector {..} | FatPointer {..} |
+            CEnum {..} | General {..} |
+            RawNullablePointer {..} |
+            StructWrappedNullablePointer {..} => false,
+
+            Array { sized, .. } |
+            Univariant { variant: Struct { sized, .. }, .. } => !sized
+        }
+    }
+
+    pub fn size(&self, dl: &TargetDataLayout) -> Size {
+        match *self {
+            Scalar { value, .. } | RawNullablePointer { value, .. } => {
+                value.size(dl)
+            }
+
+            Vector { element, count } => {
+                let elem_size = element.size(dl);
+                let vec_size = match elem_size.checked_mul(count, dl) {
+                    Some(size) => size,
+                    None => bug!("Layout::size({:?}): {} * {} overflowed",
+                                 self, elem_size.bytes(), count)
+                };
+                vec_size.abi_align(self.align(dl))
+            }
+
+            FatPointer { metadata, .. } => {
+                // Effectively a (ptr, meta) tuple.
+                Pointer.size(dl).abi_align(metadata.align(dl))
+                       .checked_add(metadata.size(dl), dl).unwrap()
+                       .abi_align(self.align(dl))
+            }
+
+            CEnum { discr, .. } => Int(discr).size(dl),
+            Array { size, .. } | General { size, .. } => size,
+
+            Univariant { ref variant, .. } |
+            StructWrappedNullablePointer { nonnull: ref variant, .. } => {
+                variant.stride()
+            }
+        }
+    }
+
+    pub fn align(&self, dl: &TargetDataLayout) -> Align {
+        match *self {
+            Scalar { value, .. } | RawNullablePointer { value, .. } => {
+                value.align(dl)
+            }
+
+            Vector { element, count } => {
+                let elem_size = element.size(dl);
+                let vec_size = match elem_size.checked_mul(count, dl) {
+                    Some(size) => size,
+                    None => bug!("Layout::align({:?}): {} * {} overflowed",
+                                 self, elem_size.bytes(), count)
+                };
+                for &(size, align) in &dl.vector_align {
+                    if size == vec_size {
+                        return align;
+                    }
+                }
+                // Default to natural alignment, which is what LLVM does.
+                // That is, use the size, rounded up to a power of 2.
+                let align = vec_size.bytes().next_power_of_two();
+                Align::from_bytes(align, align).unwrap()
+            }
+
+            FatPointer { metadata, .. } => {
+                // Effectively a (ptr, meta) tuple.
+                Pointer.align(dl).max(metadata.align(dl))
+            }
+
+            CEnum { discr, .. } => Int(discr).align(dl),
+            Array { align, .. } | General { align, .. } => align,
+
+            Univariant { ref variant, .. } |
+            StructWrappedNullablePointer { nonnull: ref variant, .. } => {
+                variant.align
+            }
+        }
+    }
+}
+
+/// Type size "skeleton", i.e. the only information determining a type's size.
+/// While this is conservative, (aside from constant sizes, only pointers,
+/// newtypes thereof and null pointer optimized enums are allowed), it is
+/// enough to statically check common usecases of transmute.
+#[derive(Copy, Clone, Debug)]
+pub enum SizeSkeleton<'tcx> {
+    /// Any statically computable Layout.
+    Known(Size),
+
+    /// A potentially-fat pointer.
+    Pointer {
+        // If true, this pointer is never null.
+        non_zero: bool,
+        // The type which determines the unsized metadata, if any,
+        // of this pointer. Either a type parameter or a projection
+        // depending on one, with regions erased.
+        tail: Ty<'tcx>
+    }
+}
+
+impl<'tcx> SizeSkeleton<'tcx> {
+    pub fn compute<'a>(ty: Ty<'tcx>, infcx: &InferCtxt<'a, 'tcx>)
+                       -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
+        let tcx = infcx.tcx;
+        assert!(!ty.has_infer_types());
+
+        // First try computing a static layout.
+        let err = match ty.layout(infcx) {
+            Ok(layout) => {
+                return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout)));
+            }
+            Err(err) => err
+        };
+
+        match ty.sty {
+            ty::TyBox(pointee) |
+            ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
+            ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                let non_zero = !ty.is_unsafe_ptr();
+                let tail = tcx.struct_tail(pointee);
+                match tail.sty {
+                    ty::TyParam(_) | ty::TyProjection(_) => {
+                        assert!(tail.has_param_types() || tail.has_self_ty());
+                        Ok(SizeSkeleton::Pointer {
+                            non_zero: non_zero,
+                            tail: tcx.erase_regions(&tail)
+                        })
+                    }
+                    _ => {
+                        bug!("SizeSkeleton::compute({}): layout errored ({}), yet \
+                              tail `{}` is not a type parameter or a projection",
+                             ty, err, tail)
+                    }
+                }
+            }
+
+            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+                // Only newtypes and enums w/ nullable pointer optimization.
+                if def.variants.is_empty() || def.variants.len() > 2 {
+                    return Err(err);
+                }
+
+                // If there's a drop flag, it can't be just a pointer.
+                if def.dtor_kind().has_drop_flag() {
+                    return Err(err);
+                }
+
+                // Get a zero-sized variant or a pointer newtype.
+                let zero_or_ptr_variant = |i: usize| {
+                    let fields = def.variants[i].fields.iter().map(|field| {
+                        let ty = normalize_associated_type(infcx, &field.ty(tcx, substs));
+                        SizeSkeleton::compute(ty, infcx)
+                    });
+                    let mut ptr = None;
+                    for field in fields {
+                        let field = field?;
+                        match field {
+                            SizeSkeleton::Known(size) => {
+                                if size.bytes() > 0 {
+                                    return Err(err);
+                                }
+                            }
+                            SizeSkeleton::Pointer {..} => {
+                                if ptr.is_some() {
+                                    return Err(err);
+                                }
+                                ptr = Some(field);
+                            }
+                        }
+                    }
+                    Ok(ptr)
+                };
+
+                let v0 = zero_or_ptr_variant(0)?;
+                // Newtype.
+                if def.variants.len() == 1 {
+                    if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
+                        return Ok(SizeSkeleton::Pointer {
+                            non_zero: non_zero ||
+                                Some(def.did) == tcx.lang_items.non_zero(),
+                            tail: tail
+                        });
+                    } else {
+                        return Err(err);
+                    }
+                }
+
+                let v1 = zero_or_ptr_variant(1)?;
+                // Nullable pointer enum optimization.
+                match (v0, v1) {
+                    (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None) |
+                    (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
+                        Ok(SizeSkeleton::Pointer {
+                            non_zero: false,
+                            tail: tail
+                        })
+                    }
+                    _ => Err(err)
+                }
+            }
+
+            _ => Err(err)
+        }
+    }
+
+    pub fn same_size(self, other: SizeSkeleton) -> bool {
+        match (self, other) {
+            (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
+            (SizeSkeleton::Pointer { tail: a, .. },
+             SizeSkeleton::Pointer { tail: b, .. }) => a == b,
+            _ => false
+        }
+    }
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index cba3a9e2ebb..76e18565d65 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -85,6 +85,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;
@@ -471,37 +472,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,
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 354744b2787..60fc47426d5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -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};
@@ -596,6 +597,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.
diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs
index e1242560e62..2f0a043f9a7 100644
--- a/src/librustc_back/target/aarch64_apple_ios.rs
+++ b/src/librustc_back/target/aarch64_apple_ios.rs
@@ -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(),
diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs
index c6901a4cc42..c4212e70212 100644
--- a/src/librustc_back/target/aarch64_linux_android.rs
+++ b/src/librustc_back/target/aarch64_linux_android.rs
@@ -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(),
diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
index 51abab6609a..3bf4e92fb6a 100644
--- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
index 732f1a353a8..0a61b147634 100644
--- a/src/librustc_back/target/arm_linux_androideabi.rs
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -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(),
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
index 7c35b43fd4b..0cb0949d462 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -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(),
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
index a99ec45996c..05b9401a063 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -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(),
diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs
index d3064800291..d131f8b2ef0 100644
--- a/src/librustc_back/target/armv7_apple_ios.rs
+++ b/src/librustc_back/target/armv7_apple_ios.rs
@@ -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(),
diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
index d7dcd714a10..9c9bb72f76c 100644
--- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
@@ -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(),
diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs
index 66ec6efca0e..d317589bf36 100644
--- a/src/librustc_back/target/armv7s_apple_ios.rs
+++ b/src/librustc_back/target/armv7s_apple_ios.rs
@@ -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(),
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index 4330e2e7b5f..546f9df605b 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -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,
     }
diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs
index 52b5901192c..d149d4bbdc2 100644
--- a/src/librustc_back/target/i386_apple_ios.rs
+++ b/src/librustc_back/target/i386_apple_ios.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs
index 98f4654ecab..b6e2f4d8e8a 100644
--- a/src/librustc_back/target/i686_apple_darwin.rs
+++ b/src/librustc_back/target/i686_apple_darwin.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs
index f548fdad3cb..b338a971ff7 100644
--- a/src/librustc_back/target/i686_linux_android.rs
+++ b/src/librustc_back/target/i686_linux_android.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs
index fa12bbd8932..48203cc74d6 100644
--- a/src/librustc_back/target/i686_pc_windows_gnu.rs
+++ b/src/librustc_back/target/i686_pc_windows_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs
index 7fe65906189..501219ad607 100644
--- a/src/librustc_back/target/i686_pc_windows_msvc.rs
+++ b/src/librustc_back/target/i686_pc_windows_msvc.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs
index 32a15b9f2d4..cdbbd5eafdd 100644
--- a/src/librustc_back/target/i686_unknown_dragonfly.rs
+++ b/src/librustc_back/target/i686_unknown_dragonfly.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs
index 812ba11cd79..fadedc24149 100644
--- a/src/librustc_back/target/i686_unknown_freebsd.rs
+++ b/src/librustc_back/target/i686_unknown_freebsd.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs
index ac2af0c64fd..a1f3ab76907 100644
--- a/src/librustc_back/target/i686_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs
index 77bc7bb5175..cce023b8430 100644
--- a/src/librustc_back/target/i686_unknown_linux_musl.rs
+++ b/src/librustc_back/target/i686_unknown_linux_musl.rs
@@ -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(),
diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs
index d37102e558d..472b73302a3 100644
--- a/src/librustc_back/target/le32_unknown_nacl.rs
+++ b/src/librustc_back/target/le32_unknown_nacl.rs
@@ -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,
     }
diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs
index 01f2de4a269..863f5ceab0a 100644
--- a/src/librustc_back/target/mips_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs
index 050fb91aa19..ac0fde5449f 100644
--- a/src/librustc_back/target/mips_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mips_unknown_linux_musl.rs
@@ -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(),
diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
index e9eef72e8c3..ff33effa3e7 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
index 383a0d891ca..d9fb1405036 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
@@ -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(),
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index a8eac524971..cdd1e4c799d 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -40,10 +40,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;
@@ -76,7 +76,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);
                 }
@@ -162,6 +163,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,
 }
@@ -172,8 +175,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".
@@ -294,7 +298,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(),
@@ -379,6 +383,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", ""),
@@ -427,7 +432,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);
diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
index 3ba0c671d2e..fe7daaec1cd 100644
--- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
index f0fac14dae0..4aab2b1802c 100644
--- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
index 6664abf5458..1df36442c06 100644
--- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs
index 3e19e148290..c8b5dd0eccc 100644
--- a/src/librustc_back/target/x86_64_apple_darwin.rs
+++ b/src/librustc_back/target/x86_64_apple_darwin.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs
index 63234c0baee..d038e88f2b4 100644
--- a/src/librustc_back/target/x86_64_apple_ios.rs
+++ b/src/librustc_back/target/x86_64_apple_ios.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
index 3e843853915..f0a09ae71ef 100644
--- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs
+++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
index 14ce2735051..b3fbd6ef051 100644
--- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs
+++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index c97b434b9e0..652159d10fd 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs
index 541c1306b33..5aa08ea9c8c 100644
--- a/src/librustc_back/target/x86_64_sun_solaris.rs
+++ b/src/librustc_back/target/x86_64_sun_solaris.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs
index 04456b1b271..e8b95ed80d9 100644
--- a/src/librustc_back/target/x86_64_unknown_bitrig.rs
+++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
index 62654176aa4..3fa46c31a5e 100644
--- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs
+++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs
index 888b7f58bff..d345a321794 100644
--- a/src/librustc_back/target/x86_64_unknown_freebsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
index e3ccd9c4c7e..69e333a1350 100644
--- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
index dafbb924a9c..622a1fe8baf 100644
--- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs
+++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs
index 4101fabe734..74bf7189119 100644
--- a/src/librustc_back/target/x86_64_unknown_netbsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs
@@ -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(),
diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs
index 8c995113c21..521de5373d0 100644
--- a/src/librustc_back/target/x86_64_unknown_openbsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs
@@ -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(),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5f4244caa62..a0c4d636fd3 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -850,6 +850,9 @@ pub struct ModuleS<'a> {
     glob_importers: RefCell<Vec<(Module<'a>, &'a ImportDirective<'a>)>>,
     globs: RefCell<Vec<&'a ImportDirective<'a>>>,
 
+    // Used to memoize the traits in this module for faster searches through all traits in scope.
+    traits: RefCell<Option<Box<[&'a NameBinding<'a>]>>>,
+
     // Whether this module is populated. If not populated, any attempt to
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
@@ -877,6 +880,7 @@ impl<'a> ModuleS<'a> {
             prelude: RefCell::new(None),
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new((Vec::new())),
+            traits: RefCell::new(None),
             populated: Cell::new(!external),
             arenas: arenas
         }
@@ -3233,18 +3237,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut search_module = self.current_module;
         loop {
             // Look for trait children.
-            let mut search_in_module = |module: Module<'a>| module.for_each_child(|_, ns, binding| {
-                if ns != TypeNS { return }
-                let trait_def_id = match binding.def() {
-                    Some(Def::Trait(trait_def_id)) => trait_def_id,
-                    Some(..) | None => return,
-                };
-                if self.trait_item_map.contains_key(&(name, trait_def_id)) {
-                    add_trait_info(&mut found_traits, trait_def_id, name);
-                    let trait_name = self.get_trait_name(trait_def_id);
-                    self.record_use(trait_name, TypeNS, binding);
+            let mut search_in_module = |module: Module<'a>| {
+                let mut traits = module.traits.borrow_mut();
+                if traits.is_none() {
+                    let mut collected_traits = Vec::new();
+                    module.for_each_child(|_, ns, binding| {
+                        if ns != TypeNS { return }
+                        if let Some(Def::Trait(_)) = binding.def() {
+                            collected_traits.push(binding);
+                        }
+                    });
+                    *traits = Some(collected_traits.into_boxed_slice());
                 }
-            });
+
+                for binding in traits.as_ref().unwrap().iter() {
+                    let trait_def_id = binding.def().unwrap().def_id();
+                    if self.trait_item_map.contains_key(&(name, trait_def_id)) {
+                        add_trait_info(&mut found_traits, trait_def_id, name);
+                        let trait_name = self.get_trait_name(trait_def_id);
+                        self.record_use(trait_name, TypeNS, binding);
+                    }
+                }
+            };
             search_in_module(search_module);
 
             match search_module.parent_link {
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 738a99fbe92..1404b8cf3ad 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -275,7 +275,6 @@ impl<'a> ::ModuleS<'a> {
     // Define the name or return the existing binding if there is a collision.
     pub fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>)
                             -> Result<(), &'a NameBinding<'a>> {
-        if self.resolutions.borrow_state() != ::std::cell::BorrowState::Unused { return Ok(()); }
         self.update_resolution(name, ns, |resolution| {
             resolution.try_define(self.arenas.alloc_name_binding(binding))
         })
@@ -318,15 +317,22 @@ impl<'a> ::ModuleS<'a> {
     fn update_resolution<T, F>(&self, name: Name, ns: Namespace, update: F) -> T
         where F: FnOnce(&mut NameResolution<'a>) -> T
     {
-        let mut resolution = &mut *self.resolution(name, ns).borrow_mut();
-        let was_known = resolution.binding().is_some();
-
-        let t = update(resolution);
-        if !was_known {
-            if let Some(binding) = resolution.binding() {
-                self.define_in_glob_importers(name, ns, binding);
+        // Ensure that `resolution` isn't borrowed during `define_in_glob_importers`,
+        // where it might end up getting re-defined via a glob cycle.
+        let (new_binding, t) = {
+            let mut resolution = &mut *self.resolution(name, ns).borrow_mut();
+            let was_known = resolution.binding().is_some();
+
+            let t = update(resolution);
+
+            if was_known { return t; }
+            match resolution.binding() {
+                Some(binding) => (binding, t),
+                None => return t,
             }
-        }
+        };
+
+        self.define_in_glob_importers(name, ns, new_binding);
         t
     }
 
@@ -646,11 +652,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
         // Add to target_module's glob_importers
         target_module.glob_importers.borrow_mut().push((module_, directive));
 
-        for (&(name, ns), resolution) in target_module.resolutions.borrow().iter() {
-            if let Some(binding) = resolution.borrow().binding() {
-                if binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) {
-                    let _ = module_.try_define_child(name, ns, directive.import(binding, None));
-                }
+        // Ensure that `resolutions` isn't borrowed during `try_define_child`,
+        // since it might get updated via a glob cycle.
+        let bindings = target_module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
+            resolution.borrow().binding().map(|binding| (*name, binding))
+        }).collect::<Vec<_>>();
+        for ((name, ns), binding) in bindings {
+            if binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) {
+                let _ = module_.try_define_child(name, ns, directive.import(binding, None));
             }
         }
 
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index cb29f27b83f..9bbe0cb5f69 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -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 {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 17230eff6e6..104a74a63c9 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -77,7 +77,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;
@@ -2745,13 +2744,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");
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 392c40a6015..5a4a5022dfc 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -584,15 +584,19 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         debug!("get_fn: not casting pointer!");
 
         attributes::from_fn_attrs(ccx, attrs, llfn);
-        if let Some(id) = local_item {
+        if local_item.is_some() {
             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
             attributes::unwind(llfn, true);
-            ccx.item_symbols().borrow_mut().insert(id, sym);
         }
 
         llfn
     };
 
+    // Always insert into item_symbols, in case this item is exported.
+    if let Some(id) = local_item {
+        ccx.item_symbols().borrow_mut().insert(id, sym);
+    }
+
     ccx.instances().borrow_mut().insert(instance, llfn);
 
     immediate_rvalue(llfn, fn_ptr_ty)
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index c1802a5f0a9..1217b2b5a1b 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -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>) -> ! {
diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs
index 5ae60d18240..5e4902cf3ca 100644
--- a/src/librustc_trans/diagnostics.rs
+++ b/src/librustc_trans/diagnostics.rs
@@ -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:
 
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 5924ae1ad84..0f9b04c04f6 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -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
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 1f0a18ad4fa..863ae3f942e 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.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
 }
 
diff --git a/src/test/auxiliary/foreign_lib.rs b/src/test/auxiliary/foreign_lib.rs
index 92239ce5598..460d0a0088c 100644
--- a/src/test/auxiliary/foreign_lib.rs
+++ b/src/test/auxiliary/foreign_lib.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![crate_name="foreign_lib"]
+
 #![feature(libc)]
 
 pub mod rustrt {
@@ -19,3 +20,29 @@ pub mod rustrt {
         pub fn rust_get_test_int() -> libc::intptr_t;
     }
 }
+
+pub mod rustrt2 {
+    extern crate libc;
+
+    extern {
+        pub fn rust_get_test_int() -> libc::intptr_t;
+    }
+}
+
+pub mod rustrt3 {
+    // Different type, but same ABI (on all supported platforms).
+    // Ensures that we don't ICE or trigger LLVM asserts when
+    // importing the same symbol under different types.
+    // See https://github.com/rust-lang/rust/issues/32740.
+    extern {
+        pub fn rust_get_test_int() -> *const u8;
+    }
+}
+
+pub fn local_uses() {
+    unsafe {
+        let x = rustrt::rust_get_test_int();
+        assert_eq!(x, rustrt2::rust_get_test_int());
+        assert_eq!(x as *const _, rustrt3::rust_get_test_int());
+    }
+}
diff --git a/src/test/compile-fail/glob-cycles.rs b/src/test/compile-fail/glob-cycles.rs
new file mode 100644
index 00000000000..077ae19b4cb
--- /dev/null
+++ b/src/test/compile-fail/glob-cycles.rs
@@ -0,0 +1,26 @@
+// 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.
+
+mod foo {
+    pub use bar::*;
+    pub use main as f; //~ ERROR has already been imported
+}
+
+mod bar {
+    pub use foo::*;
+}
+
+pub use foo::*;
+pub use baz::*; //~ ERROR has already been imported
+mod baz {
+    pub use super::*;
+}
+
+pub fn main() {}
diff --git a/src/test/compile-fail/issue-21174.rs b/src/test/compile-fail/issue-21174.rs
index 30fd2eb4d2f..c92a404b71a 100644
--- a/src/test/compile-fail/issue-21174.rs
+++ b/src/test/compile-fail/issue-21174.rs
@@ -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() { }
diff --git a/src/test/compile-fail/issue-32377.rs b/src/test/compile-fail/issue-32377.rs
new file mode 100644
index 00000000000..6e8126348da
--- /dev/null
+++ b/src/test/compile-fail/issue-32377.rs
@@ -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() {}
diff --git a/src/test/compile-fail/issue-32797.rs b/src/test/compile-fail/issue-32797.rs
new file mode 100644
index 00000000000..af75783a710
--- /dev/null
+++ b/src/test/compile-fail/issue-32797.rs
@@ -0,0 +1,21 @@
+// 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.
+
+pub use bar::*;
+mod bar {
+    pub use super::*;
+}
+
+pub use baz::*; //~ ERROR already been imported
+mod baz {
+    pub use main as f;
+}
+
+pub fn main() {}
diff --git a/src/test/compile-fail/transmute-from-fn-item-types-error.rs b/src/test/compile-fail/transmute-from-fn-item-types-error.rs
new file mode 100644
index 00000000000..50bcd53ecb8
--- /dev/null
+++ b/src/test/compile-fail/transmute-from-fn-item-types-error.rs
@@ -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();
+    }
+}
diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
index 3eae76f9492..42c3cb7f181 100644
--- a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
+++ b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
@@ -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() {
diff --git a/src/test/compile-fail/transmute-type-parameters.rs b/src/test/compile-fail/transmute-type-parameters.rs
index b06966bd867..b6e7e32663e 100644
--- a/src/test/compile-fail/transmute-type-parameters.rs
+++ b/src/test/compile-fail/transmute-type-parameters.rs
@@ -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() {}
diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json
index e3080d29ec3..b7083c2776a 100644
--- a/src/test/run-make/target-specs/my-awesome-platform.json
+++ b/src/test/run-make/target-specs/my-awesome-platform.json
@@ -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",
diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs
index 6c393ce99e3..163ee617d6f 100644
--- a/src/test/run-pass/foreign-dupe.rs
+++ b/src/test/run-pass/foreign-dupe.rs
@@ -8,43 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// calling pin_thread and that's having weird side-effects.
+// aux-build:foreign_lib.rs
 
-// pretty-expanded FIXME #23616
+// Check that we can still call duplicated extern (imported) functions
+// which were declared in another crate. See issues #32740 and #32783.
 
-#![feature(libc)]
-
-mod rustrt1 {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers")]
-    extern {
-        pub fn rust_get_test_int() -> libc::intptr_t;
-    }
-}
-
-mod rustrt2 {
-    extern crate libc;
-
-    extern {
-        pub fn rust_get_test_int() -> libc::intptr_t;
-    }
-}
-
-mod rustrt3 {
-    // Different type, but same ABI (on all supported platforms).
-    // Ensures that we don't ICE or trigger LLVM asserts when
-    // importing the same symbol under different types.
-    // See https://github.com/rust-lang/rust/issues/32740.
-    extern {
-        pub fn rust_get_test_int() -> *const u8;
-    }
-}
+extern crate foreign_lib;
 
 pub fn main() {
     unsafe {
-        let x = rustrt1::rust_get_test_int();
-        assert_eq!(x, rustrt2::rust_get_test_int());
-        assert_eq!(x as *const _, rustrt3::rust_get_test_int());
+        let x = foreign_lib::rustrt::rust_get_test_int();
+        assert_eq!(x, foreign_lib::rustrt2::rust_get_test_int());
+        assert_eq!(x as *const _, foreign_lib::rustrt3::rust_get_test_int());
     }
 }