Resolve merge conflict
This commit is contained in:
commit
8a3ea01bca
110 changed files with 1691 additions and 713 deletions
2
configure
vendored
2
configure
vendored
|
|
@ -479,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
|
|||
valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
|
||||
valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
|
||||
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
|
||||
valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path"
|
||||
valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
|
||||
valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
|
||||
valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory"
|
||||
|
|
@ -746,6 +747,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK
|
|||
putvar CFG_ARM_LINUX_ANDROIDEABI_NDK
|
||||
putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK
|
||||
putvar CFG_I686_LINUX_ANDROID_NDK
|
||||
putvar CFG_X86_64_LINUX_ANDROID_NDK
|
||||
putvar CFG_NACL_CROSS_PATH
|
||||
putvar CFG_MANDIR
|
||||
putvar CFG_DOCDIR
|
||||
|
|
|
|||
2
rls
2
rls
|
|
@ -1 +1 @@
|
|||
Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373
|
||||
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce
|
||||
|
|
@ -151,6 +151,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
|
|||
if !up_to_date(src_file, dst_file) {
|
||||
let mut cmd = Command::new(&compiler_path);
|
||||
build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
|
||||
.arg("--cfg").arg(format!("stage{}", compiler.stage))
|
||||
.arg("--target").arg(target)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(dst_dir)
|
||||
|
|
|
|||
|
|
@ -570,6 +570,12 @@ impl Config {
|
|||
.or_insert(Target::default());
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => {
|
||||
let target = "x86_64-linux-android".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
|
||||
let path = parse_configure_path(value);
|
||||
self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ RUN curl -o /usr/local/bin/sccache \
|
|||
chmod +x /usr/local/bin/sccache
|
||||
|
||||
ENV TARGETS=arm-linux-androideabi
|
||||
ENV TARGETS=$TARGETS,armv7-linux-androideabi
|
||||
ENV TARGETS=$TARGETS,i686-linux-android
|
||||
ENV TARGETS=$TARGETS,aarch64-linux-android
|
||||
ENV TARGETS=$TARGETS,armv7-linux-androideabi
|
||||
ENV TARGETS=$TARGETS,x86_64-linux-android
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--target=$TARGETS \
|
||||
|
|
@ -46,6 +47,7 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--arm-linux-androideabi-ndk=/android/ndk-arm-9 \
|
||||
--armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
|
||||
--i686-linux-android-ndk=/android/ndk-x86-9 \
|
||||
--aarch64-linux-android-ndk=/android/ndk-aarch64
|
||||
--aarch64-linux-android-ndk=/android/ndk-arm64-21 \
|
||||
--x86_64-linux-android-ndk=/android/ndk-x86_64-21
|
||||
|
||||
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
|
|||
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
|
||||
--platform=android-21 \
|
||||
--toolchain=aarch64-linux-android-4.9 \
|
||||
--install-dir=/android/ndk-aarch64 \
|
||||
--install-dir=/android/ndk-arm64-21 \
|
||||
--ndk-dir=/android/android-ndk-r11c \
|
||||
--arch=arm64
|
||||
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
|
||||
|
|
@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
|
|||
--install-dir=/android/ndk-x86-9 \
|
||||
--ndk-dir=/android/android-ndk-r11c \
|
||||
--arch=x86
|
||||
bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
|
||||
--platform=android-21 \
|
||||
--toolchain=x86_64-4.9 \
|
||||
--install-dir=/android/ndk-x86_64-21 \
|
||||
--ndk-dir=/android/android-ndk-r11c \
|
||||
--arch=x86_64
|
||||
|
||||
rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
- [prelude_import](language-features/prelude-import.md)
|
||||
- [proc_macro](language-features/proc-macro.md)
|
||||
- [quote](language-features/quote.md)
|
||||
- [repr_align](language-features/repr-align.md)
|
||||
- [repr_simd](language-features/repr-simd.md)
|
||||
- [rustc_attrs](language-features/rustc-attrs.md)
|
||||
- [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md)
|
||||
|
|
@ -224,4 +225,3 @@
|
|||
- [windows_net](library-features/windows-net.md)
|
||||
- [windows_stdio](library-features/windows-stdio.md)
|
||||
- [zero_one](library-features/zero-one.md)
|
||||
>>>>>> Add top level sections to the Unstable Book.
|
||||
|
|
|
|||
11
src/doc/unstable-book/src/language-features/repr-align.md
Normal file
11
src/doc/unstable-book/src/language-features/repr-align.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# `repr_align`
|
||||
|
||||
The tracking issue for this feature is: [#33626]
|
||||
|
||||
[#33626]: https://github.com/rust-lang/rust/issues/33626
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -17,7 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot`
|
|||
GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"
|
||||
|
||||
# Run GDB with the additional arguments that load the pretty printers
|
||||
PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" gdb \
|
||||
# Set the environment variable `RUST_GDB` to overwrite the call to a
|
||||
# different/specific command (defaults to `gdb`).
|
||||
RUST_GDB="${RUST_GDB:-gdb}"
|
||||
PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \
|
||||
-d "$GDB_PYTHON_MODULE_DIRECTORY" \
|
||||
-iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \
|
||||
"$@"
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ pub struct Difference<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Difference")
|
||||
.field(&self.clone())
|
||||
.field(&self.a)
|
||||
.field(&self.b)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -160,7 +161,8 @@ pub struct SymmetricDifference<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("SymmetricDifference")
|
||||
.field(&self.clone())
|
||||
.field(&self.a)
|
||||
.field(&self.b)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +184,8 @@ pub struct Intersection<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Intersection")
|
||||
.field(&self.clone())
|
||||
.field(&self.a)
|
||||
.field(&self.b)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -204,7 +207,8 @@ pub struct Union<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Union")
|
||||
.field(&self.clone())
|
||||
.field(&self.a)
|
||||
.field(&self.b)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,8 @@ pub struct Iter<E> {
|
|||
impl<E: fmt::Debug> fmt::Debug for Iter<E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Iter")
|
||||
.field(&self.clone())
|
||||
.field(&self.index)
|
||||
.field(&self.bits)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ pub struct Iter<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Iter")
|
||||
.field(&self.clone())
|
||||
.field(&self.len)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@ pub struct IterMut<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IterMut")
|
||||
.field(self.clone())
|
||||
.field(&self.list)
|
||||
.field(&self.len)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +130,7 @@ pub struct IntoIter<T> {
|
|||
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IntoIter")
|
||||
.field(self.clone())
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -1128,7 +1129,7 @@ pub struct FrontPlace<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("FrontPlace")
|
||||
.field(self.clone())
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -1183,7 +1184,7 @@ pub struct BackPlace<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("BackPlace")
|
||||
.field(self.clone())
|
||||
.field(&self.list)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ fn test_extend() {
|
|||
let mut v = Vec::new();
|
||||
let mut w = Vec::new();
|
||||
|
||||
v.extend(w.clone());
|
||||
assert_eq!(v, &[]);
|
||||
|
||||
v.extend(0..3);
|
||||
for i in 0..3 {
|
||||
w.push(i)
|
||||
|
|
@ -100,6 +103,25 @@ fn test_extend() {
|
|||
|
||||
v.extend(w.clone()); // specializes to `append`
|
||||
assert!(v.iter().eq(w.iter().chain(w.iter())));
|
||||
|
||||
// Zero sized types
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct Foo;
|
||||
|
||||
let mut a = Vec::new();
|
||||
let b = vec![Foo, Foo];
|
||||
|
||||
a.extend(b);
|
||||
assert_eq!(a, &[Foo, Foo]);
|
||||
|
||||
// Double drop
|
||||
let mut count_x = 0;
|
||||
{
|
||||
let mut x = Vec::new();
|
||||
let y = vec![DropCounter { count: &mut count_x }];
|
||||
x.extend(y);
|
||||
}
|
||||
assert_eq!(count_x, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1041,18 +1041,22 @@ impl<T> Vec<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "append", since = "1.4.0")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
self.reserve(other.len());
|
||||
let len = self.len();
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(other.as_ptr(), self.get_unchecked_mut(len), other.len());
|
||||
}
|
||||
|
||||
self.len += other.len();
|
||||
unsafe {
|
||||
self.append_elements(other.as_slice() as _);
|
||||
other.set_len(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends elements to `Self` from other buffer.
|
||||
#[inline]
|
||||
unsafe fn append_elements(&mut self, other: *const [T]) {
|
||||
let count = (*other).len();
|
||||
self.reserve(count);
|
||||
let len = self.len();
|
||||
ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count);
|
||||
self.len += count;
|
||||
}
|
||||
|
||||
/// Create a draining iterator that removes the specified range in the vector
|
||||
/// and yields the removed items.
|
||||
///
|
||||
|
|
@ -1738,7 +1742,7 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
|
|||
vector
|
||||
}
|
||||
|
||||
fn spec_extend(&mut self, iterator: I) {
|
||||
default fn spec_extend(&mut self, iterator: I) {
|
||||
// This is the case for a TrustedLen iterator.
|
||||
let (low, high) = iterator.size_hint();
|
||||
if let Some(high_value) = high {
|
||||
|
|
@ -1783,6 +1787,13 @@ impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
|
|||
vector
|
||||
}
|
||||
}
|
||||
|
||||
fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
|
||||
unsafe {
|
||||
self.append_elements(iterator.as_slice() as _);
|
||||
}
|
||||
iterator.ptr = iterator.end;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec<T>
|
||||
|
|
|
|||
|
|
@ -1913,7 +1913,9 @@ pub struct Iter<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Iter")
|
||||
.field(&self.clone())
|
||||
.field(&self.ring)
|
||||
.field(&self.tail)
|
||||
.field(&self.head)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -2000,7 +2002,9 @@ pub struct IterMut<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IterMut")
|
||||
.field(&self.clone())
|
||||
.field(&self.ring)
|
||||
.field(&self.tail)
|
||||
.field(&self.head)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -2081,7 +2085,7 @@ pub struct IntoIter<T> {
|
|||
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IntoIter")
|
||||
.field(&self.clone())
|
||||
.field(&self.inner)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -2139,7 +2143,9 @@ pub struct Drain<'a, T: 'a> {
|
|||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("Drain")
|
||||
.field(&self.clone())
|
||||
.field(&self.after_tail)
|
||||
.field(&self.after_head)
|
||||
.field(&self.iter)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
//! Like many traits, these are often used as bounds for generic functions, to
|
||||
//! support arguments of multiple types.
|
||||
//!
|
||||
//! - Impl the `As*` traits for reference-to-reference conversions
|
||||
//! - Impl the [`Into`] trait when you want to consume the value in the conversion
|
||||
//! - Implement the `As*` traits for reference-to-reference conversions
|
||||
//! - Implement the [`Into`] trait when you want to consume the value in the conversion
|
||||
//! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions
|
||||
//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the
|
||||
//! conversion to fail
|
||||
|
|
@ -26,16 +26,16 @@
|
|||
//! As a library author, you should prefer implementing [`From<T>`][`From`] or
|
||||
//! [`TryFrom<T>`][`TryFrom`] rather than [`Into<U>`][`Into`] or [`TryInto<U>`][`TryInto`],
|
||||
//! as [`From`] and [`TryFrom`] provide greater flexibility and offer
|
||||
//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation
|
||||
//! in the standard library.
|
||||
//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a
|
||||
//! blanket implementation in the standard library.
|
||||
//!
|
||||
//! # Generic impl
|
||||
//! # Generic Implementations
|
||||
//!
|
||||
//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference
|
||||
//! - [`From`]`<U> for T` implies [`Into`]`<T> for U`
|
||||
//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> for U`
|
||||
//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()`
|
||||
//! themselves and `from()` themselves
|
||||
//! - [`From`] and [`Into`] are reflexive, which means that all types can
|
||||
//! `into` themselves and `from` themselves
|
||||
//!
|
||||
//! See each trait for usage examples.
|
||||
//!
|
||||
|
|
@ -50,20 +50,42 @@
|
|||
|
||||
use str::FromStr;
|
||||
|
||||
/// A cheap, reference-to-reference conversion.
|
||||
/// A cheap reference-to-reference conversion. Used to convert a value to a
|
||||
/// reference value within generic code.
|
||||
///
|
||||
/// `AsRef` is very similar to, but different than, [`Borrow`]. See
|
||||
/// [the book][book] for more.
|
||||
/// `AsRef` is very similar to, but serves a slightly different purpose than,
|
||||
/// [`Borrow`].
|
||||
///
|
||||
/// `AsRef` is to be used when wishing to convert to a reference of another
|
||||
/// type.
|
||||
/// `Borrow` is more related to the notion of taking the reference. It is
|
||||
/// useful when wishing to abstract over the type of reference
|
||||
/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated
|
||||
/// in the same manner.
|
||||
///
|
||||
/// The key difference between the two traits is the intention:
|
||||
///
|
||||
/// - Use `AsRef` when goal is to simply convert into a reference
|
||||
/// - Use `Borrow` when goal is related to writing code that is agnostic to the
|
||||
/// type of borrow and if is reference or value
|
||||
///
|
||||
/// See [the book][book] for a more detailed comparison.
|
||||
///
|
||||
/// [book]: ../../book/borrow-and-asref.html
|
||||
/// [`Borrow`]: ../../std/borrow/trait.Borrow.html
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
|
||||
/// returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use a
|
||||
/// dedicated method which returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
///
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
|
||||
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
|
||||
/// `&mut Foo` or `&&mut Foo`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Both [`String`] and `&str` implement `AsRef<str>`:
|
||||
|
|
@ -82,11 +104,6 @@ use str::FromStr;
|
|||
/// is_hello(s);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
|
||||
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
|
||||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait AsRef<T: ?Sized> {
|
||||
/// Performs the conversion.
|
||||
|
|
@ -96,12 +113,21 @@ pub trait AsRef<T: ?Sized> {
|
|||
|
||||
/// A cheap, mutable reference-to-mutable reference conversion.
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
|
||||
/// returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
/// This trait is similar to `AsRef` but used for converting between mutable
|
||||
/// references.
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use a
|
||||
/// dedicated method which returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
///
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
|
||||
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
|
||||
/// `&mut Foo` or `&&mut Foo`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`Box<T>`] implements `AsMut<T>`:
|
||||
|
|
@ -118,10 +144,6 @@ pub trait AsRef<T: ?Sized> {
|
|||
/// assert_eq!(*boxed_num, 1);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
|
||||
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`)
|
||||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait AsMut<T: ?Sized> {
|
||||
|
|
@ -130,14 +152,22 @@ pub trait AsMut<T: ?Sized> {
|
|||
fn as_mut(&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
/// A conversion that consumes `self`, which may or may not be expensive.
|
||||
/// A conversion that consumes `self`, which may or may not be expensive. The
|
||||
/// reciprocal of [`From`][From].
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated
|
||||
/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use
|
||||
/// [`TryInto`] or a dedicated method which returns an [`Option<T>`] or a
|
||||
/// [`Result<T, E>`].
|
||||
///
|
||||
/// Library authors should not directly implement this trait, but should prefer implementing
|
||||
/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into`
|
||||
/// implementation for free, thanks to a blanket implementation in the standard library.
|
||||
/// Library authors should not directly implement this trait, but should prefer
|
||||
/// implementing the [`From`][From] trait, which offers greater flexibility and
|
||||
/// provides an equivalent `Into` implementation for free, thanks to a blanket
|
||||
/// implementation in the standard library.
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - [`From<T>`][From]` for U` implies `Into<U> for T`
|
||||
/// - [`into`] is reflexive, which means that `Into<T> for T` is implemented
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -153,11 +183,6 @@ pub trait AsMut<T: ?Sized> {
|
|||
/// is_hello(s);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - [`From<T>`][From]` for U` implies `Into<U> for T`
|
||||
/// - [`into`] is reflexive, which means that `Into<T> for T` is implemented
|
||||
///
|
||||
/// [`TryInto`]: trait.TryInto.html
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
|
|
@ -171,10 +196,31 @@ pub trait Into<T>: Sized {
|
|||
fn into(self) -> T;
|
||||
}
|
||||
|
||||
/// Construct `Self` via a conversion.
|
||||
/// Simple and safe type conversions in to `Self`. It is the reciprocal of
|
||||
/// `Into`.
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated
|
||||
/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
|
||||
/// This trait is useful when performing error handling as described by
|
||||
/// [the book][book] and is closely related to the `?` operator.
|
||||
///
|
||||
/// When constructing a function that is capable of failing the return type
|
||||
/// will generally be of the form `Result<T, E>`.
|
||||
///
|
||||
/// The `From` trait allows for simplification of error handling by providing a
|
||||
/// means of returning a single error type that encapsulates numerous possible
|
||||
/// erroneous situations.
|
||||
///
|
||||
/// This trait is not limited to error handling, rather the general case for
|
||||
/// this trait would be in any type conversions to have an explicit definition
|
||||
/// of how they are performed.
|
||||
///
|
||||
/// **Note: this trait must not fail**. If the conversion can fail, use
|
||||
/// [`TryFrom`] or a dedicated method which returns an [`Option<T>`] or a
|
||||
/// [`Result<T, E>`].
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - `From<T> for U` implies [`Into<U>`]` for T`
|
||||
/// - [`from`] is reflexive, which means that `From<T> for T` is implemented
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -186,10 +232,38 @@ pub trait Into<T>: Sized {
|
|||
///
|
||||
/// assert_eq!(string, other_string);
|
||||
/// ```
|
||||
/// # Generic impls
|
||||
///
|
||||
/// - `From<T> for U` implies [`Into<U>`]` for T`
|
||||
/// - [`from`] is reflexive, which means that `From<T> for T` is implemented
|
||||
/// An example usage for error handling:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::{self, Read};
|
||||
/// use std::num;
|
||||
///
|
||||
/// enum CliError {
|
||||
/// IoError(io::Error),
|
||||
/// ParseError(num::ParseIntError),
|
||||
/// }
|
||||
///
|
||||
/// impl From<io::Error> for CliError {
|
||||
/// fn from(error: io::Error) -> Self {
|
||||
/// CliError::IoError(error)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl From<num::ParseIntError> for CliError {
|
||||
/// fn from(error: num::ParseIntError) -> Self {
|
||||
/// CliError::ParseError(error)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
|
||||
/// let mut file = std::fs::File::open("test")?;
|
||||
/// let mut contents = String::new();
|
||||
/// file.read_to_string(&mut contents)?;
|
||||
/// let num: i32 = contents.trim().parse()?;
|
||||
/// Ok(num)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`TryFrom`]: trait.TryFrom.html
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
|
|
@ -197,6 +271,7 @@ pub trait Into<T>: Sized {
|
|||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`Into<U>`]: trait.Into.html
|
||||
/// [`from`]: trait.From.html#tymethod.from
|
||||
/// [book]: ../../book/error-handling.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait From<T>: Sized {
|
||||
/// Performs the conversion.
|
||||
|
|
@ -204,11 +279,13 @@ pub trait From<T>: Sized {
|
|||
fn from(T) -> Self;
|
||||
}
|
||||
|
||||
/// An attempted conversion that consumes `self`, which may or may not be expensive.
|
||||
/// An attempted conversion that consumes `self`, which may or may not be
|
||||
/// expensive.
|
||||
///
|
||||
/// Library authors should not directly implement this trait, but should prefer implementing
|
||||
/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto`
|
||||
/// implementation for free, thanks to a blanket implementation in the standard library.
|
||||
/// Library authors should not directly implement this trait, but should prefer
|
||||
/// implementing the [`TryFrom`] trait, which offers greater flexibility and
|
||||
/// provides an equivalent `TryInto` implementation for free, thanks to a
|
||||
/// blanket implementation in the standard library.
|
||||
///
|
||||
/// [`TryFrom`]: trait.TryFrom.html
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
|
|
@ -236,7 +313,8 @@ pub trait TryFrom<T>: Sized {
|
|||
|
||||
// As lifts over &
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U>
|
||||
{
|
||||
fn as_ref(&self) -> &U {
|
||||
<T as AsRef<U>>::as_ref(*self)
|
||||
}
|
||||
|
|
@ -244,7 +322,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
|
|||
|
||||
// As lifts over &mut
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U>
|
||||
{
|
||||
fn as_ref(&self) -> &U {
|
||||
<T as AsRef<U>>::as_ref(*self)
|
||||
}
|
||||
|
|
@ -260,7 +339,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
|
|||
|
||||
// AsMut lifts over &mut
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
|
||||
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U>
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut U {
|
||||
(*self).as_mut()
|
||||
}
|
||||
|
|
@ -276,7 +356,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
|
|||
|
||||
// From implies Into
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, U> Into<U> for T where U: From<T> {
|
||||
impl<T, U> Into<U> for T where U: From<T>
|
||||
{
|
||||
fn into(self) -> U {
|
||||
U::from(self)
|
||||
}
|
||||
|
|
@ -291,7 +372,8 @@ impl<T> From<T> for T {
|
|||
|
||||
// TryFrom implies TryInto
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<T, U> TryInto<U> for T where U: TryFrom<T> {
|
||||
impl<T, U> TryInto<U> for T where U: TryFrom<T>
|
||||
{
|
||||
type Error = U::Error;
|
||||
|
||||
fn try_into(self) -> Result<U, U::Error> {
|
||||
|
|
@ -327,7 +409,8 @@ impl AsRef<str> for str {
|
|||
|
||||
// FromStr implies TryFrom<&str>
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<'a, T> TryFrom<&'a str> for T where T: FromStr {
|
||||
impl<'a, T> TryFrom<&'a str> for T where T: FromStr
|
||||
{
|
||||
type Error = <T as FromStr>::Err;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<T, Self::Error> {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use cell::UnsafeCell;
|
||||
use cmp;
|
||||
use hash::Hash;
|
||||
use hash::Hasher;
|
||||
|
|
@ -553,3 +554,19 @@ mod impls {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
|
||||
}
|
||||
|
||||
/// Compiler-internal trait used to determine whether a type contains
|
||||
/// any `UnsafeCell` internally, but not through an indirection.
|
||||
/// This affects, for example, whether a `static` of that type is
|
||||
/// placed in read-only static memory or writable static memory.
|
||||
#[cfg_attr(not(stage0), lang = "freeze")]
|
||||
unsafe trait Freeze {}
|
||||
|
||||
unsafe impl Freeze for .. {}
|
||||
|
||||
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for *const T {}
|
||||
unsafe impl<T: ?Sized> Freeze for *mut T {}
|
||||
unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
|
||||
unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f
|
||||
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
|
||||
|
|
@ -1847,5 +1847,6 @@ register_diagnostics! {
|
|||
E0489, // type/lifetime parameter not in scope here
|
||||
E0490, // a value of type `..` is borrowed for too long
|
||||
E0495, // cannot infer an appropriate lifetime due to conflicting requirements
|
||||
E0566 // conflicting representation hints
|
||||
E0566, // conflicting representation hints
|
||||
E0587, // conflicting packed and align representation hints
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
};
|
||||
|
||||
let mut conflicting_reprs = 0;
|
||||
let mut found_packed = false;
|
||||
let mut found_align = false;
|
||||
|
||||
for word in words {
|
||||
|
||||
let name = match word.name() {
|
||||
|
|
@ -84,6 +87,7 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
("attribute should be applied to struct or union",
|
||||
"a struct or union")
|
||||
} else {
|
||||
found_packed = true;
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +100,15 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
continue
|
||||
}
|
||||
}
|
||||
"align" => {
|
||||
found_align = true;
|
||||
if target != Target::Struct {
|
||||
("attribute should be applied to struct",
|
||||
"a struct")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
"i8" | "u8" | "i16" | "u16" |
|
||||
"i32" | "u32" | "i64" | "u64" |
|
||||
"isize" | "usize" => {
|
||||
|
|
@ -117,6 +130,10 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
span_warn!(self.sess, attr.span, E0566,
|
||||
"conflicting representation hints");
|
||||
}
|
||||
if found_align && found_packed {
|
||||
struct_span_err!(self.sess, attr.span, E0587,
|
||||
"conflicting packed and align representation hints").emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ language_item_table! {
|
|||
UnsizeTraitLangItem, "unsize", unsize_trait;
|
||||
CopyTraitLangItem, "copy", copy_trait;
|
||||
SyncTraitLangItem, "sync", sync_trait;
|
||||
FreezeTraitLangItem, "freeze", freeze_trait;
|
||||
|
||||
DropTraitLangItem, "drop", drop_trait;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,255 +0,0 @@
|
|||
// Copyright 2012-2015 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 hir::def_id::{DefId};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::FxHashMap;
|
||||
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
/// Type contents is how the type checker reasons about kinds.
|
||||
/// They track what kinds of things are found within a type. You can
|
||||
/// think of them as kind of an "anti-kind". They track the kinds of values
|
||||
/// and thinks that are contained in types. Having a larger contents for
|
||||
/// a type tends to rule that type *out* from various kinds. For example,
|
||||
/// a type that contains a reference is not sendable.
|
||||
///
|
||||
/// The reason we compute type contents and not kinds is that it is
|
||||
/// easier for me (nmatsakis) to think about what is contained within
|
||||
/// a type than to think about what is *not* contained within a type.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TypeContents {
|
||||
pub bits: u64
|
||||
}
|
||||
|
||||
macro_rules! def_type_content_sets {
|
||||
(mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
|
||||
#[allow(non_snake_case)]
|
||||
mod $mname {
|
||||
use super::TypeContents;
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: TypeContents = TypeContents { bits: $bits };
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_type_content_sets! {
|
||||
mod TC {
|
||||
None = 0b0000_0000__0000_0000__0000,
|
||||
|
||||
// Things that are interior to the value (first nibble):
|
||||
InteriorUnsafe = 0b0000_0000__0000_0000__0010,
|
||||
InteriorParam = 0b0000_0000__0000_0000__0100,
|
||||
// InteriorAll = 0b00000000__00000000__1111,
|
||||
|
||||
// Things that are owned by the value (second and third nibbles):
|
||||
OwnsDtor = 0b0000_0000__0000_0010__0000,
|
||||
// OwnsAll = 0b0000_0000__1111_1111__0000,
|
||||
|
||||
// All bits
|
||||
All = 0b1111_1111__1111_1111__1111
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeContents {
|
||||
pub fn when(&self, cond: bool) -> TypeContents {
|
||||
if cond {*self} else {TC::None}
|
||||
}
|
||||
|
||||
pub fn intersects(&self, tc: TypeContents) -> bool {
|
||||
(self.bits & tc.bits) != 0
|
||||
}
|
||||
|
||||
pub fn interior_param(&self) -> bool {
|
||||
self.intersects(TC::InteriorParam)
|
||||
}
|
||||
|
||||
pub fn interior_unsafe(&self) -> bool {
|
||||
self.intersects(TC::InteriorUnsafe)
|
||||
}
|
||||
|
||||
pub fn needs_drop(&self, _: TyCtxt) -> bool {
|
||||
self.intersects(TC::OwnsDtor)
|
||||
}
|
||||
|
||||
pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
|
||||
I: IntoIterator<Item=T>,
|
||||
F: FnMut(T) -> TypeContents,
|
||||
{
|
||||
v.into_iter().fold(TC::None, |tc, ty| tc | f(ty))
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::BitOr for TypeContents {
|
||||
type Output = TypeContents;
|
||||
|
||||
fn bitor(self, other: TypeContents) -> TypeContents {
|
||||
TypeContents {bits: self.bits | other.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::BitAnd for TypeContents {
|
||||
type Output = TypeContents;
|
||||
|
||||
fn bitand(self, other: TypeContents) -> TypeContents {
|
||||
TypeContents {bits: self.bits & other.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for TypeContents {
|
||||
type Output = TypeContents;
|
||||
|
||||
fn sub(self, other: TypeContents) -> TypeContents {
|
||||
TypeContents {bits: self.bits & !other.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TypeContents {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TypeContents({:b})", self.bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents {
|
||||
return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap()));
|
||||
|
||||
fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
cache: &mut FxHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
|
||||
{
|
||||
// Subtle: Note that we are *not* using tcx.tc_cache here but rather a
|
||||
// private cache for this walk. This is needed in the case of cyclic
|
||||
// types like:
|
||||
//
|
||||
// struct List { next: Box<Option<List>>, ... }
|
||||
//
|
||||
// When computing the type contents of such a type, we wind up deeply
|
||||
// recursing as we go. So when we encounter the recursive reference
|
||||
// to List, we temporarily use TC::None as its contents. Later we'll
|
||||
// patch up the cache with the correct value, once we've computed it
|
||||
// (this is basically a co-inductive process, if that helps). So in
|
||||
// the end we'll compute TC::OwnsOwned, in this case.
|
||||
//
|
||||
// The problem is, as we are doing the computation, we will also
|
||||
// compute an *intermediate* contents for, e.g., Option<List> of
|
||||
// TC::None. This is ok during the computation of List itself, but if
|
||||
// we stored this intermediate value into tcx.tc_cache, then later
|
||||
// requests for the contents of Option<List> would also yield TC::None
|
||||
// which is incorrect. This value was computed based on the crutch
|
||||
// value for the type contents of list. The correct value is
|
||||
// TC::OwnsOwned. This manifested as issue #4821.
|
||||
if let Some(tc) = cache.get(&ty) {
|
||||
return *tc;
|
||||
}
|
||||
// Must check both caches!
|
||||
if let Some(tc) = tcx.tc_cache.borrow().get(&ty) {
|
||||
return *tc;
|
||||
}
|
||||
cache.insert(ty, TC::None);
|
||||
|
||||
let result = match ty.sty {
|
||||
// usize and isize are ffi-unsafe
|
||||
ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => {
|
||||
TC::None
|
||||
}
|
||||
|
||||
// Scalar and unique types are sendable, and durable
|
||||
ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
|
||||
ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
|
||||
TC::None
|
||||
}
|
||||
|
||||
ty::TyDynamic(..) => {
|
||||
TC::All - TC::InteriorParam
|
||||
}
|
||||
|
||||
ty::TyRawPtr(_) => {
|
||||
TC::None
|
||||
}
|
||||
|
||||
ty::TyRef(..) => {
|
||||
TC::None
|
||||
}
|
||||
|
||||
ty::TyArray(ty, _) => {
|
||||
tc_ty(tcx, ty, cache)
|
||||
}
|
||||
|
||||
ty::TySlice(ty) => {
|
||||
tc_ty(tcx, ty, cache)
|
||||
}
|
||||
ty::TyStr => TC::None,
|
||||
|
||||
ty::TyClosure(def_id, ref substs) => {
|
||||
TypeContents::union(
|
||||
substs.upvar_tys(def_id, tcx),
|
||||
|ty| tc_ty(tcx, &ty, cache))
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
TypeContents::union(&tys[..],
|
||||
|ty| tc_ty(tcx, *ty, cache))
|
||||
}
|
||||
|
||||
ty::TyAdt(def, substs) => {
|
||||
let mut res =
|
||||
TypeContents::union(&def.variants, |v| {
|
||||
TypeContents::union(&v.fields, |f| {
|
||||
tc_ty(tcx, f.ty(tcx, substs), cache)
|
||||
})
|
||||
});
|
||||
|
||||
if def.is_union() {
|
||||
// unions don't have destructors regardless of the child types
|
||||
res = res - TC::OwnsDtor;
|
||||
}
|
||||
|
||||
if def.has_dtor(tcx) {
|
||||
res = res | TC::OwnsDtor;
|
||||
}
|
||||
|
||||
apply_lang_items(tcx, def.did, res)
|
||||
}
|
||||
|
||||
ty::TyProjection(..) |
|
||||
ty::TyParam(_) |
|
||||
ty::TyAnon(..) => {
|
||||
TC::All
|
||||
}
|
||||
|
||||
ty::TyInfer(_) |
|
||||
ty::TyError => {
|
||||
bug!("asked to compute contents of error type");
|
||||
}
|
||||
};
|
||||
|
||||
cache.insert(ty, result);
|
||||
result
|
||||
}
|
||||
|
||||
fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
did: DefId, tc: TypeContents)
|
||||
-> TypeContents {
|
||||
if Some(did) == tcx.lang_items.unsafe_cell_type() {
|
||||
tc | TC::InteriorUnsafe
|
||||
} else {
|
||||
tc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -436,9 +436,6 @@ pub struct GlobalCtxt<'tcx> {
|
|||
// Internal cache for metadata decoding. No need to track deps on this.
|
||||
pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
|
||||
|
||||
// Cache for the type-contents routine. FIXME -- track deps?
|
||||
pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
|
||||
|
||||
// FIXME dep tracking -- should be harmless enough
|
||||
pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
|
||||
|
||||
|
|
@ -708,7 +705,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
freevars: RefCell::new(resolutions.freevars),
|
||||
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
|
||||
rcache: RefCell::new(FxHashMap()),
|
||||
tc_cache: RefCell::new(FxHashMap()),
|
||||
normalized_cache: RefCell::new(FxHashMap()),
|
||||
inhabitedness_cache: RefCell::new(FxHashMap()),
|
||||
lang_items: lang_items,
|
||||
|
|
|
|||
|
|
@ -548,8 +548,12 @@ pub type FieldPath = Vec<u32>;
|
|||
/// A structure, a product type in ADT terms.
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Struct {
|
||||
/// Maximum alignment of fields and repr alignment.
|
||||
pub align: Align,
|
||||
|
||||
/// Primitive alignment of fields without repr alignment.
|
||||
pub primitive_align: Align,
|
||||
|
||||
/// If true, no alignment padding is used.
|
||||
pub packed: bool,
|
||||
|
||||
|
|
@ -583,10 +587,20 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
|
||||
repr: &ReprOptions, kind: StructKind,
|
||||
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
|
||||
let packed = repr.packed();
|
||||
if repr.packed() && repr.align > 0 {
|
||||
bug!("Struct cannot be packed and aligned");
|
||||
}
|
||||
|
||||
let align = if repr.packed() {
|
||||
dl.i8_align
|
||||
} else {
|
||||
dl.aggregate_align
|
||||
};
|
||||
|
||||
let mut ret = Struct {
|
||||
align: if packed { dl.i8_align } else { dl.aggregate_align },
|
||||
packed: packed,
|
||||
align: align,
|
||||
primitive_align: align,
|
||||
packed: repr.packed(),
|
||||
sized: true,
|
||||
offsets: vec![],
|
||||
memory_index: vec![],
|
||||
|
|
@ -660,7 +674,9 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
// Invariant: offset < dl.obj_size_bound() <= 1<<61
|
||||
if !ret.packed {
|
||||
let align = field.align(dl);
|
||||
let primitive_align = field.primitive_align(dl);
|
||||
ret.align = ret.align.max(align);
|
||||
ret.primitive_align = ret.primitive_align.max(primitive_align);
|
||||
offset = offset.abi_align(align);
|
||||
}
|
||||
|
||||
|
|
@ -671,6 +687,11 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
.map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
|
||||
}
|
||||
|
||||
if repr.align > 0 {
|
||||
let repr_align = repr.align as u64;
|
||||
ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap());
|
||||
debug!("Struct::new repr_align: {:?}", repr_align);
|
||||
}
|
||||
|
||||
debug!("Struct::new min_size: {:?}", offset);
|
||||
ret.min_size = offset;
|
||||
|
|
@ -836,12 +857,23 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn over_align(&self) -> Option<u32> {
|
||||
let align = self.align.abi();
|
||||
let primitive_align = self.primitive_align.abi();
|
||||
if align > primitive_align {
|
||||
Some(align as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An untagged union.
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Union {
|
||||
pub align: Align,
|
||||
pub primitive_align: Align,
|
||||
|
||||
pub min_size: Size,
|
||||
|
||||
|
|
@ -851,8 +883,10 @@ pub struct Union {
|
|||
|
||||
impl<'a, 'gcx, 'tcx> Union {
|
||||
fn new(dl: &TargetDataLayout, packed: bool) -> Union {
|
||||
let align = if packed { dl.i8_align } else { dl.aggregate_align };
|
||||
Union {
|
||||
align: if packed { dl.i8_align } else { dl.aggregate_align },
|
||||
align: align,
|
||||
primitive_align: align,
|
||||
min_size: Size::from_bytes(0),
|
||||
packed: packed,
|
||||
}
|
||||
|
|
@ -875,6 +909,7 @@ impl<'a, 'gcx, 'tcx> Union {
|
|||
|
||||
if !self.packed {
|
||||
self.align = self.align.max(field.align(dl));
|
||||
self.primitive_align = self.primitive_align.max(field.primitive_align(dl));
|
||||
}
|
||||
self.min_size = cmp::max(self.min_size, field.size(dl));
|
||||
}
|
||||
|
|
@ -888,6 +923,16 @@ impl<'a, 'gcx, 'tcx> Union {
|
|||
pub fn stride(&self) -> Size {
|
||||
self.min_size.abi_align(self.align)
|
||||
}
|
||||
|
||||
pub fn over_align(&self) -> Option<u32> {
|
||||
let align = self.align.abi();
|
||||
let primitive_align = self.primitive_align.abi();
|
||||
if align > primitive_align {
|
||||
Some(align as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The first half of a fat pointer.
|
||||
|
|
@ -924,6 +969,7 @@ pub enum Layout {
|
|||
/// If true, the size is exact, otherwise it's only a lower bound.
|
||||
sized: bool,
|
||||
align: Align,
|
||||
primitive_align: Align,
|
||||
element_size: Size,
|
||||
count: u64
|
||||
},
|
||||
|
|
@ -970,7 +1016,8 @@ pub enum Layout {
|
|||
discr: Integer,
|
||||
variants: Vec<Struct>,
|
||||
size: Size,
|
||||
align: Align
|
||||
align: Align,
|
||||
primitive_align: Align,
|
||||
},
|
||||
|
||||
/// Two cases distinguished by a nullable pointer: the case with discriminant
|
||||
|
|
@ -1118,6 +1165,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
Array {
|
||||
sized: true,
|
||||
align: element.align(dl),
|
||||
primitive_align: element.primitive_align(dl),
|
||||
element_size: element_size,
|
||||
count: count
|
||||
}
|
||||
|
|
@ -1127,6 +1175,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
Array {
|
||||
sized: false,
|
||||
align: element.align(dl),
|
||||
primitive_align: element.primitive_align(dl),
|
||||
element_size: element.size(dl),
|
||||
count: 0
|
||||
}
|
||||
|
|
@ -1135,6 +1184,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
Array {
|
||||
sized: false,
|
||||
align: dl.i8_align,
|
||||
primitive_align: dl.i8_align,
|
||||
element_size: Size::from_bytes(1),
|
||||
count: 0
|
||||
}
|
||||
|
|
@ -1340,6 +1390,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
assert!(discr_max >= 0);
|
||||
let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut primitive_align = dl.aggregate_align;
|
||||
let mut size = Size::from_bytes(0);
|
||||
|
||||
// We're interested in the smallest alignment, so start large.
|
||||
|
|
@ -1369,6 +1420,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
}
|
||||
size = cmp::max(size, st.min_size);
|
||||
align = align.max(st.align);
|
||||
primitive_align = primitive_align.max(st.primitive_align);
|
||||
Ok(st)
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
|
|
@ -1435,7 +1487,8 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
discr: ity,
|
||||
variants: variants,
|
||||
size: size,
|
||||
align: align
|
||||
align: align,
|
||||
primitive_align: primitive_align
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1557,6 +1610,30 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns alignment before repr alignment is applied
|
||||
pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align {
|
||||
match *self {
|
||||
Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align,
|
||||
Univariant { ref variant, .. } |
|
||||
StructWrappedNullablePointer { nonnull: ref variant, .. } => {
|
||||
variant.primitive_align
|
||||
},
|
||||
|
||||
_ => self.align(dl)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns repr alignment if it is greater than the primitive alignment.
|
||||
pub fn over_align(&self, dl: &TargetDataLayout) -> Option<u32> {
|
||||
let align = self.align(dl);
|
||||
let primitive_align = self.primitive_align(dl);
|
||||
if align.abi() > primitive_align.abi() {
|
||||
Some(align.abi() as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_offset<C: HasDataLayout>(&self,
|
||||
cx: C,
|
||||
i: usize,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ use serialize::{self, Encodable, Encoder};
|
|||
use std::borrow::Cow;
|
||||
use std::cell::{Cell, RefCell, Ref};
|
||||
use std::collections::BTreeMap;
|
||||
use std::cmp;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -71,7 +72,6 @@ pub use self::sty::InferTy::*;
|
|||
pub use self::sty::Region::*;
|
||||
pub use self::sty::TypeVariants::*;
|
||||
|
||||
pub use self::contents::TypeContents;
|
||||
pub use self::context::{TyCtxt, GlobalArenas, tls};
|
||||
pub use self::context::{Lift, TypeckTables};
|
||||
|
||||
|
|
@ -99,7 +99,6 @@ pub mod walk;
|
|||
pub mod wf;
|
||||
pub mod util;
|
||||
|
||||
mod contents;
|
||||
mod context;
|
||||
mod flags;
|
||||
mod instance;
|
||||
|
|
@ -425,6 +424,10 @@ bitflags! {
|
|||
const IS_SIZED = 1 << 17,
|
||||
const MOVENESS_CACHED = 1 << 18,
|
||||
const MOVES_BY_DEFAULT = 1 << 19,
|
||||
const FREEZENESS_CACHED = 1 << 20,
|
||||
const IS_FREEZE = 1 << 21,
|
||||
const NEEDS_DROP_CACHED = 1 << 22,
|
||||
const NEEDS_DROP = 1 << 23,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1181,6 +1184,9 @@ pub struct ParameterEnvironment<'tcx> {
|
|||
|
||||
/// A cache for `type_is_sized`
|
||||
pub is_sized_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
|
||||
|
||||
/// A cache for `type_is_freeze`
|
||||
pub is_freeze_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
||||
|
|
@ -1195,6 +1201,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
|||
free_id_outlive: self.free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1464,10 +1471,12 @@ impl_stable_hash_for!(struct ReprFlags {
|
|||
#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
|
||||
pub struct ReprOptions {
|
||||
pub int: Option<attr::IntType>,
|
||||
pub align: u16,
|
||||
pub flags: ReprFlags,
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ReprOptions {
|
||||
align,
|
||||
int,
|
||||
flags
|
||||
});
|
||||
|
|
@ -1476,7 +1485,7 @@ impl ReprOptions {
|
|||
pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
|
||||
let mut flags = ReprFlags::empty();
|
||||
let mut size = None;
|
||||
|
||||
let mut max_align = 0;
|
||||
for attr in tcx.get_attrs(did).iter() {
|
||||
for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
|
||||
flags.insert(match r {
|
||||
|
|
@ -1487,6 +1496,10 @@ impl ReprOptions {
|
|||
size = Some(i);
|
||||
ReprFlags::empty()
|
||||
},
|
||||
attr::ReprAlign(align) => {
|
||||
max_align = cmp::max(align, max_align);
|
||||
ReprFlags::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1500,7 +1513,7 @@ impl ReprOptions {
|
|||
if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) {
|
||||
flags.insert(ReprFlags::IS_LINEAR);
|
||||
}
|
||||
ReprOptions { int: size, flags: flags }
|
||||
ReprOptions { int: size, align: max_align, flags: flags }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -2375,40 +2388,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
Some(self.item_mir(did))
|
||||
}
|
||||
|
||||
/// If `type_needs_drop` returns true, then `ty` is definitely
|
||||
/// non-copy and *might* have a destructor attached; if it returns
|
||||
/// false, then `ty` definitely has no destructor (i.e. no drop glue).
|
||||
///
|
||||
/// (Note that this implies that if `ty` has a destructor attached,
|
||||
/// then `type_needs_drop` will definitely return `true` for `ty`.)
|
||||
pub fn type_needs_drop_given_env(self,
|
||||
ty: Ty<'gcx>,
|
||||
param_env: &ty::ParameterEnvironment<'gcx>) -> bool {
|
||||
// Issue #22536: We first query type_moves_by_default. It sees a
|
||||
// normalized version of the type, and therefore will definitely
|
||||
// know whether the type implements Copy (and thus needs no
|
||||
// cleanup/drop/zeroing) ...
|
||||
let tcx = self.global_tcx();
|
||||
let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP);
|
||||
|
||||
if implements_copy { return false; }
|
||||
|
||||
// ... (issue #22536 continued) but as an optimization, still use
|
||||
// prior logic of asking if the `needs_drop` bit is set; we need
|
||||
// not zero non-Copy types if they have no destructor.
|
||||
|
||||
// FIXME(#22815): Note that calling `ty::type_contents` is a
|
||||
// conservative heuristic; it may report that `needs_drop` is set
|
||||
// when actual type does not actually have a destructor associated
|
||||
// with it. But since `ty` absolutely did not have the `Copy`
|
||||
// bound attached (see above), it is sound to treat it as having a
|
||||
// destructor (e.g. zero its memory on move).
|
||||
|
||||
let contents = ty.type_contents(tcx);
|
||||
debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
|
||||
contents.needs_drop(tcx)
|
||||
}
|
||||
|
||||
/// Get the attributes of a definition.
|
||||
pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> {
|
||||
if let Some(id) = self.hir.as_local_node_id(did) {
|
||||
|
|
@ -2531,6 +2510,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2603,6 +2583,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
};
|
||||
|
||||
let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use ty::fold::TypeVisitor;
|
|||
use ty::layout::{Layout, LayoutError};
|
||||
use ty::TypeVariants::*;
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::FxHashMap;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use middle::lang_items;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
|
|
@ -655,6 +655,165 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Returns `true` if and only if there are no `UnsafeCell`s
|
||||
/// nested within the type (ignoring `PhantomData` or pointers).
|
||||
#[inline]
|
||||
pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
span: Span) -> bool
|
||||
{
|
||||
if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) {
|
||||
return self.flags.get().intersects(TypeFlags::IS_FREEZE);
|
||||
}
|
||||
|
||||
self.is_freeze_uncached(tcx, param_env, span)
|
||||
}
|
||||
|
||||
fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
span: Span) -> bool {
|
||||
assert!(!self.needs_infer());
|
||||
|
||||
// Fast-path for primitive types
|
||||
let result = match self.sty {
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
|
||||
TyStr | TyNever => Some(true),
|
||||
|
||||
TyArray(..) | TySlice(_) |
|
||||
TyTuple(..) | TyClosure(..) | TyAdt(..) |
|
||||
TyDynamic(..) | TyProjection(..) | TyParam(..) |
|
||||
TyInfer(..) | TyAnon(..) | TyError => None
|
||||
}.unwrap_or_else(|| {
|
||||
self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem),
|
||||
¶m_env.is_freeze_cache, span) });
|
||||
|
||||
if !self.has_param_types() && !self.has_self_ty() {
|
||||
self.flags.set(self.flags.get() | if result {
|
||||
TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE
|
||||
} else {
|
||||
TypeFlags::FREEZENESS_CACHED
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
|
||||
/// non-copy and *might* have a destructor attached; if it returns
|
||||
/// `false`, then `ty` definitely has no destructor (i.e. no drop glue).
|
||||
///
|
||||
/// (Note that this implies that if `ty` has a destructor attached,
|
||||
/// then `needs_drop` will definitely return `true` for `ty`.)
|
||||
#[inline]
|
||||
pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>) -> bool {
|
||||
if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
|
||||
return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
|
||||
}
|
||||
|
||||
self.needs_drop_uncached(tcx, param_env, &mut FxHashSet())
|
||||
}
|
||||
|
||||
fn needs_drop_inner(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
stack: &mut FxHashSet<Ty<'tcx>>)
|
||||
-> bool {
|
||||
if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
|
||||
return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
|
||||
}
|
||||
|
||||
// This should be reported as an error by `check_representable`.
|
||||
//
|
||||
// Consider the type as not needing drop in the meanwhile to avoid
|
||||
// further errors.
|
||||
if let Some(_) = stack.replace(self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let needs_drop = self.needs_drop_uncached(tcx, param_env, stack);
|
||||
|
||||
// "Pop" the cycle detection "stack".
|
||||
stack.remove(self);
|
||||
|
||||
needs_drop
|
||||
}
|
||||
|
||||
fn needs_drop_uncached(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
stack: &mut FxHashSet<Ty<'tcx>>)
|
||||
-> bool {
|
||||
assert!(!self.needs_infer());
|
||||
|
||||
let result = match self.sty {
|
||||
// Fast-path for primitive types
|
||||
ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
|
||||
ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
|
||||
ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
|
||||
|
||||
// Issue #22536: We first query type_moves_by_default. It sees a
|
||||
// normalized version of the type, and therefore will definitely
|
||||
// know whether the type implements Copy (and thus needs no
|
||||
// cleanup/drop/zeroing) ...
|
||||
_ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false,
|
||||
|
||||
// ... (issue #22536 continued) but as an optimization, still use
|
||||
// prior logic of asking for the structural "may drop".
|
||||
|
||||
// FIXME(#22815): Note that this is a conservative heuristic;
|
||||
// it may report that the type "may drop" when actual type does
|
||||
// not actually have a destructor associated with it. But since
|
||||
// the type absolutely did not have the `Copy` bound attached
|
||||
// (see above), it is sound to treat it as having a destructor.
|
||||
|
||||
// User destructors are the only way to have concrete drop types.
|
||||
ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
|
||||
|
||||
// Can refer to a type which may drop.
|
||||
// FIXME(eddyb) check this against a ParameterEnvironment.
|
||||
ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
|
||||
ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
|
||||
|
||||
// Structural recursion.
|
||||
ty::TyArray(ty, _) | ty::TySlice(ty) => {
|
||||
ty.needs_drop_inner(tcx, param_env, stack)
|
||||
}
|
||||
|
||||
ty::TyClosure(def_id, ref substs) => {
|
||||
substs.upvar_tys(def_id, tcx)
|
||||
.any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
|
||||
}
|
||||
|
||||
// unions don't have destructors regardless of the child types
|
||||
ty::TyAdt(def, _) if def.is_union() => false,
|
||||
|
||||
ty::TyAdt(def, substs) => {
|
||||
def.variants.iter().any(|v| {
|
||||
v.fields.iter().any(|f| {
|
||||
f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack)
|
||||
})
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if !self.has_param_types() && !self.has_self_ty() {
|
||||
self.flags.set(self.flags.get() | if result {
|
||||
TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP
|
||||
} else {
|
||||
TypeFlags::NEEDS_DROP_CACHED
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
|
||||
-> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ supported_targets! {
|
|||
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
|
||||
|
||||
("i686-linux-android", i686_linux_android),
|
||||
("x86_64-linux-android", x86_64_linux_android),
|
||||
("arm-linux-androideabi", arm_linux_androideabi),
|
||||
("armv7-linux-androideabi", armv7_linux_androideabi),
|
||||
("aarch64-linux-android", aarch64_linux_android),
|
||||
|
|
|
|||
34
src/librustc_back/target/x86_64_linux_android.rs
Normal file
34
src/librustc_back/target/x86_64_linux_android.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2017 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 LinkerFlavor;
|
||||
use target::{Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::android_base::opts();
|
||||
base.cpu = "x86-64".to_string();
|
||||
// https://developer.android.com/ndk/guides/abis.html#86-64
|
||||
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "x86_64-linux-android".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: "android".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>(
|
|||
let ty = lvalue.ty(mir, tcx).to_ty(tcx);
|
||||
debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty);
|
||||
|
||||
if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) {
|
||||
if ty.needs_drop(tcx, &ctxt.param_env) {
|
||||
each_child(child);
|
||||
} else {
|
||||
debug!("on_all_drop_children_bits - skipping")
|
||||
|
|
|
|||
|
|
@ -263,6 +263,41 @@ impl EmitterWriter {
|
|||
|
||||
draw_col_separator(buffer, line_offset, width_offset - 2);
|
||||
|
||||
// Special case when there's only one annotation involved, it is the start of a multiline
|
||||
// span and there's no text at the beginning of the code line. Instead of doing the whole
|
||||
// graph:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | _^
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_^ test
|
||||
//
|
||||
// we simplify the output to:
|
||||
//
|
||||
// 2 | / fn foo() {
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_^ test
|
||||
if line.annotations.len() == 1 {
|
||||
if let Some(ref ann) = line.annotations.get(0) {
|
||||
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
|
||||
if source_string[0..ann.start_col].trim() == "" {
|
||||
let style = if ann.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::UnderlineSecondary
|
||||
};
|
||||
buffer.putc(line_offset,
|
||||
width_offset + depth - 1,
|
||||
'/',
|
||||
style);
|
||||
return vec![(depth, style)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We want to display like this:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
|
|
@ -355,10 +390,8 @@ impl EmitterWriter {
|
|||
for (i, annotation) in annotations.iter().enumerate() {
|
||||
for (j, next) in annotations.iter().enumerate() {
|
||||
if overlaps(next, annotation, 0) // This label overlaps with another one and both
|
||||
&& !annotation.is_line() // take space (they have text and are not
|
||||
&& !next.is_line() // multiline lines).
|
||||
&& annotation.has_label()
|
||||
&& j > i
|
||||
&& annotation.has_label() // take space (they have text and are not
|
||||
&& j > i // multiline lines).
|
||||
&& p == 0 // We're currently on the first line, move the label one line down
|
||||
{
|
||||
// This annotation needs a new line in the output.
|
||||
|
|
@ -374,7 +407,7 @@ impl EmitterWriter {
|
|||
} else {
|
||||
0
|
||||
};
|
||||
if overlaps(next, annotation, l) // Do not allow two labels to be in the same
|
||||
if (overlaps(next, annotation, l) // Do not allow two labels to be in the same
|
||||
// line if they overlap including padding, to
|
||||
// avoid situations like:
|
||||
//
|
||||
|
|
@ -383,11 +416,18 @@ impl EmitterWriter {
|
|||
// | |
|
||||
// fn_spanx_span
|
||||
//
|
||||
&& !annotation.is_line() // Do not add a new line if this annotation
|
||||
&& !next.is_line() // or the next are vertical line placeholders.
|
||||
&& annotation.has_label() // Both labels must have some text, otherwise
|
||||
&& next.has_label() // they are not overlapping.
|
||||
&& next.has_label()) // they are not overlapping.
|
||||
// Do not add a new line if this annotation
|
||||
// or the next are vertical line placeholders.
|
||||
|| (annotation.takes_space() // If either this or the next annotation is
|
||||
&& next.has_label()) // multiline start/end, move it to a new line
|
||||
|| (annotation.has_label() // so as not to overlap the orizontal lines.
|
||||
&& next.takes_space())
|
||||
|| (annotation.takes_space()
|
||||
&& next.takes_space())
|
||||
{
|
||||
// This annotation needs a new line in the output.
|
||||
p += 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -397,6 +437,7 @@ impl EmitterWriter {
|
|||
line_len = p;
|
||||
}
|
||||
}
|
||||
|
||||
if line_len != 0 {
|
||||
line_len += 1;
|
||||
}
|
||||
|
|
@ -480,7 +521,7 @@ impl EmitterWriter {
|
|||
};
|
||||
let pos = pos + 1;
|
||||
|
||||
if pos > 1 && annotation.has_label() {
|
||||
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
|
||||
for p in line_offset + 1..line_offset + pos + 1 {
|
||||
buffer.putc(p,
|
||||
code_offset + annotation.start_col,
|
||||
|
|
@ -514,12 +555,12 @@ impl EmitterWriter {
|
|||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | __________ starting here...
|
||||
// | __________
|
||||
// | |
|
||||
// | something about `foo`
|
||||
// 3 |
|
||||
// 4 | }
|
||||
// | _ ...ending here: test
|
||||
// | _ test
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
let style = if annotation.is_primary {
|
||||
Style::LabelPrimary
|
||||
|
|
@ -557,12 +598,12 @@ impl EmitterWriter {
|
|||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | ____-_____^ starting here...
|
||||
// | ____-_____^
|
||||
// | |
|
||||
// | something about `foo`
|
||||
// 3 |
|
||||
// 4 | }
|
||||
// | _^ ...ending here: test
|
||||
// | _^ test
|
||||
for &(_, annotation) in &annotations_position {
|
||||
let (underline, style) = if annotation.is_primary {
|
||||
('^', Style::UnderlinePrimary)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl MultilineAnnotation {
|
|||
start_col: self.start_col,
|
||||
end_col: self.start_col + 1,
|
||||
is_primary: self.is_primary,
|
||||
label: Some("starting here...".to_owned()),
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineStart(self.depth)
|
||||
}
|
||||
}
|
||||
|
|
@ -73,10 +73,7 @@ impl MultilineAnnotation {
|
|||
start_col: self.end_col - 1,
|
||||
end_col: self.end_col,
|
||||
is_primary: self.is_primary,
|
||||
label: match self.label {
|
||||
Some(ref label) => Some(format!("...ending here: {}", label)),
|
||||
None => Some("...ending here".to_owned()),
|
||||
},
|
||||
label: self.label.clone(),
|
||||
annotation_type: AnnotationType::MultilineEnd(self.depth)
|
||||
}
|
||||
}
|
||||
|
|
@ -106,9 +103,9 @@ pub enum AnnotationType {
|
|||
// Each of these corresponds to one part of the following diagram:
|
||||
//
|
||||
// x | foo(1 + bar(x,
|
||||
// | _________^ starting here... < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ ...ending here: label < MultilineEnd
|
||||
// | _________^ < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ label < MultilineEnd
|
||||
// x | z);
|
||||
/// Annotation marking the first character of a fully shown multiline span
|
||||
MultilineStart(usize),
|
||||
|
|
@ -189,6 +186,15 @@ impl Annotation {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn takes_space(&self) -> bool {
|
||||
// Multiline annotations always have to keep vertical space.
|
||||
match self.annotation_type {
|
||||
AnnotationType::MultilineStart(_) |
|
||||
AnnotationType::MultilineEnd(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
|
|||
let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
|
||||
for field in vdata.fields() {
|
||||
let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id));
|
||||
if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
|
||||
if field_ty.needs_drop(ctx.tcx, param_env) {
|
||||
ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
|
||||
field.span,
|
||||
"union contains a field with possibly non-trivial drop code, \
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
type with inference types/regions",
|
||||
ty);
|
||||
});
|
||||
self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment)
|
||||
ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment)
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
// a regular goto.
|
||||
let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
|
||||
let ty = ty.to_ty(tcx);
|
||||
if tcx.type_needs_drop_given_env(ty, ¶m_env) {
|
||||
if ty.needs_drop(tcx, ¶m_env) {
|
||||
cost += CALL_PENALTY;
|
||||
if let Some(unwind) = unwind {
|
||||
work_list.push(unwind);
|
||||
|
|
|
|||
|
|
@ -80,10 +80,10 @@ impl<'a, 'tcx> Qualif {
|
|||
fn restrict(&mut self, ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>) {
|
||||
if !ty.type_contents(tcx).interior_unsafe() {
|
||||
if ty.is_freeze(tcx, param_env, DUMMY_SP) {
|
||||
*self = *self - Qualif::MUTABLE_INTERIOR;
|
||||
}
|
||||
if !tcx.type_needs_drop_given_env(ty, param_env) {
|
||||
if !ty.needs_drop(tcx, param_env) {
|
||||
*self = *self - Qualif::NEEDS_DROP;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,8 +277,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
|
||||
let mut fields = fields;
|
||||
fields.retain(|&(ref lvalue, _)| {
|
||||
self.tcx().type_needs_drop_given_env(
|
||||
self.lvalue_ty(lvalue), self.elaborator.param_env())
|
||||
self.lvalue_ty(lvalue).needs_drop(self.tcx(), self.elaborator.param_env())
|
||||
});
|
||||
|
||||
debug!("drop_ladder - fields needing drop: {:?}", fields);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ use rustc::lint::builtin::CONST_ERR;
|
|||
|
||||
use rustc::hir::{self, PatKind, RangeEnd};
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
|
|
@ -85,11 +85,11 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
|||
|
||||
// Adds the worst effect out of all the values of one type.
|
||||
fn add_type(&mut self, ty: Ty<'gcx>) {
|
||||
if ty.type_contents(self.tcx).interior_unsafe() {
|
||||
if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) {
|
||||
self.promotable = false;
|
||||
}
|
||||
|
||||
if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
|
||||
if ty.needs_drop(self.tcx, &self.param_env) {
|
||||
self.promotable = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
// bitcasting to the struct type yields invalid cast errors.
|
||||
|
||||
// We instead thus allocate some scratch space...
|
||||
let llscratch = bcx.alloca(ty, "abi_cast");
|
||||
let llscratch = bcx.alloca(ty, "abi_cast", None);
|
||||
base::Lifetime::Start.call(bcx, llscratch);
|
||||
|
||||
// ...where we first store the value...
|
||||
|
|
@ -746,13 +746,13 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
|
||||
// both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
|
||||
// on memory dependencies rather than pointer equality
|
||||
let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
|
||||
let is_freeze = ccx.shared().type_is_freeze(mt.ty);
|
||||
|
||||
if mt.mutbl != hir::MutMutable && !interior_unsafe {
|
||||
if mt.mutbl != hir::MutMutable && is_freeze {
|
||||
arg.attrs.set(ArgAttribute::NoAlias);
|
||||
}
|
||||
|
||||
if mt.mutbl == hir::MutImmutable && !interior_unsafe {
|
||||
if mt.mutbl == hir::MutImmutable && is_freeze {
|
||||
arg.attrs.set(ArgAttribute::ReadOnly);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,12 +90,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
|||
/// and fill in the actual contents in a second pass to prevent
|
||||
/// unbounded recursion; see also the comments in `trans::type_of`.
|
||||
pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
||||
generic_type_of(cx, t, None, false, false)
|
||||
generic_type_of(cx, t, None)
|
||||
}
|
||||
|
||||
pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
t: Ty<'tcx>, name: &str) -> Type {
|
||||
generic_type_of(cx, t, Some(name), false, false)
|
||||
generic_type_of(cx, t, Some(name))
|
||||
}
|
||||
|
||||
pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
|
@ -114,7 +114,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
_ => unreachable!()
|
||||
};
|
||||
let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
|
||||
llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
|
||||
llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant),
|
||||
packed)
|
||||
},
|
||||
_ => bug!("This function cannot handle {} with layout {:#?}", t, l)
|
||||
|
|
@ -123,12 +123,9 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
name: Option<&str>,
|
||||
sizing: bool,
|
||||
dst: bool) -> Type {
|
||||
name: Option<&str>) -> Type {
|
||||
let l = cx.layout_of(t);
|
||||
debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {} dst: {}",
|
||||
t, name, sizing, dst);
|
||||
debug!("adt::generic_type_of t: {:?} name: {:?}", t, name);
|
||||
match *l {
|
||||
layout::CEnum { discr, .. } => Type::from_integer(cx, discr),
|
||||
layout::RawNullablePointer { nndiscr, .. } => {
|
||||
|
|
@ -148,11 +145,10 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let fields = compute_fields(cx, t, nndiscr as usize, false);
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
|
||||
Type::struct_(cx, &struct_llfields(cx, &fields, nonnull),
|
||||
nonnull.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
assert_eq!(sizing, false);
|
||||
Type::named_struct(cx, name)
|
||||
}
|
||||
}
|
||||
|
|
@ -163,13 +159,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let fields = compute_fields(cx, t, 0, true);
|
||||
match name {
|
||||
None => {
|
||||
let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
|
||||
let fields = struct_llfields(cx, &fields, &variant);
|
||||
Type::struct_(cx, &fields, variant.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
// Hypothesis: named_struct's can never need a
|
||||
// drop flag. (... needs validation.)
|
||||
assert_eq!(sizing, false);
|
||||
Type::named_struct(cx, name)
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +185,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
}
|
||||
layout::General { discr, size, align, .. } => {
|
||||
layout::General { discr, size, align, primitive_align, .. } => {
|
||||
// We need a representation that has:
|
||||
// * The alignment of the most-aligned field
|
||||
// * The size of the largest variant (rounded up to that alignment)
|
||||
|
|
@ -203,14 +198,15 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
// of the size.
|
||||
let size = size.bytes();
|
||||
let align = align.abi();
|
||||
let primitive_align = primitive_align.abi();
|
||||
assert!(align <= std::u32::MAX as u64);
|
||||
let discr_ty = Type::from_integer(cx, discr);
|
||||
let discr_size = discr.size().bytes();
|
||||
let padded_discr_size = roundup(discr_size, align as u32);
|
||||
let variant_part_size = size-padded_discr_size;
|
||||
let variant_fill = union_fill(cx, variant_part_size, align);
|
||||
let variant_fill = union_fill(cx, variant_part_size, primitive_align);
|
||||
|
||||
assert_eq!(machine::llalign_of_min(cx, variant_fill), align as u32);
|
||||
assert_eq!(machine::llalign_of_min(cx, variant_fill), primitive_align as u32);
|
||||
assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
|
||||
let fields: Vec<Type> =
|
||||
[discr_ty,
|
||||
|
|
@ -245,15 +241,60 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
|
|||
}
|
||||
|
||||
|
||||
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
|
||||
variant: &layout::Struct,
|
||||
sizing: bool, _dst: bool) -> Vec<Type> {
|
||||
let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
|
||||
if sizing {
|
||||
bug!()
|
||||
} else {
|
||||
fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
|
||||
// Double index to account for padding (FieldPath already uses `Struct::memory_index`)
|
||||
fn struct_llfields_path(discrfield: &layout::FieldPath) -> Vec<usize> {
|
||||
discrfield.iter().map(|&i| (i as usize) << 1).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
|
||||
// Lookup `Struct::memory_index` and double it to account for padding
|
||||
pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize {
|
||||
(variant.memory_index[index] as usize) << 1
|
||||
}
|
||||
|
||||
|
||||
pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, field_tys: &Vec<Ty<'tcx>>,
|
||||
variant: &layout::Struct) -> Vec<Type> {
|
||||
debug!("struct_llfields: variant: {:?}", variant);
|
||||
let mut first_field = true;
|
||||
let mut min_offset = 0;
|
||||
let mut result: Vec<Type> = Vec::with_capacity(field_tys.len() * 2);
|
||||
let field_iter = variant.field_index_by_increasing_offset().map(|i| {
|
||||
(i, field_tys[i as usize], variant.offsets[i as usize].bytes()) });
|
||||
for (index, ty, target_offset) in field_iter {
|
||||
if first_field {
|
||||
debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}",
|
||||
index, ty, min_offset, target_offset);
|
||||
first_field = false;
|
||||
} else {
|
||||
assert!(target_offset >= min_offset);
|
||||
let padding_bytes = if variant.packed { 0 } else { target_offset - min_offset };
|
||||
result.push(Type::array(&Type::i8(cx), padding_bytes));
|
||||
debug!("struct_llfields: {} ty: {} pad_bytes: {} min_offset: {} target_offset: {}",
|
||||
index, ty, padding_bytes, min_offset, target_offset);
|
||||
}
|
||||
let llty = type_of::in_memory_type_of(cx, ty);
|
||||
result.push(llty);
|
||||
let layout = cx.layout_of(ty);
|
||||
let target_size = layout.size(&cx.tcx().data_layout).bytes();
|
||||
min_offset = target_offset + target_size;
|
||||
}
|
||||
if variant.sized && !field_tys.is_empty() {
|
||||
if variant.stride().bytes() < min_offset {
|
||||
bug!("variant: {:?} stride: {} min_offset: {}", variant, variant.stride().bytes(),
|
||||
min_offset);
|
||||
}
|
||||
let padding_bytes = variant.stride().bytes() - min_offset;
|
||||
debug!("struct_llfields: pad_bytes: {} min_offset: {} min_size: {} stride: {}\n",
|
||||
padding_bytes, min_offset, variant.min_size.bytes(), variant.stride().bytes());
|
||||
result.push(Type::array(&Type::i8(cx), padding_bytes));
|
||||
assert!(result.len() == (field_tys.len() * 2));
|
||||
} else {
|
||||
debug!("struct_llfields: min_offset: {} min_size: {} stride: {}\n",
|
||||
min_offset, variant.min_size.bytes(), variant.stride().bytes());
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
|
||||
|
|
@ -309,8 +350,8 @@ fn struct_wrapped_nullable_bitdiscr(
|
|||
scrutinee: ValueRef,
|
||||
alignment: Alignment,
|
||||
) -> ValueRef {
|
||||
let llptrptr = bcx.gepi(scrutinee,
|
||||
&discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>());
|
||||
let path = struct_llfields_path(discrfield);
|
||||
let llptrptr = bcx.gepi(scrutinee, &path);
|
||||
let llptr = bcx.load(llptrptr, alignment.to_align());
|
||||
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
|
||||
bcx.icmp(cmp, llptr, C_null(val_ty(llptr)))
|
||||
|
|
@ -380,7 +421,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
|
|||
let align = C_i32(bcx.ccx, nonnull.align.abi() as i32);
|
||||
base::call_memset(bcx, llptr, fill_byte, size, align, false);
|
||||
} else {
|
||||
let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
|
||||
let path = struct_llfields_path(discrfield);
|
||||
let llptrptr = bcx.gepi(val, &path);
|
||||
let llptrty = val_ty(llptrptr).element_type();
|
||||
bcx.store(C_null(llptrty), llptrptr, None);
|
||||
|
|
|
|||
|
|
@ -477,24 +477,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
|
||||
pub fn alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
|
||||
let builder = Builder::with_ccx(self.ccx);
|
||||
builder.position_at_start(unsafe {
|
||||
llvm::LLVMGetFirstBasicBlock(self.llfn())
|
||||
});
|
||||
builder.dynamic_alloca(ty, name)
|
||||
builder.dynamic_alloca(ty, name, align)
|
||||
}
|
||||
|
||||
pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
|
||||
pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
|
||||
self.count_insn("alloca");
|
||||
unsafe {
|
||||
if name.is_empty() {
|
||||
let alloca = if name.is_empty() {
|
||||
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
|
||||
} else {
|
||||
let name = CString::new(name).unwrap();
|
||||
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
|
||||
name.as_ptr())
|
||||
};
|
||||
if let Some(align) = align {
|
||||
llvm::LLVMSetAlignment(alloca, align as c_uint);
|
||||
}
|
||||
alloca
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,8 +261,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// As an optimization, all shared statics which do not have interior
|
||||
// mutability are placed into read-only memory.
|
||||
if m != hir::MutMutable {
|
||||
let tcontents = ty.type_contents(ccx.tcx());
|
||||
if !tcontents.interior_unsafe() {
|
||||
if ccx.shared().type_is_freeze(ty) {
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,13 +392,17 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env)
|
||||
ty.needs_drop(self.tcx, &self.empty_param_env)
|
||||
}
|
||||
|
||||
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
|
||||
&self.exported_symbols
|
||||
}
|
||||
|
|
|
|||
|
|
@ -778,7 +778,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
//
|
||||
// More information can be found in libstd's seh.rs implementation.
|
||||
let i64p = Type::i64(ccx).ptr_to();
|
||||
let slot = bcx.alloca(i64p, "slot");
|
||||
let slot = bcx.alloca(i64p, "slot", None);
|
||||
bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
|
||||
None);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc::ty::{self, TypeFoldable};
|
|||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use rustc::mir;
|
||||
use abi::{Abi, FnType, ArgType};
|
||||
use adt;
|
||||
use base::{self, Lifetime};
|
||||
use callee;
|
||||
use builder::Builder;
|
||||
|
|
@ -177,7 +178,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
};
|
||||
let llslot = match op.val {
|
||||
Immediate(_) | Pair(..) => {
|
||||
let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret");
|
||||
let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret", None);
|
||||
self.store_operand(&bcx, llscratch, None, op);
|
||||
llscratch
|
||||
}
|
||||
|
|
@ -630,7 +631,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let (mut llval, align, by_ref) = match op.val {
|
||||
Immediate(_) | Pair(..) => {
|
||||
if arg.is_indirect() || arg.cast.is_some() {
|
||||
let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
|
||||
let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None);
|
||||
self.store_operand(bcx, llscratch, None, op);
|
||||
(llscratch, Alignment::AbiAligned, true)
|
||||
} else {
|
||||
|
|
@ -642,7 +643,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
// think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
|
||||
// have scary latent bugs around.
|
||||
|
||||
let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg");
|
||||
let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None);
|
||||
base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
|
||||
(llscratch, Alignment::AbiAligned, true)
|
||||
}
|
||||
|
|
@ -711,7 +712,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
bug!("Not a tuple.");
|
||||
};
|
||||
for (n, &ty) in arg_types.iter().enumerate() {
|
||||
let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize);
|
||||
let mut elem = bcx.extract_value(
|
||||
llval, adt::struct_llfields_index(v, n));
|
||||
// Truncate bools to i1, if needed
|
||||
if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) {
|
||||
elem = bcx.trunc(elem, Type::i1(bcx.ccx));
|
||||
|
|
@ -750,7 +752,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
slot
|
||||
} else {
|
||||
let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
|
||||
let slot = bcx.alloca(llretty, "personalityslot");
|
||||
let slot = bcx.alloca(llretty, "personalityslot", None);
|
||||
self.llpersonalityslot = Some(slot);
|
||||
slot
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
|
||||
pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> {
|
||||
debug!("alloca({:?}: {:?})", name, ty);
|
||||
let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name);
|
||||
let tmp = bcx.alloca(
|
||||
type_of::type_of(bcx.ccx, ty), name, bcx.ccx.over_align_of(ty));
|
||||
assert!(!ty.has_param_types());
|
||||
Self::new_sized_ty(tmp, ty, Alignment::AbiAligned)
|
||||
}
|
||||
|
|
@ -131,11 +132,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
|
||||
let alignment = self.alignment | Alignment::from_packed(st.packed);
|
||||
|
||||
let llfields = adt::struct_llfields(ccx, fields, st);
|
||||
let ptr_val = if needs_cast {
|
||||
let fields = st.field_index_by_increasing_offset().map(|i| {
|
||||
type_of::in_memory_type_of(ccx, fields[i])
|
||||
}).collect::<Vec<_>>();
|
||||
let real_ty = Type::struct_(ccx, &fields[..], st.packed);
|
||||
let real_ty = Type::struct_(ccx, &llfields[..], st.packed);
|
||||
bcx.pointercast(self.llval, real_ty.ptr_to())
|
||||
} else {
|
||||
self.llval
|
||||
|
|
@ -147,14 +146,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
// * Field is sized - pointer is properly aligned already
|
||||
if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
|
||||
bcx.ccx.shared().type_is_sized(fty) {
|
||||
return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
|
||||
return (bcx.struct_gep(
|
||||
ptr_val, adt::struct_llfields_index(st, ix)), alignment);
|
||||
}
|
||||
|
||||
// If the type of the last field is [T] or str, then we don't need to do
|
||||
// any adjusments
|
||||
match fty.sty {
|
||||
ty::TySlice(..) | ty::TyStr => {
|
||||
return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment);
|
||||
return (bcx.struct_gep(
|
||||
ptr_val, adt::struct_llfields_index(st, ix)), alignment);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
|
@ -163,7 +164,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
if !self.has_extra() {
|
||||
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
|
||||
ix, Value(ptr_val));
|
||||
return (bcx.struct_gep(ptr_val, ix), alignment);
|
||||
return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment);
|
||||
}
|
||||
|
||||
// We need to get the pointer manually now.
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
// doesn't actually strip the offset when splitting the closure
|
||||
// environment into its components so it ends up out of bounds.
|
||||
let env_ptr = if !env_ref {
|
||||
let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr");
|
||||
let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr", None);
|
||||
bcx.store(llval, alloc, None);
|
||||
alloc
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc::mir;
|
|||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use adt;
|
||||
use base;
|
||||
use common::{self, CrateContext, C_null};
|
||||
use builder::Builder;
|
||||
|
|
@ -134,6 +135,12 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
|||
if common::val_ty(elem) == Type::i1(bcx.ccx) {
|
||||
elem = bcx.zext(elem, Type::i8(bcx.ccx));
|
||||
}
|
||||
let layout = bcx.ccx.layout_of(self.ty);
|
||||
let i = if let Layout::Univariant { ref variant, .. } = *layout {
|
||||
adt::struct_llfields_index(variant, i)
|
||||
} else {
|
||||
i
|
||||
};
|
||||
llpair = bcx.insert_value(llpair, elem, i);
|
||||
}
|
||||
self.val = OperandValue::Immediate(llpair);
|
||||
|
|
@ -183,14 +190,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let (lldata, llextra) = base::load_fat_ptr(bcx, llval, align, ty);
|
||||
OperandValue::Pair(lldata, llextra)
|
||||
} else if common::type_is_imm_pair(bcx.ccx, ty) {
|
||||
let f_align = match *bcx.ccx.layout_of(ty) {
|
||||
Layout::Univariant { ref variant, .. } =>
|
||||
Alignment::from_packed(variant.packed) | align,
|
||||
_ => align
|
||||
let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(ty) {
|
||||
Layout::Univariant { ref variant, .. } => {
|
||||
(adt::struct_llfields_index(variant, 0),
|
||||
adt::struct_llfields_index(variant, 1),
|
||||
Alignment::from_packed(variant.packed) | align)
|
||||
},
|
||||
_ => (0, 1, align)
|
||||
};
|
||||
let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap();
|
||||
let a_ptr = bcx.struct_gep(llval, 0);
|
||||
let b_ptr = bcx.struct_gep(llval, 1);
|
||||
let a_ptr = bcx.struct_gep(llval, ix0);
|
||||
let b_ptr = bcx.struct_gep(llval, ix1);
|
||||
|
||||
OperandValue::Pair(
|
||||
base::load_ty(bcx, a_ptr, f_align, a_ty),
|
||||
|
|
@ -302,17 +312,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
bcx.store(base::from_immediate(bcx, s), lldest, align);
|
||||
}
|
||||
OperandValue::Pair(a, b) => {
|
||||
let f_align = match *bcx.ccx.layout_of(operand.ty) {
|
||||
Layout::Univariant { ref variant, .. } if variant.packed => {
|
||||
Some(1)
|
||||
let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(operand.ty) {
|
||||
Layout::Univariant { ref variant, .. } => {
|
||||
(adt::struct_llfields_index(variant, 0),
|
||||
adt::struct_llfields_index(variant, 1),
|
||||
if variant.packed { Some(1) } else { None })
|
||||
}
|
||||
_ => align
|
||||
_ => (0, 1, align)
|
||||
};
|
||||
|
||||
let a = base::from_immediate(bcx, a);
|
||||
let b = base::from_immediate(bcx, b);
|
||||
bcx.store(a, bcx.struct_gep(lldest, 0), f_align);
|
||||
bcx.store(b, bcx.struct_gep(lldest, 1), f_align);
|
||||
bcx.store(a, bcx.struct_gep(lldest, ix0), f_align);
|
||||
bcx.store(b, bcx.struct_gep(lldest, ix1), f_align);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,10 +130,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
_ => {
|
||||
// If this is a tuple or closure, we need to translate GEP indices.
|
||||
let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx()));
|
||||
let translation = if let Layout::Univariant { ref variant, .. } = *layout {
|
||||
Some(&variant.memory_index)
|
||||
} else {
|
||||
None
|
||||
let get_memory_index = |i| {
|
||||
if let Layout::Univariant { ref variant, .. } = *layout {
|
||||
adt::struct_llfields_index(variant, i)
|
||||
} else {
|
||||
i
|
||||
}
|
||||
};
|
||||
let alignment = dest.alignment;
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
|
|
@ -143,11 +145,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
// Note: perhaps this should be StructGep, but
|
||||
// note that in some cases the values here will
|
||||
// not be structs but arrays.
|
||||
let i = if let Some(ref t) = translation {
|
||||
t[i] as usize
|
||||
} else {
|
||||
i
|
||||
};
|
||||
let i = get_memory_index(i);
|
||||
let dest = bcx.gepi(dest.llval, &[0, i]);
|
||||
self.store_operand(&bcx, dest, alignment.to_align(), op);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,16 @@ impl<'a, 'tcx> CrateContext<'a, 'tcx> {
|
|||
pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
|
||||
self.layout_of(ty).size(self).bytes() as machine::llsize
|
||||
}
|
||||
|
||||
pub fn over_align_of(&self, t: Ty<'tcx>)
|
||||
-> Option<machine::llalign> {
|
||||
let layout = self.layout_of(t);
|
||||
if let Some(align) = layout.over_align(&self.tcx().data_layout) {
|
||||
Some(align as machine::llalign)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ use errors::DiagnosticBuilder;
|
|||
use syntax::abi;
|
||||
use syntax::feature_gate;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::Deref;
|
||||
|
|
@ -722,6 +723,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
Ok(target)
|
||||
}
|
||||
|
||||
/// Same as `try_coerce()`, but without side-effects.
|
||||
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
||||
let source = self.resolve_type_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::can({:?} -> {:?})", source, target);
|
||||
|
||||
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
|
||||
}
|
||||
|
||||
/// Given some expressions, their known unified type and another expression,
|
||||
/// tries to unify the types, potentially inserting coercions on any of the
|
||||
/// provided expressions and returns their LUB (aka "common supertype").
|
||||
|
|
|
|||
|
|
@ -10,15 +10,14 @@
|
|||
|
||||
|
||||
use check::FnCtxt;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::infer::{InferOk};
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits::ObligationCause;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::{self, Span};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::ty::{self, AssociatedItem};
|
||||
use rustc::ty::{self, Ty, AssociatedItem};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
use super::method::probe;
|
||||
|
|
@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
|
||||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
||||
let mode = probe::Mode::MethodCall;
|
||||
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
|
||||
mode,
|
||||
expected,
|
||||
checked_ty,
|
||||
ast::DUMMY_NODE_ID);
|
||||
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
|
||||
if suggestions.len() > 0 {
|
||||
err.help(&format!("here are some functions which \
|
||||
might fulfill your needs:\n{}",
|
||||
self.get_best_match(&suggestions).join("\n")));
|
||||
};
|
||||
if let Some(suggestion) = self.check_ref(expr,
|
||||
checked_ty,
|
||||
expected) {
|
||||
err.help(&suggestion);
|
||||
} else {
|
||||
let mode = probe::Mode::MethodCall;
|
||||
let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
|
||||
mode,
|
||||
expected,
|
||||
checked_ty,
|
||||
ast::DUMMY_NODE_ID);
|
||||
if suggestions.len() > 0 {
|
||||
err.help(&format!("here are some functions which \
|
||||
might fulfill your needs:\n{}",
|
||||
self.get_best_match(&suggestions).join("\n")));
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
|
@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is used to determine potential "simple" improvements or users' errors and
|
||||
/// provide them useful help. For example:
|
||||
///
|
||||
/// ```
|
||||
/// fn some_fn(s: &str) {}
|
||||
///
|
||||
/// let x = "hey!".to_owned();
|
||||
/// some_fn(x); // error
|
||||
/// ```
|
||||
///
|
||||
/// No need to find every potential function which could make a coercion to transform a
|
||||
/// `String` into a `&str` since a `&` would do the trick!
|
||||
///
|
||||
/// In addition of this check, it also checks between references mutability state. If the
|
||||
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
|
||||
/// `&mut`!".
|
||||
fn check_ref(&self,
|
||||
expr: &hir::Expr,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>)
|
||||
-> Option<String> {
|
||||
match (&expected.sty, &checked_ty.sty) {
|
||||
(&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
|
||||
(&ty::TyRef(_, mutability), _) => {
|
||||
// Check if it can work when put into a ref. For example:
|
||||
//
|
||||
// ```
|
||||
// fn bar(x: &mut i32) {}
|
||||
//
|
||||
// let x = 0u32;
|
||||
// bar(&x); // error, expected &mut
|
||||
// ```
|
||||
let ref_ty = match mutability.mutbl {
|
||||
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
|
||||
self.tcx.mk_region(ty::ReStatic),
|
||||
checked_ty),
|
||||
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
|
||||
self.tcx.mk_region(ty::ReStatic),
|
||||
checked_ty),
|
||||
};
|
||||
if self.can_coerce(ref_ty, expected) {
|
||||
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
|
||||
return Some(format!("try with `{}{}`",
|
||||
match mutability.mutbl {
|
||||
hir::Mutability::MutMutable => "&mut ",
|
||||
hir::Mutability::MutImmutable => "&",
|
||||
},
|
||||
&src));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -953,6 +953,12 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
if def.repr.simd() {
|
||||
check_simd(tcx, span, def_id);
|
||||
}
|
||||
|
||||
// if struct is packed and not aligned, check fields for alignment.
|
||||
// Checks for combining packed and align attrs on single struct are done elsewhere.
|
||||
if tcx.lookup_adt_def(def_id).repr.packed() && tcx.lookup_adt_def(def_id).repr.align == 0 {
|
||||
check_packed(tcx, span, def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
|
@ -1371,6 +1377,47 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
|
|||
}
|
||||
}
|
||||
|
||||
fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
|
||||
if check_packed_inner(tcx, def_id, &mut Vec::new()) {
|
||||
struct_span_err!(tcx.sess, sp, E0588,
|
||||
"packed struct cannot transitively contain a `[repr(align)]` struct").emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
stack: &mut Vec<DefId>) -> bool {
|
||||
let t = tcx.item_type(def_id);
|
||||
if stack.contains(&def_id) {
|
||||
debug!("check_packed_inner: {:?} is recursive", t);
|
||||
return false;
|
||||
}
|
||||
match t.sty {
|
||||
ty::TyAdt(def, substs) if def.is_struct() => {
|
||||
if tcx.lookup_adt_def(def.did).repr.align > 0 {
|
||||
return true;
|
||||
}
|
||||
// push struct def_id before checking fields
|
||||
stack.push(def_id);
|
||||
for field in &def.struct_variant().fields {
|
||||
let f = field.ty(tcx, substs);
|
||||
match f.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
if check_packed_inner(tcx, def.did, stack) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
// only need to pop if not early out
|
||||
stack.pop();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
sp: Span,
|
||||
|
|
|
|||
|
|
@ -4168,5 +4168,6 @@ register_diagnostics! {
|
|||
// but `{}` was found in the type `{}`
|
||||
E0567, // auto traits can not have type parameters
|
||||
E0568, // auto-traits can not have predicates,
|
||||
E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
|
||||
E0592, // duplicate definitions with name `{}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
|
|||
text: *const hoedown_buffer,
|
||||
lang: *const hoedown_buffer,
|
||||
data: *const hoedown_renderer_data,
|
||||
line: libc::size_t) {
|
||||
_line: libc::size_t) {
|
||||
unsafe {
|
||||
if text.is_null() { return }
|
||||
let block_info = if lang.is_null() {
|
||||
|
|
@ -503,11 +503,15 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
|
|||
LangString::parse(s)
|
||||
};
|
||||
if !block_info.rust { return }
|
||||
let text = (*text).as_bytes();
|
||||
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
|
||||
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
|
||||
let line = tests.get_line() + line;
|
||||
let text = str::from_utf8(text).unwrap();
|
||||
let lines = text.lines().map(|l| {
|
||||
stripped_filtered_line(l).unwrap_or(l)
|
||||
});
|
||||
let filename = tests.get_filename();
|
||||
tests.add_old_test(line, filename);
|
||||
tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(test)]
|
||||
#![feature(unicode)]
|
||||
#![feature(vec_remove_item)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate getopts;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::io::prelude::*;
|
||||
|
|
@ -381,7 +382,7 @@ fn partition_source(s: &str) -> (String, String) {
|
|||
pub struct Collector {
|
||||
pub tests: Vec<testing::TestDescAndFn>,
|
||||
// to be removed when hoedown will be definitely gone
|
||||
pub old_tests: Vec<String>,
|
||||
pub old_tests: HashMap<String, Vec<String>>,
|
||||
names: Vec<String>,
|
||||
cfgs: Vec<String>,
|
||||
libs: SearchPaths,
|
||||
|
|
@ -403,7 +404,7 @@ impl Collector {
|
|||
codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
|
||||
Collector {
|
||||
tests: Vec::new(),
|
||||
old_tests: Vec::new(),
|
||||
old_tests: HashMap::new(),
|
||||
names: Vec::new(),
|
||||
cfgs: cfgs,
|
||||
libs: libs,
|
||||
|
|
@ -432,9 +433,24 @@ impl Collector {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_old_test(&mut self, line: usize, filename: String) {
|
||||
let name = self.generate_name(line, &filename);
|
||||
self.old_tests.push(name);
|
||||
// to be removed once hoedown is gone
|
||||
fn generate_name_beginning(&self, filename: &str) -> String {
|
||||
if self.use_headers {
|
||||
if let Some(ref header) = self.current_header {
|
||||
format!("{} - {} (line", filename, header)
|
||||
} else {
|
||||
format!("{} - (line", filename)
|
||||
}
|
||||
} else {
|
||||
format!("{} - {} (line", filename, self.names.join("::"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_old_test(&mut self, test: String, filename: String) {
|
||||
let name_beg = self.generate_name_beginning(&filename);
|
||||
let entry = self.old_tests.entry(name_beg)
|
||||
.or_insert(Vec::new());
|
||||
entry.push(test.trim().to_owned());
|
||||
}
|
||||
|
||||
pub fn add_test(&mut self, test: String,
|
||||
|
|
@ -442,7 +458,14 @@ impl Collector {
|
|||
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
|
||||
line: usize, filename: String) {
|
||||
let name = self.generate_name(line, &filename);
|
||||
if self.old_tests.iter().find(|&x| x == &name).is_none() {
|
||||
let name_beg = self.generate_name_beginning(&filename);
|
||||
let mut found = false;
|
||||
// to be removed when hoedown is removed
|
||||
let test = test.trim().to_owned();
|
||||
if let Some(entry) = self.old_tests.get_mut(&name_beg) {
|
||||
found = entry.remove_item(&test).is_some();
|
||||
}
|
||||
if !found {
|
||||
let _ = writeln!(&mut io::stderr(),
|
||||
"WARNING: {} Code block is not currently run as a test, but will in \
|
||||
future versions of rustdoc. Please ensure this code block is a \
|
||||
|
|
|
|||
|
|
@ -165,3 +165,66 @@ mod arch {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod arch {
|
||||
use os::raw::{c_uint, c_long, c_ulong};
|
||||
use os::unix::raw::{uid_t, gid_t};
|
||||
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type dev_t = u64;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type mode_t = u32;
|
||||
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type blkcnt_t = u64;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type blksize_t = u64;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type ino_t = u64;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type nlink_t = u32;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type off_t = u64;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type time_t = i64;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub struct stat {
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_dev: dev_t,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_ino: ino_t,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_nlink: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_mode: c_uint,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_uid: uid_t,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_gid: gid_t,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_rdev: dev_t,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_size: i64,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_blksize: c_long,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_blocks: c_long,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_atime: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_atime_nsec: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_mtime: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_mtime_nsec: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_ctime: c_ulong,
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub st_ctime_nsec: c_ulong,
|
||||
__unused: [c_long; 3],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1189,8 +1189,13 @@ impl PathBuf {
|
|||
/// If [`self.file_name`] was [`None`], this is equivalent to pushing
|
||||
/// `file_name`.
|
||||
///
|
||||
/// Otherwise it is equivalent to calling [`pop`] and then pushing
|
||||
/// `file_name`. The new path will be a sibling of the original path.
|
||||
/// (That is, it will have the same parent.)
|
||||
///
|
||||
/// [`self.file_name`]: struct.PathBuf.html#method.file_name
|
||||
/// [`None`]: ../../std/option/enum.Option.html#variant.None
|
||||
/// [`pop`]: struct.PathBuf.html#method.pop
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1725,7 +1730,10 @@ impl Path {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns the final component of the `Path`, if it is a normal file.
|
||||
/// Returns the final component of the `Path`, if there is one.
|
||||
///
|
||||
/// If the path is a normal file, this is the file name. If it's the path of a directory, this
|
||||
/// is the directory name.
|
||||
///
|
||||
/// Returns [`None`] If the path terminates in `..`.
|
||||
///
|
||||
|
|
@ -1737,10 +1745,12 @@ impl Path {
|
|||
/// use std::path::Path;
|
||||
/// use std::ffi::OsStr;
|
||||
///
|
||||
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name());
|
||||
/// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
|
||||
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
|
||||
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
|
||||
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
|
||||
/// assert_eq!(None, Path::new("foo.txt/..").file_name());
|
||||
/// assert_eq!(None, Path::new("/").file_name());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn file_name(&self) -> Option<&OsStr> {
|
||||
|
|
@ -1926,6 +1936,9 @@ impl Path {
|
|||
///
|
||||
/// let path = Path::new("/tmp/foo.txt");
|
||||
/// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
|
||||
///
|
||||
/// let path = Path::new("/tmp");
|
||||
/// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
|
||||
|
|
|
|||
|
|
@ -73,6 +73,15 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
|||
/// spawning process and can itself be constructed using a builder-style
|
||||
/// interface.
|
||||
///
|
||||
/// There is no implementation of [`Drop`] for child processes,
|
||||
/// so if you do not ensure the `Child` has exited then it will continue to
|
||||
/// run, even after the `Child` handle to the child process has gone out of
|
||||
/// scope.
|
||||
///
|
||||
/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make
|
||||
/// the parent process wait until the child has actually exited before
|
||||
/// continuing.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```should_panic
|
||||
|
|
@ -89,17 +98,6 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
|||
/// assert!(ecode.success());
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Take note that there is no implementation of [`Drop`] for child processes,
|
||||
/// so if you do not ensure the `Child` has exited then it will continue to
|
||||
/// run, even after the `Child` handle to the child process has gone out of
|
||||
/// scope.
|
||||
///
|
||||
/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make
|
||||
/// the parent process wait until the child has actually exited before
|
||||
/// continuing.
|
||||
///
|
||||
/// [`Command`]: struct.Command.html
|
||||
/// [`Drop`]: ../../core/ops/trait.Drop.html
|
||||
/// [`wait`]: #method.wait
|
||||
|
|
|
|||
|
|
@ -147,6 +147,24 @@ impl NestedMetaItem {
|
|||
self.meta_item().and_then(|meta_item| meta_item.value_str())
|
||||
}
|
||||
|
||||
/// Returns a name and single literal value tuple of the MetaItem.
|
||||
pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
|
||||
self.meta_item().and_then(
|
||||
|meta_item| meta_item.meta_item_list().and_then(
|
||||
|meta_item_list| {
|
||||
if meta_item_list.len() == 1 {
|
||||
let nested_item = &meta_item_list[0];
|
||||
if nested_item.is_literal() {
|
||||
Some((meta_item.name(), nested_item.literal().unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
else {
|
||||
None
|
||||
}}))
|
||||
}
|
||||
|
||||
/// Returns a MetaItem if self is a MetaItem with Kind Word.
|
||||
pub fn word(&self) -> Option<&MetaItem> {
|
||||
self.meta_item().and_then(|meta_item| if meta_item.is_word() {
|
||||
|
|
@ -931,6 +949,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
|
|||
continue
|
||||
}
|
||||
|
||||
let mut recognised = false;
|
||||
if let Some(mi) = item.word() {
|
||||
let word = &*mi.name().as_str();
|
||||
let hint = match word {
|
||||
|
|
@ -941,20 +960,43 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
|
|||
_ => match int_type_of_word(word) {
|
||||
Some(ity) => Some(ReprInt(ity)),
|
||||
None => {
|
||||
// Not a word we recognize
|
||||
span_err!(diagnostic, item.span, E0552,
|
||||
"unrecognized representation hint");
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(h) = hint {
|
||||
recognised = true;
|
||||
acc.push(h);
|
||||
}
|
||||
} else {
|
||||
span_err!(diagnostic, item.span, E0553,
|
||||
"unrecognized enum representation hint");
|
||||
} else if let Some((name, value)) = item.name_value_literal() {
|
||||
if name == "align" {
|
||||
recognised = true;
|
||||
let mut align_error = None;
|
||||
if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
|
||||
if align.is_power_of_two() {
|
||||
// rustc::ty::layout::Align restricts align to <= 32768
|
||||
if align <= 32768 {
|
||||
acc.push(ReprAlign(align as u16));
|
||||
} else {
|
||||
align_error = Some("larger than 32768");
|
||||
}
|
||||
} else {
|
||||
align_error = Some("not a power of two");
|
||||
}
|
||||
} else {
|
||||
align_error = Some("not an unsuffixed integer");
|
||||
}
|
||||
if let Some(align_error) = align_error {
|
||||
span_err!(diagnostic, item.span, E0589,
|
||||
"invalid `repr(align)` attribute: {}", align_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !recognised {
|
||||
// Not a word we recognize
|
||||
span_err!(diagnostic, item.span, E0552,
|
||||
"unrecognized representation hint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -986,6 +1028,7 @@ pub enum ReprAttr {
|
|||
ReprExtern,
|
||||
ReprPacked,
|
||||
ReprSimd,
|
||||
ReprAlign(u16),
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
|
||||
|
|
|
|||
|
|
@ -287,10 +287,10 @@ register_diagnostics! {
|
|||
E0550, // multiple deprecated attributes
|
||||
E0551, // incorrect meta item
|
||||
E0552, // unrecognized representation hint
|
||||
E0553, // unrecognized enum representation hint
|
||||
E0554, // #[feature] may not be used on the [] release channel
|
||||
E0555, // malformed feature attribute, expected #![feature(...)]
|
||||
E0556, // malformed feature, expected just one word
|
||||
E0557, // feature has been removed
|
||||
E0584, // file for module `..` found at both .. and ..
|
||||
E0589, // invalid `repr(align)` attribute
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
module.directory.pop();
|
||||
self.cx.current_expansion.module = Rc::new(module);
|
||||
|
||||
let orig_mod_span = krate.module.inner;
|
||||
|
||||
let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
|
||||
attrs: krate.attrs,
|
||||
span: krate.span,
|
||||
|
|
@ -214,11 +216,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
vis: ast::Visibility::Public,
|
||||
})));
|
||||
|
||||
match self.expand(krate_item).make_items().pop().unwrap().unwrap() {
|
||||
ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => {
|
||||
match self.expand(krate_item).make_items().pop().map(P::unwrap) {
|
||||
Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
|
||||
krate.attrs = attrs;
|
||||
krate.module = module;
|
||||
},
|
||||
None => {
|
||||
// Resolution failed so we return an empty expansion
|
||||
krate.attrs = vec![];
|
||||
krate.module = ast::Mod {
|
||||
inner: orig_mod_span,
|
||||
items: vec![],
|
||||
};
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -335,6 +335,9 @@ declare_features! (
|
|||
// Allows the `catch {...}` expression
|
||||
(active, catch_expr, "1.17.0", Some(31436)),
|
||||
|
||||
// Allows `repr(align(u16))` struct attribute (RFC 1358)
|
||||
(active, repr_align, "1.17.0", Some(33626)),
|
||||
|
||||
// See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
|
||||
(active, rvalue_static_promotion, "1.15.1", Some(38865)),
|
||||
|
||||
|
|
@ -1185,6 +1188,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
and possibly buggy");
|
||||
|
||||
}
|
||||
if item.check_name("align") {
|
||||
gate_feature_post!(&self, repr_align, i.span,
|
||||
"the struct `#[repr(align(u16))]` attribute \
|
||||
is experimental");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,9 +128,9 @@ error: foo
|
|||
--> test.rs:2:10
|
||||
|
|
||||
2 | fn foo() {
|
||||
| __________^ starting here...
|
||||
| __________^
|
||||
3 | | }
|
||||
| |_^ ...ending here: test
|
||||
| |_^ test
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -161,11 +161,11 @@ error: foo
|
|||
--> test.rs:2:10
|
||||
|
|
||||
2 | fn foo() {
|
||||
| __________^ starting here...
|
||||
| __________^
|
||||
3 | |
|
||||
4 | |
|
||||
5 | | }
|
||||
| |___^ ...ending here: test
|
||||
| |___^ test
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -207,14 +207,14 @@ error: foo
|
|||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0
|
||||
| ____^__- starting here...
|
||||
| ____^__-
|
||||
| | ___|
|
||||
| || starting here...
|
||||
| ||
|
||||
4 | || X1 Y1
|
||||
5 | || X2 Y2
|
||||
| ||____^__- ...ending here: `Y` is a good letter too
|
||||
| ||____^__- `Y` is a good letter too
|
||||
| |____|
|
||||
| ...ending here: `X` is a good letter
|
||||
| `X` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -256,13 +256,13 @@ error: foo
|
|||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0
|
||||
| ____^__- starting here...
|
||||
| ____^__-
|
||||
| | ___|
|
||||
| || starting here...
|
||||
| ||
|
||||
4 | || Y1 X1
|
||||
| ||____-__^ ...ending here: `X` is a good letter
|
||||
| ||____-__^ `X` is a good letter
|
||||
| |_____|
|
||||
| ...ending here: `Y` is a good letter too
|
||||
| `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -306,13 +306,13 @@ error: foo
|
|||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
| ______^
|
||||
4 | | X1 Y1 Z1
|
||||
| |_________- starting here...
|
||||
| |_________-
|
||||
5 | || X2 Y2 Z2
|
||||
| ||____^ ...ending here: `X` is a good letter
|
||||
| ||____^ `X` is a good letter
|
||||
6 | | X3 Y3 Z3
|
||||
| |_____- ...ending here: `Y` is a good letter too
|
||||
| |_____- `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -366,16 +366,16 @@ error: foo
|
|||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| _____^__-__- starting here...
|
||||
| _____^__-__-
|
||||
| | ____|__|
|
||||
| || ___| starting here...
|
||||
| ||| starting here...
|
||||
| || ___|
|
||||
| |||
|
||||
4 | ||| X1 Y1 Z1
|
||||
5 | ||| X2 Y2 Z2
|
||||
| |||____^__-__- ...ending here: `Z` label
|
||||
| |||____^__-__- `Z` label
|
||||
| ||____|__|
|
||||
| |____| ...ending here: `Y` is a good letter too
|
||||
| ...ending here: `X` is a good letter
|
||||
| |____| `Y` is a good letter too
|
||||
| `X` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -430,17 +430,17 @@ error: foo
|
|||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
| ______^
|
||||
4 | | X1 Y1 Z1
|
||||
| |____^_- starting here...
|
||||
| |____^_-
|
||||
| ||____|
|
||||
| | ...ending here: `X` is a good letter
|
||||
| | `X` is a good letter
|
||||
5 | | X2 Y2 Z2
|
||||
| |____-______- ...ending here: `Y` is a good letter too
|
||||
| |____-______- `Y` is a good letter too
|
||||
| ____|
|
||||
| | starting here...
|
||||
| |
|
||||
6 | | X3 Y3 Z3
|
||||
| |________- ...ending here: `Z`
|
||||
| |________- `Z`
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -458,7 +458,7 @@ fn foo() {
|
|||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
string: "X0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
|
|
@ -481,16 +481,15 @@ fn foo() {
|
|||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:6
|
||||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
3 | / X0 Y0 Z0
|
||||
4 | | X1 Y1 Z1
|
||||
| |____^ ...ending here: `X` is a good letter
|
||||
| |____^ `X` is a good letter
|
||||
5 | X2 Y2 Z2
|
||||
| ______- starting here...
|
||||
| ______-
|
||||
6 | | X3 Y3 Z3
|
||||
| |__________- ...ending here: `Y` is a good letter too
|
||||
| |__________- `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -534,14 +533,14 @@ error: foo
|
|||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
| ______^
|
||||
4 | | X1 Y1 Z1
|
||||
| |____^____- starting here...
|
||||
| |____^____-
|
||||
| ||____|
|
||||
| | ...ending here: `X` is a good letter
|
||||
| | `X` is a good letter
|
||||
5 | | X2 Y2 Z2
|
||||
6 | | X3 Y3 Z3
|
||||
| |___________- ...ending here: `Y` is a good letter too
|
||||
| |___________- `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -982,18 +981,18 @@ error: foo
|
|||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
| ______^
|
||||
4 | | X1 Y1 Z1
|
||||
| |____^____- starting here...
|
||||
| |____^____-
|
||||
| ||____|
|
||||
| | ...ending here: `X` is a good letter
|
||||
| | `X` is a good letter
|
||||
5 | | 1
|
||||
6 | | 2
|
||||
7 | | 3
|
||||
... |
|
||||
15 | | X2 Y2 Z2
|
||||
16 | | X3 Y3 Z3
|
||||
| |___________- ...ending here: `Y` is a good letter too
|
||||
| |___________- `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
@ -1047,21 +1046,21 @@ error: foo
|
|||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
| ______^
|
||||
4 | | 1
|
||||
5 | | 2
|
||||
6 | | 3
|
||||
7 | | X1 Y1 Z1
|
||||
| |_________- starting here...
|
||||
| |_________-
|
||||
8 | || 4
|
||||
9 | || 5
|
||||
10 | || 6
|
||||
11 | || X2 Y2 Z2
|
||||
| ||__________- ...ending here: `Z` is a good letter too
|
||||
| ||__________- `Z` is a good letter too
|
||||
... |
|
||||
15 | | 10
|
||||
16 | | X3 Y3 Z3
|
||||
| |_______^ ...ending here: `Y` is a good letter
|
||||
| |_______^ `Y` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
|
|||
for a in type_attrs {
|
||||
for r in &attr::find_repr_attrs(diagnostic, a) {
|
||||
repr_type_name = match *r {
|
||||
attr::ReprPacked | attr::ReprSimd => continue,
|
||||
attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue,
|
||||
attr::ReprExtern => "i32",
|
||||
|
||||
attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
// object (usually called `crtX.o), which then invokes initialization callbacks
|
||||
// of other runtime components (registered via yet another special image section).
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![feature(no_core, lang_items, optin_builtin_traits)]
|
||||
#![crate_type="rlib"]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
|
@ -31,9 +31,12 @@
|
|||
trait Sized {}
|
||||
#[lang = "sync"]
|
||||
trait Sync {}
|
||||
impl Sync for .. {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
impl<T> Sync for T {}
|
||||
#[cfg_attr(not(stage0), lang = "freeze")]
|
||||
trait Freeze {}
|
||||
impl Freeze for .. {}
|
||||
|
||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||
pub mod eh_frames {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![feature(proc_macro)]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
22
src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
Normal file
22
src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
// aux-build:issue-41211.rs
|
||||
|
||||
// FIXME: https://github.com/rust-lang/rust/issues/41430
|
||||
// This is a temporary regression test for the ICE reported in #41211
|
||||
|
||||
#![feature(proc_macro)]
|
||||
#![emit_unchanged]
|
||||
//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope
|
||||
extern crate issue_41211;
|
||||
use issue_41211::emit_unchanged;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
|
||||
|
|
@ -29,6 +30,9 @@ struct SInt(f64, f64);
|
|||
#[repr(C)]
|
||||
enum EExtern { A, B }
|
||||
|
||||
#[repr(align(8))] //~ ERROR: attribute should be applied to struct
|
||||
enum EAlign { A, B }
|
||||
|
||||
#[repr(packed)] //~ ERROR: attribute should be applied to struct
|
||||
enum EPacked { A, B }
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,5 @@ fn main() {
|
|||
let _: &[i32] = [0];
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `&[i32]`
|
||||
//~| found type `[{integer}; 1]`
|
||||
//~| expected &[i32], found array of 1 elements
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_align)]
|
||||
|
||||
#[repr(C)]
|
||||
enum A { A }
|
||||
|
|
@ -26,5 +27,7 @@ enum D { D }
|
|||
#[repr(C, packed)]
|
||||
struct E(i32);
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
||||
#[repr(packed, align(8))] //~ ERROR conflicting packed and align representation hints
|
||||
struct F(i32);
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Trait for Foo {}
|
|||
|
||||
pub fn main() {
|
||||
let x: Box<Trait> = Box::new(Foo);
|
||||
let _y: &Trait = x; //~ ERROR mismatched types
|
||||
let _y: &Trait = x; //~ ERROR E0308
|
||||
//~| expected type `&Trait`
|
||||
//~| found type `std::boxed::Box<Trait>`
|
||||
}
|
||||
|
|
|
|||
15
src/test/compile-fail/feature-gate-repr_align.rs
Normal file
15
src/test/compile-fail/feature-gate-repr_align.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 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.
|
||||
#![feature(attr_literals)]
|
||||
|
||||
#[repr(align(64))]
|
||||
struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
|
|||
fn main() {
|
||||
let mut c = for_stdin();
|
||||
let mut v = Vec::new();
|
||||
c.read_to(v); //~ ERROR mismatched types
|
||||
c.read_to(v); //~ ERROR E0308
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,4 +35,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
|
|||
fn main() {
|
||||
check((3, 5));
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP try with `&(3, 5)`
|
||||
}
|
||||
|
|
|
|||
23
src/test/compile-fail/repr-align.rs
Normal file
23
src/test/compile-fail/repr-align.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 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.
|
||||
#![allow(dead_code)]
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_align)]
|
||||
|
||||
#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
|
||||
struct A(i32);
|
||||
|
||||
#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
|
||||
struct B(i32);
|
||||
|
||||
#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768
|
||||
struct C(i32);
|
||||
|
||||
fn main() {}
|
||||
25
src/test/compile-fail/repr-packed-contains-align.rs
Normal file
25
src/test/compile-fail/repr-packed-contains-align.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2017 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.
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_align)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[repr(align(16))]
|
||||
struct A(i32);
|
||||
|
||||
struct B(A);
|
||||
|
||||
#[repr(packed)]
|
||||
struct C(A); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
|
||||
|
||||
#[repr(packed)]
|
||||
struct D(B); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#![crate_type = "lib"]
|
||||
// we can compile to a variety of platforms, because we don't need
|
||||
// cross-compiled standard libraries.
|
||||
#![feature(no_core)]
|
||||
#![feature(no_core, optin_builtin_traits)]
|
||||
#![no_core]
|
||||
|
||||
#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)]
|
||||
|
|
@ -78,3 +78,7 @@ pub trait Copy { }
|
|||
pub mod marker {
|
||||
pub use Copy;
|
||||
}
|
||||
|
||||
#[lang = "freeze"]
|
||||
trait Freeze {}
|
||||
impl Freeze for .. {}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(lang_items, no_core)]
|
||||
#![feature(lang_items, no_core, optin_builtin_traits)]
|
||||
#![no_core]
|
||||
|
||||
#[lang="copy"]
|
||||
|
|
@ -17,6 +17,10 @@ trait Copy { }
|
|||
#[lang="sized"]
|
||||
trait Sized { }
|
||||
|
||||
#[lang = "freeze"]
|
||||
trait Freeze {}
|
||||
impl Freeze for .. {}
|
||||
|
||||
#[lang="start"]
|
||||
fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 }
|
||||
|
||||
|
|
|
|||
196
src/test/run-pass/align-struct.rs
Normal file
196
src/test/run-pass/align-struct.rs
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright 2017 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.
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_align)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
// Raising alignment
|
||||
#[repr(align(16))]
|
||||
struct Align16(i32);
|
||||
|
||||
// Lowering has no effect
|
||||
#[repr(align(1))]
|
||||
struct Align1(i32);
|
||||
|
||||
// Multiple attributes take the max
|
||||
#[repr(align(4))]
|
||||
#[repr(align(16))]
|
||||
#[repr(align(8))]
|
||||
struct AlignMany(i32);
|
||||
|
||||
// Raising alignment may not alter size.
|
||||
#[repr(align(8))]
|
||||
#[allow(dead_code)]
|
||||
struct Align8Many {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: i32,
|
||||
d: u8,
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
#[allow(dead_code)]
|
||||
A(i32),
|
||||
B(Align16)
|
||||
}
|
||||
|
||||
// Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test
|
||||
#[repr(C)]
|
||||
struct Nested {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: Align16,
|
||||
d: i8,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct Packed(i32);
|
||||
|
||||
#[repr(align(16))]
|
||||
struct AlignContainsPacked {
|
||||
a: Packed,
|
||||
b: Packed,
|
||||
}
|
||||
|
||||
impl Align16 {
|
||||
// return aligned type
|
||||
pub fn new(i: i32) -> Align16 {
|
||||
Align16(i)
|
||||
}
|
||||
// pass aligned type
|
||||
pub fn consume(a: Align16) -> i32 {
|
||||
a.0
|
||||
}
|
||||
}
|
||||
|
||||
const CONST_ALIGN16: Align16 = Align16(7);
|
||||
static STATIC_ALIGN16: Align16 = Align16(8);
|
||||
|
||||
// Check the actual address is aligned
|
||||
fn is_aligned_to<T>(p: &T, align: usize) -> bool {
|
||||
let addr = p as *const T as usize;
|
||||
(addr & (align - 1)) == 0
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
// check alignment and size by type and value
|
||||
assert_eq!(mem::align_of::<Align16>(), 16);
|
||||
assert_eq!(mem::size_of::<Align16>(), 16);
|
||||
|
||||
let a = Align16(7);
|
||||
assert_eq!(a.0, 7);
|
||||
assert_eq!(mem::align_of_val(&a), 16);
|
||||
assert_eq!(mem::size_of_val(&a), 16);
|
||||
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
|
||||
// lowering should have no effect
|
||||
assert_eq!(mem::align_of::<Align1>(), 4);
|
||||
assert_eq!(mem::size_of::<Align1>(), 4);
|
||||
let a = Align1(7);
|
||||
assert_eq!(a.0, 7);
|
||||
assert_eq!(mem::align_of_val(&a), 4);
|
||||
assert_eq!(mem::size_of_val(&a), 4);
|
||||
assert!(is_aligned_to(&a, 4));
|
||||
|
||||
// when multiple attributes are specified the max should be used
|
||||
assert_eq!(mem::align_of::<AlignMany>(), 16);
|
||||
assert_eq!(mem::size_of::<AlignMany>(), 16);
|
||||
let a = AlignMany(7);
|
||||
assert_eq!(a.0, 7);
|
||||
assert_eq!(mem::align_of_val(&a), 16);
|
||||
assert_eq!(mem::size_of_val(&a), 16);
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
|
||||
// raising alignment should not reduce size
|
||||
assert_eq!(mem::align_of::<Align8Many>(), 8);
|
||||
assert_eq!(mem::size_of::<Align8Many>(), 16);
|
||||
let a = Align8Many { a: 1, b: 2, c: 3, d: 4 };
|
||||
assert_eq!(a.a, 1);
|
||||
assert_eq!(mem::align_of_val(&a), 8);
|
||||
assert_eq!(mem::size_of_val(&a), 16);
|
||||
assert!(is_aligned_to(&a, 8));
|
||||
|
||||
// return type
|
||||
let a = Align16::new(1);
|
||||
assert_eq!(mem::align_of_val(&a), 16);
|
||||
assert_eq!(mem::size_of_val(&a), 16);
|
||||
assert_eq!(a.0, 1);
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
assert_eq!(Align16::consume(a), 1);
|
||||
|
||||
// check const alignment, size and value
|
||||
assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16);
|
||||
assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16);
|
||||
assert_eq!(CONST_ALIGN16.0, 7);
|
||||
assert!(is_aligned_to(&CONST_ALIGN16, 16));
|
||||
|
||||
// check global static alignment, size and value
|
||||
assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16);
|
||||
assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16);
|
||||
assert_eq!(STATIC_ALIGN16.0, 8);
|
||||
assert!(is_aligned_to(&STATIC_ALIGN16, 16));
|
||||
|
||||
// Note that the size of Nested may change if struct field re-ordering is enabled
|
||||
assert_eq!(mem::align_of::<Nested>(), 16);
|
||||
assert_eq!(mem::size_of::<Nested>(), 48);
|
||||
let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4};
|
||||
assert_eq!(mem::align_of_val(&a), 16);
|
||||
assert_eq!(mem::align_of_val(&a.b), 4);
|
||||
assert_eq!(mem::align_of_val(&a.c), 16);
|
||||
assert_eq!(mem::size_of_val(&a), 48);
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
// check the correct fields are indexed
|
||||
assert_eq!(a.a, 1);
|
||||
assert_eq!(a.b, 2);
|
||||
assert_eq!(a.c.0, 3);
|
||||
assert_eq!(a.d, 4);
|
||||
|
||||
// enum should be aligned to max alignment
|
||||
assert_eq!(mem::align_of::<Enum>(), 16);
|
||||
assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16);
|
||||
let e = Enum::B(Align16(15));
|
||||
match e {
|
||||
Enum::B(ref a) => {
|
||||
assert_eq!(a.0, 15);
|
||||
assert_eq!(mem::align_of_val(a), 16);
|
||||
assert_eq!(mem::size_of_val(a), 16);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
assert!(is_aligned_to(&e, 16));
|
||||
|
||||
// arrays of aligned elements should also be aligned
|
||||
assert_eq!(mem::align_of::<[Align16;2]>(), 16);
|
||||
assert_eq!(mem::size_of::<[Align16;2]>(), 32);
|
||||
|
||||
let a = [Align16(0), Align16(1)];
|
||||
assert_eq!(mem::align_of_val(&a[0]), 16);
|
||||
assert_eq!(mem::align_of_val(&a[1]), 16);
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
|
||||
// check heap value is aligned
|
||||
assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16);
|
||||
|
||||
// check heap array is aligned
|
||||
let a = vec!(Align16(0), Align16(1));
|
||||
assert_eq!(mem::align_of_val(&a[0]), 16);
|
||||
assert_eq!(mem::align_of_val(&a[1]), 16);
|
||||
|
||||
assert_eq!(mem::align_of::<AlignContainsPacked>(), 16);
|
||||
assert_eq!(mem::size_of::<AlignContainsPacked>(), 16);
|
||||
let a = AlignContainsPacked { a: Packed(1), b: Packed(2) };
|
||||
assert_eq!(mem::align_of_val(&a), 16);
|
||||
assert_eq!(mem::align_of_val(&a.a), 1);
|
||||
assert_eq!(mem::align_of_val(&a.b), 1);
|
||||
assert_eq!(mem::size_of_val(&a), 16);
|
||||
assert!(is_aligned_to(&a, 16));
|
||||
}
|
||||
|
|
@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait
|
|||
15 | fn renew<'b: 'a>(self) -> &'b mut [T];
|
||||
| -------------------------------------- definition of `renew` from trait
|
||||
...
|
||||
19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
||||
| _____^ starting here...
|
||||
19 | / fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
||||
20 | | //~^ ERROR E0276
|
||||
21 | | &mut self[..]
|
||||
22 | | }
|
||||
| |_____^ ...ending here: impl has extra requirement `'a: 'b`
|
||||
| |_____^ impl has extra requirement `'a: 'b`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait
|
|||
19 | fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
|
||||
| ------------------------------------------------------------------ definition of `zip` from trait
|
||||
...
|
||||
23 | fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
|
||||
| _____^ starting here...
|
||||
23 | / fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
|
||||
24 | | //~^ ERROR E0276
|
||||
25 | | ZipIterator{a: self, b: other}
|
||||
26 | | }
|
||||
| |_____^ ...ending here: impl has extra requirement `U: Iterator<B>`
|
||||
| |_____^ impl has extra requirement `U: Iterator<B>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ error: missing `fn`, `type`, or `const` for impl-item declaration
|
|||
--> $DIR/issue-40006.rs:11:9
|
||||
|
|
||||
11 | impl X {
|
||||
| _________^ starting here...
|
||||
| _________^
|
||||
12 | | Y
|
||||
| |____^ ...ending here: missing `fn`, `type`, or `const`
|
||||
| |____^ missing `fn`, `type`, or `const`
|
||||
|
||||
error: missing `fn`, `type`, or `const` for trait-item declaration
|
||||
--> $DIR/issue-40006.rs:17:10
|
||||
|
|
||||
17 | trait X {
|
||||
| __________^ starting here...
|
||||
| __________^
|
||||
18 | | X() {}
|
||||
| |____^ ...ending here: missing `fn`, `type`, or `const`
|
||||
| |____^ missing `fn`, `type`, or `const`
|
||||
|
||||
error: expected `[`, found `#`
|
||||
--> $DIR/issue-40006.rs:19:17
|
||||
|
|
@ -24,17 +24,17 @@ error: missing `fn`, `type`, or `const` for trait-item declaration
|
|||
--> $DIR/issue-40006.rs:19:21
|
||||
|
|
||||
19 | fn xxx() { ### }
|
||||
| _____________________^ starting here...
|
||||
| _____________________^
|
||||
20 | | L = M;
|
||||
| |____^ ...ending here: missing `fn`, `type`, or `const`
|
||||
| |____^ missing `fn`, `type`, or `const`
|
||||
|
||||
error: missing `fn`, `type`, or `const` for trait-item declaration
|
||||
--> $DIR/issue-40006.rs:20:11
|
||||
|
|
||||
20 | L = M;
|
||||
| ___________^ starting here...
|
||||
| ___________^
|
||||
21 | | Z = { 2 + 3 };
|
||||
| |____^ ...ending here: missing `fn`, `type`, or `const`
|
||||
| |____^ missing `fn`, `type`, or `const`
|
||||
|
||||
error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
|
||||
--> $DIR/issue-40006.rs:21:18
|
||||
|
|
|
|||
|
|
@ -1,26 +1,24 @@
|
|||
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1
|
||||
|
|
||||
32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
|
||||
| _^ starting here...
|
||||
32 | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
|
||||
33 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
34 | |
|
||||
35 | | // (unsafe to access self.1 due to #[may_dangle] on A)
|
||||
36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
|
||||
37 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
|
||||
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1
|
||||
|
|
||||
38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
|
||||
| _^ starting here...
|
||||
38 | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
|
||||
39 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
40 | |
|
||||
41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a)
|
||||
42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
|
||||
43 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
error: reached the type-length limit while instantiating `<T as Foo><(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...`
|
||||
--> $DIR/issue-37311.rs:23:5
|
||||
|
|
||||
23 | fn recurse(&self) {
|
||||
| _____^ starting here...
|
||||
23 | / fn recurse(&self) {
|
||||
24 | | (self, self).recurse();
|
||||
25 | | }
|
||||
| |_____^ ...ending here
|
||||
| |_____^
|
||||
|
|
||||
= note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate
|
||||
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ note: ...the reference is valid for the lifetime 'a as defined on the body at 11
|
|||
--> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
|
||||
|
|
||||
11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
|
||||
| ____________________________________________^ starting here...
|
||||
| ____________________________________________^
|
||||
12 | | if x > y { x } else { y }
|
||||
13 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43
|
||||
--> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
|
||||
|
|
||||
11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
|
||||
| ____________________________________________^ starting here...
|
||||
| ____________________________________________^
|
||||
12 | | if x > y { x } else { y }
|
||||
13 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ note: the anonymous lifetime #2 defined on the body at 15:51...
|
|||
--> $DIR/ex2a-push-one-existing-name.rs:15:52
|
||||
|
|
||||
15 | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
|
||||
| ____________________________________________________^ starting here...
|
||||
| ____________________________________________________^
|
||||
16 | | x.push(y);
|
||||
17 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51
|
||||
--> $DIR/ex2a-push-one-existing-name.rs:15:52
|
||||
|
|
||||
15 | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
|
||||
| ____________________________________________________^ starting here...
|
||||
| ____________________________________________________^
|
||||
16 | | x.push(y);
|
||||
17 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ note: the anonymous lifetime #3 defined on the body at 15:43...
|
|||
--> $DIR/ex2b-push-no-existing-names.rs:15:44
|
||||
|
|
||||
15 | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
|
||||
| ____________________________________________^ starting here...
|
||||
| ____________________________________________^
|
||||
16 | | x.push(y);
|
||||
17 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43
|
||||
--> $DIR/ex2b-push-no-existing-names.rs:15:44
|
||||
|
|
||||
15 | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
|
||||
| ____________________________________________^ starting here...
|
||||
| ____________________________________________^
|
||||
16 | | x.push(y);
|
||||
17 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
|
|||
--> $DIR/ex2c-push-inference-variable.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let z = Ref { data: y.data };
|
||||
17 | | x.push(z);
|
||||
18 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/ex2c-push-inference-variable.rs:16:25
|
||||
|
|
||||
|
|
@ -22,11 +22,11 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
|
|||
--> $DIR/ex2c-push-inference-variable.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let z = Ref { data: y.data };
|
||||
17 | | x.push(z);
|
||||
18 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>)
|
||||
--> $DIR/ex2c-push-inference-variable.rs:17:12
|
||||
|
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
|
|||
--> $DIR/ex2d-push-inference-variable-2.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let a: &mut Vec<Ref<i32>> = x;
|
||||
17 | | let b = Ref { data: y.data };
|
||||
18 | | a.push(b);
|
||||
19 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/ex2d-push-inference-variable-2.rs:17:25
|
||||
|
|
||||
|
|
@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
|
|||
--> $DIR/ex2d-push-inference-variable-2.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let a: &mut Vec<Ref<i32>> = x;
|
||||
17 | | let b = Ref { data: y.data };
|
||||
18 | | a.push(b);
|
||||
19 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that expression is assignable (expected &mut std::vec::Vec<Ref<'_, i32>>, found &mut std::vec::Vec<Ref<'b, i32>>)
|
||||
--> $DIR/ex2d-push-inference-variable-2.rs:16:33
|
||||
|
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body
|
|||
--> $DIR/ex2e-push-inference-variable-3.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let a: &mut Vec<Ref<i32>> = x;
|
||||
17 | | let b = Ref { data: y.data };
|
||||
18 | | Vec::push(a, b);
|
||||
19 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/ex2e-push-inference-variable-3.rs:17:25
|
||||
|
|
||||
|
|
@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
|
|||
--> $DIR/ex2e-push-inference-variable-3.rs:15:67
|
||||
|
|
||||
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
|
||||
| ___________________________________________________________________^ starting here...
|
||||
| ___________________________________________________________________^
|
||||
16 | | let a: &mut Vec<Ref<i32>> = x;
|
||||
17 | | let b = Ref { data: y.data };
|
||||
18 | | Vec::push(a, b);
|
||||
19 | | }
|
||||
| |_^ ...ending here
|
||||
| |_^
|
||||
note: ...so that expression is assignable (expected &mut std::vec::Vec<Ref<'_, i32>>, found &mut std::vec::Vec<Ref<'b, i32>>)
|
||||
--> $DIR/ex2e-push-inference-variable-3.rs:16:33
|
||||
|
|
||||
|
|
|
|||
|
|
@ -37,15 +37,14 @@ error[E0308]: mismatched types
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/abridged.rs:42:5
|
||||
|
|
||||
42 | X {
|
||||
| _____^ starting here...
|
||||
42 | / X {
|
||||
43 | | x: X {
|
||||
44 | | x: "".to_string(),
|
||||
45 | | y: 2,
|
||||
46 | | },
|
||||
47 | | y: 3,
|
||||
48 | | }
|
||||
| |_____^ ...ending here: expected struct `std::string::String`, found integral variable
|
||||
| |_____^ expected struct `std::string::String`, found integral variable
|
||||
|
|
||||
= note: expected type `X<X<_, std::string::String>, std::string::String>`
|
||||
found type `X<X<_, {integer}>, {integer}>`
|
||||
|
|
@ -53,15 +52,14 @@ error[E0308]: mismatched types
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/abridged.rs:52:5
|
||||
|
|
||||
52 | X {
|
||||
| _____^ starting here...
|
||||
52 | / X {
|
||||
53 | | x: X {
|
||||
54 | | x: "".to_string(),
|
||||
55 | | y: 2,
|
||||
56 | | },
|
||||
57 | | y: "".to_string(),
|
||||
58 | | }
|
||||
| |_____^ ...ending here: expected struct `std::string::String`, found integral variable
|
||||
| |_____^ expected struct `std::string::String`, found integral variable
|
||||
|
|
||||
= note: expected type `X<X<_, std::string::String>, _>`
|
||||
found type `X<X<_, {integer}>, _>`
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ error[E0308]: mismatched types
|
|||
--> $DIR/main.rs:12:18
|
||||
|
|
||||
12 | let x: u32 = (
|
||||
| __________________^ starting here...
|
||||
| __________________^
|
||||
13 | | );
|
||||
| |_____^ ...ending here: expected u32, found ()
|
||||
| |_____^ expected u32, found ()
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `()`
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ error: main function not found
|
|||
error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method`
|
||||
--> $DIR/m2.rs:20:1
|
||||
|
|
||||
20 | impl m1::X for X {
|
||||
| _^ starting here...
|
||||
20 | / impl m1::X for X {
|
||||
21 | | }
|
||||
| |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation
|
||||
| |_^ missing `CONSTANT`, `Type`, `method` in implementation
|
||||
|
|
||||
= note: `CONSTANT` from trait: `const CONSTANT: u32;`
|
||||
= note: `Type` from trait: `type Type;`
|
||||
|
|
|
|||
43
src/test/ui/print_type_sizes/repr-align.rs
Normal file
43
src/test/ui/print_type_sizes/repr-align.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// 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.
|
||||
|
||||
// compile-flags: -Z print-type-sizes
|
||||
|
||||
// This file illustrates how padding is handled: alignment
|
||||
// requirements can lead to the introduction of padding, either before
|
||||
// fields or at the end of the structure as a whole.
|
||||
//
|
||||
// It avoids using u64/i64 because on some targets that is only 4-byte
|
||||
// aligned (while on most it is 8-byte aligned) and so the resulting
|
||||
// padding and overall computed sizes can be quite different.
|
||||
#![feature(attr_literals)]
|
||||
#![feature(repr_align)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[repr(align(16))]
|
||||
#[derive(Default)]
|
||||
struct A(i32);
|
||||
|
||||
enum E {
|
||||
A(i32),
|
||||
B(A)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct S {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: A,
|
||||
d: i8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _s: S = Default::default();
|
||||
}
|
||||
16
src/test/ui/print_type_sizes/repr-align.stdout
Normal file
16
src/test/ui/print_type_sizes/repr-align.stdout
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
print-type-size type: `E`: 32 bytes, alignment: 16 bytes
|
||||
print-type-size discriminant: 4 bytes
|
||||
print-type-size variant `A`: 4 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
print-type-size variant `B`: 28 bytes
|
||||
print-type-size padding: 12 bytes
|
||||
print-type-size field `.0`: 16 bytes, alignment: 16 bytes
|
||||
print-type-size type: `S`: 32 bytes, alignment: 16 bytes
|
||||
print-type-size field `.c`: 16 bytes
|
||||
print-type-size field `.a`: 4 bytes
|
||||
print-type-size field `.b`: 4 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
print-type-size end padding: 7 bytes
|
||||
print-type-size type: `A`: 16 bytes, alignment: 16 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
print-type-size end padding: 12 bytes
|
||||
|
|
@ -32,7 +32,6 @@ fn main() {
|
|||
//~| NOTE types differ in mutability
|
||||
//~| NOTE expected type `&mut std::string::String`
|
||||
//~| NOTE found type `&std::string::String`
|
||||
//~| HELP try with `&mut y`
|
||||
test2(&y);
|
||||
//~^ ERROR E0308
|
||||
//~| NOTE types differ in mutability
|
||||
|
|
|
|||
|
|
@ -18,11 +18,7 @@ error[E0308]: mismatched types
|
|||
|
|
||||
= note: expected type `&str`
|
||||
found type `std::string::String`
|
||||
= help: here are some functions which might fulfill your needs:
|
||||
- .as_str()
|
||||
- .trim()
|
||||
- .trim_left()
|
||||
- .trim_right()
|
||||
= help: try with `&String::new()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:30:10
|
||||
|
|
@ -34,18 +30,18 @@ error[E0308]: mismatched types
|
|||
found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:36:11
|
||||
--> $DIR/coerce-suggestions.rs:35:11
|
||||
|
|
||||
36 | test2(&y);
|
||||
35 | test2(&y);
|
||||
| ^^ types differ in mutability
|
||||
|
|
||||
= note: expected type `&mut i32`
|
||||
found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:42:9
|
||||
--> $DIR/coerce-suggestions.rs:41:9
|
||||
|
|
||||
42 | f = box f;
|
||||
41 | f = box f;
|
||||
| ^^^^^ cyclic type of infinite size
|
||||
|
|
||||
= note: expected type `_`
|
||||
|
|
|
|||
|
|
@ -19,15 +19,14 @@ error[E0046]: not all trait items implemented, missing: `bar`
|
|||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
...
|
||||
22 | impl Foo for FooConstForMethod {
|
||||
| _^ starting here...
|
||||
22 | / impl Foo for FooConstForMethod {
|
||||
23 | | //~^ ERROR E0046
|
||||
24 | | //~| NOTE missing `bar` in implementation
|
||||
25 | | const bar: u64 = 1;
|
||||
... |
|
||||
28 | | const MY_CONST: u32 = 1;
|
||||
29 | | }
|
||||
| |_^ ...ending here: missing `bar` in implementation
|
||||
| |_^ missing `bar` in implementation
|
||||
|
||||
error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:37:5
|
||||
|
|
@ -44,15 +43,14 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST`
|
|||
17 | const MY_CONST: u32;
|
||||
| -------------------- `MY_CONST` from trait
|
||||
...
|
||||
33 | impl Foo for FooMethodForConst {
|
||||
| _^ starting here...
|
||||
33 | / impl Foo for FooMethodForConst {
|
||||
34 | | //~^ ERROR E0046
|
||||
35 | | //~| NOTE missing `MY_CONST` in implementation
|
||||
36 | | fn bar(&self) {}
|
||||
... |
|
||||
39 | | //~| NOTE does not match trait
|
||||
40 | | }
|
||||
| |_^ ...ending here: missing `MY_CONST` in implementation
|
||||
| |_^ missing `MY_CONST` in implementation
|
||||
|
||||
error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:47:5
|
||||
|
|
@ -69,23 +67,21 @@ error[E0046]: not all trait items implemented, missing: `bar`
|
|||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
...
|
||||
44 | impl Foo for FooTypeForMethod {
|
||||
| _^ starting here...
|
||||
44 | / impl Foo for FooTypeForMethod {
|
||||
45 | | //~^ ERROR E0046
|
||||
46 | | //~| NOTE missing `bar` in implementation
|
||||
47 | | type bar = u64;
|
||||
... |
|
||||
50 | | const MY_CONST: u32 = 1;
|
||||
51 | | }
|
||||
| |_^ ...ending here: missing `bar` in implementation
|
||||
| |_^ missing `bar` in implementation
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `fmt`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:53:1
|
||||
|
|
||||
53 | impl Debug for FooTypeForMethod {
|
||||
| _^ starting here...
|
||||
53 | / impl Debug for FooTypeForMethod {
|
||||
54 | | }
|
||||
| |_^ ...ending here: missing `fmt` in implementation
|
||||
| |_^ missing `fmt` in implementation
|
||||
|
|
||||
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
error[E0046]: not all trait items implemented, missing: `Item`
|
||||
--> $DIR/issue-23729.rs:20:9
|
||||
|
|
||||
20 | impl Iterator for Recurrence {
|
||||
| _________^ starting here...
|
||||
20 | / impl Iterator for Recurrence {
|
||||
21 | | //~^ ERROR E0046
|
||||
22 | | //~| NOTE missing `Item` in implementation
|
||||
23 | | //~| NOTE `Item` from trait: `type Item;`
|
||||
... |
|
||||
36 | | }
|
||||
37 | | }
|
||||
| |_________^ ...ending here: missing `Item` in implementation
|
||||
| |_________^ missing `Item` in implementation
|
||||
|
|
||||
= note: `Item` from trait: `type Item;`
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue