Resolve merge conflict

This commit is contained in:
matthewjasper 2017-04-22 17:55:59 +01:00
commit 8a3ea01bca
110 changed files with 1691 additions and 713 deletions

2
configure vendored
View file

@ -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

@ -1 +1 @@
Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce

View file

@ -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)

View file

@ -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"]));

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -0,0 +1,11 @@
# `repr_align`
The tracking issue for this feature is: [#33626]
[#33626]: https://github.com/rust-lang/rust/issues/33626
------------------------

View file

@ -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" \
"$@"

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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]

View file

@ -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>

View file

@ -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()
}
}

View file

@ -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> {

View file

@ -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

View file

@ -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
}

View file

@ -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) {

View file

@ -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;

View file

@ -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
}
}
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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));

View file

@ -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),
&param_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>> {

View file

@ -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),

View 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,
})
}

View file

@ -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")

View file

@ -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)

View file

@ -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)]

View file

@ -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, \

View file

@ -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> {

View file

@ -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, &param_env) {
if ty.needs_drop(tcx, &param_env) {
cost += CALL_PENALTY;
if let Some(unwind) = unwind {
work_list.push(unwind);

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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
}
}

View file

@ -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);
}
}

View file

@ -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
}

View file

@ -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);

View file

@ -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
}

View file

@ -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.

View file

@ -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 {

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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").

View file

@ -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,
}
}
}

View file

@ -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,

View file

@ -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 `{}`
}

View file

@ -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);
}
}

View file

@ -27,6 +27,7 @@
#![feature(staged_api)]
#![feature(test)]
#![feature(unicode)]
#![feature(vec_remove_item)]
extern crate arena;
extern crate getopts;

View file

@ -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 \

View file

@ -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],
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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)]

View file

@ -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
}

View file

@ -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!(),
};

View file

@ -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");
}
}
}
}

View file

@ -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
"#);
}

View file

@ -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",

View file

@ -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 {

View 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.
// 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
}

View 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() {}

View file

@ -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 }

View file

@ -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
}

View file

@ -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() {}

View file

@ -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>`
}

View 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() {}

View file

@ -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
}

View file

@ -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)`
}

View 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() {}

View 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() {}

View file

@ -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 .. {}

View file

@ -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 }

View 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));
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
|

View file

@ -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
|

View file

@ -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
|

View file

@ -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}>, _>`

View file

@ -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 `()`

View file

@ -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;`

View 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();
}

View 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

View file

@ -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

View file

@ -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 `_`

View file

@ -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>`

View file

@ -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