Added error-format flag to x.py.
Fixes #48475
r? @Mark-Simulacrum
raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
# only the n64 ABI is supported, indicate it
ostype += 'abi64'
- elif cputype == 'sparcv9' or cputype == 'sparc64':
+ elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64':
pass
else:
err = "unknown cpu type: {}".format(cputype)
fn run(self, builder: &Builder) -> Interned<PathBuf> {
let compiler = self.compiler;
- let lib = if compiler.stage >= 1 && builder.build.config.libdir.is_some() {
- builder.build.config.libdir.clone().unwrap()
+ let config = &builder.build.config;
+ let lib = if compiler.stage >= 1 && config.libdir_relative().is_some() {
+ builder.build.config.libdir_relative().unwrap()
} else {
- PathBuf::from("lib")
+ Path::new("lib")
};
let sysroot = builder.sysroot(self.compiler).join(lib)
.join("rustlib").join(self.target).join("lib");
.env("CFG_VERSION", build.rust_version())
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
- let libdir_relative =
- build.config.libdir.clone().unwrap_or(PathBuf::from("lib"));
+ let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
// If we're not building a compiler with debugging information then remove
use std::env;
use std::fs::File;
use std::io::prelude::*;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::process;
use std::cmp;
config
}
+ /// Try to find the relative path of `libdir`.
+ pub fn libdir_relative(&self) -> Option<&Path> {
+ let libdir = self.libdir.as_ref()?;
+ if libdir.is_relative() {
+ Some(libdir)
+ } else {
+ // Try to make it relative to the prefix.
+ libdir.strip_prefix(self.prefix.as_ref()?).ok()
+ }
+ }
+
pub fn verbose(&self) -> bool {
self.verbose > 0
}
type Output = ();
fn should_run(run: ShouldRun) -> ShouldRun {
- run.path("src/rt/rust_test_helpers.c")
+ run.path("src/test/auxiliary/rust_test_helpers.c")
}
fn make_run(run: RunConfig) {
let build = builder.build;
let target = self.target;
let dst = build.test_helpers_out(target);
- let src = build.src.join("src/rt/rust_test_helpers.c");
+ let src = build.src.join("src/test/auxiliary/rust_test_helpers.c");
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
return
}
.opt_level(0)
.warnings(false)
.debug(false)
- .file(build.src.join("src/rt/rust_test_helpers.c"))
+ .file(build.src.join("src/test/auxiliary/rust_test_helpers.c"))
.compile("rust_test_helpers");
}
}
"mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
"mipsel-unknown-linux-gnu" => "linux-mips32",
"powerpc-unknown-linux-gnu" => "linux-ppc",
+ "powerpc-unknown-netbsd" => "BSD-generic32",
"powerpc64-unknown-linux-gnu" => "linux-ppc64",
"powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
"s390x-unknown-linux-gnu" => "linux64-s390x",
+ "sparc-unknown-linux-gnu" => "linux-sparcv9",
"sparc64-unknown-linux-gnu" => "linux64-sparcv9",
"sparc64-unknown-netbsd" => "BSD-sparc64",
"x86_64-apple-darwin" => "darwin64-x86_64-cc",
"x86_64-unknown-freebsd" => "BSD-x86_64",
"x86_64-unknown-dragonfly" => "BSD-x86_64",
"x86_64-unknown-linux-gnu" => "linux-x86_64",
+ "x86_64-unknown-linux-gnux32" => "linux-x32",
"x86_64-unknown-linux-musl" => "linux-x86_64",
"x86_64-unknown-netbsd" => "BSD-x86_64",
_ => panic!("don't know how to configure OpenSSL for {}", target),
-Subproject commit ec5660820dea91df470dab0b9eb26ef798f20889
+Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d
+++ /dev/null
-# `entry_and_modify`
-
-The tracking issue for this feature is: [#44733]
-
-[#44733]: https://github.com/rust-lang/rust/issues/44733
-
-------------------------
-
-This introduces a new method for the Entry API of maps
-(`std::collections::HashMap` and `std::collections::BTreeMap`), so that
-occupied entries can be modified before any potential inserts into the
-map.
-
-For example:
-
-```rust
-#![feature(entry_and_modify)]
-# fn main() {
-use std::collections::HashMap;
-
-struct Foo {
- new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-map.entry("quux")
- .and_modify(|e| e.new = false)
- .or_insert(Foo { new: true });
-# }
-```
-
-This is not possible with the stable API alone since inserting a default
-_before_ modifying the `new` field would mean we would lose the default state:
-
-```rust
-# fn main() {
-use std::collections::HashMap;
-
-struct Foo {
- new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-map.entry("quux").or_insert(Foo { new: true }).new = false;
-# }
-```
-
-In the above code the `new` field will never be `true`, even though we only
-intended to update that field to `false` for previously extant entries.
-
-To achieve the same effect as `and_modify` we would have to manually match
-against the `Occupied` and `Vacant` variants of the `Entry` enum, which is
-a little less user-friendly, and much more verbose:
-
-```rust
-# fn main() {
-use std::collections::HashMap;
-use std::collections::hash_map::Entry;
-
-struct Foo {
- new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-match map.entry("quux") {
- Entry::Occupied(entry) => {
- entry.into_mut().new = false;
- },
- Entry::Vacant(entry) => {
- entry.insert(Foo { new: true });
- },
-};
-# }
-```
/// Simple usage:
///
/// ```
- /// #![feature(box_leak)]
- ///
/// fn main() {
/// let x = Box::new(41);
/// let static_ref: &'static mut usize = Box::leak(x);
/// Unsized data:
///
/// ```
- /// #![feature(box_leak)]
- ///
/// fn main() {
/// let x = vec![1, 2, 3].into_boxed_slice();
/// let static_ref = Box::leak(x);
/// assert_eq!(*static_ref, [4, 2, 3]);
/// }
/// ```
- #[unstable(feature = "box_leak", reason = "needs an FCP to stabilize",
- issue = "46179")]
+ #[stable(feature = "box_leak", since = "1.26.0")]
#[inline]
pub fn leak<'a>(b: Box<T>) -> &'a mut T
where
/// # Examples
///
/// ```
- /// #![feature(entry_and_modify)]
/// use std::collections::BTreeMap;
///
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
/// .or_insert(42);
/// assert_eq!(map["poneyland"], 43);
/// ```
- #[unstable(feature = "entry_and_modify", issue = "44733")]
+ #[stable(feature = "entry_and_modify", since = "1.26.0")]
pub fn and_modify<F>(self, mut f: F) -> Self
where F: FnMut(&mut V)
{
use ops::Try;
use super::{AlwaysOk, LoopState};
-use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
+use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse};
+use super::{Flatten, FlatMap, flatten_compat};
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
use super::{Zip, Sum, Product};
use super::{ChainState, FromIterator, ZipImpl};
/// an extra layer of indirection. `flat_map()` will remove this extra layer
/// on its own.
///
+ /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent
+ /// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
+ ///
/// Another way of thinking about `flat_map()`: [`map`]'s closure returns
/// one item for each element, and `flat_map()`'s closure returns an
/// iterator for each element.
///
/// [`map`]: #method.map
+ /// [`flatten`]: #method.flatten
///
/// # Examples
///
fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
{
- FlatMap{iter: self, f: f, frontiter: None, backiter: None }
+ FlatMap { inner: flatten_compat(self.map(f)) }
+ }
+
+ /// Creates an iterator that flattens nested structure.
+ ///
+ /// This is useful when you have an iterator of iterators or an iterator of
+ /// things that can be turned into iterators and you want to remove one
+ /// level of indirection.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(iterator_flatten)]
+ ///
+ /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
+ /// let flattened = data.into_iter().flatten().collect::<Vec<u8>>();
+ /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);
+ /// ```
+ ///
+ /// Mapping and then flattening:
+ ///
+ /// ```
+ /// #![feature(iterator_flatten)]
+ ///
+ /// let words = ["alpha", "beta", "gamma"];
+ ///
+ /// // chars() returns an iterator
+ /// let merged: String = words.iter()
+ /// .map(|s| s.chars())
+ /// .flatten()
+ /// .collect();
+ /// assert_eq!(merged, "alphabetagamma");
+ /// ```
+ ///
+ /// You can also rewrite this in terms of [`flat_map()`] which is preferable
+ /// in this case since that conveys intent clearer:
+ ///
+ /// ```
+ /// let words = ["alpha", "beta", "gamma"];
+ ///
+ /// // chars() returns an iterator
+ /// let merged: String = words.iter()
+ /// .flat_map(|s| s.chars())
+ /// .collect();
+ /// assert_eq!(merged, "alphabetagamma");
+ /// ```
+ ///
+ /// Flattening once only removes one level of nesting:
+ ///
+ /// ```
+ /// #![feature(iterator_flatten)]
+ ///
+ /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
+ ///
+ /// let d2 = d3.iter().flatten().collect::<Vec<_>>();
+ /// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]);
+ ///
+ /// let d1 = d3.iter().flatten().flatten().collect::<Vec<_>>();
+ /// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]);
+ /// ```
+ ///
+ /// Here we see that `flatten()` does not perform a "deep" flatten.
+ /// Instead, only one level of nesting is removed. That is, if you
+ /// `flatten()` a three-dimensional array the result will be
+ /// two-dimensional and not one-dimensional. To get a one-dimensional
+ /// structure, you have to `flatten()` again.
+ #[inline]
+ #[unstable(feature = "iterator_flatten", issue = "48213")]
+ fn flatten(self) -> Flatten<Self>
+ where Self: Sized, Self::Item: IntoIterator {
+ Flatten { inner: flatten_compat(self) }
}
/// Creates an iterator which ends after the first [`None`].
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
pub struct FlatMap<I, U: IntoIterator, F> {
- iter: I,
- f: F,
- frontiter: Option<U::IntoIter>,
- backiter: Option<U::IntoIter>,
+ inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Clone, U: Clone + IntoIterator, F: Clone> Clone for FlatMap<I, U, F>
+ where <U as IntoIterator>::IntoIter: Clone
+{
+ fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where U::IntoIter: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("FlatMap")
- .field("iter", &self.iter)
- .field("frontiter", &self.frontiter)
- .field("backiter", &self.backiter)
- .finish()
+ f.debug_struct("FlatMap").field("inner", &self.inner).finish()
}
}
{
type Item = U::Item;
+ #[inline]
+ fn next(&mut self) -> Option<U::Item> { self.inner.next() }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+ Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+ {
+ self.inner.try_fold(init, fold)
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.inner.fold(init, fold)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
+ where F: FnMut(I::Item) -> U,
+ U: IntoIterator,
+ U::IntoIter: DoubleEndedIterator
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+ Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+ {
+ self.inner.try_rfold(init, fold)
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.inner.rfold(init, fold)
+ }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U, F> FusedIterator for FlatMap<I, U, F>
+ where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
+
+/// An iterator that flattens one level of nesting in an iterator of things
+/// that can be turned into iterators.
+///
+/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`flatten`]: trait.Iterator.html#method.flatten
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
+pub struct Flatten<I: Iterator>
+where I::Item: IntoIterator {
+ inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
+}
+
+#[unstable(feature = "iterator_flatten", issue = "48213")]
+impl<I, U> fmt::Debug for Flatten<I>
+ where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Flatten").field("inner", &self.inner).finish()
+ }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "48213")]
+impl<I, U> Clone for Flatten<I>
+ where I: Iterator + Clone, U: Iterator + Clone,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
+{
+ fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "48213")]
+impl<I, U> Iterator for Flatten<I>
+ where I: Iterator, U: Iterator,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+{
+ type Item = U::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<U::Item> { self.inner.next() }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+ Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+ {
+ self.inner.try_fold(init, fold)
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.inner.fold(init, fold)
+ }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "48213")]
+impl<I, U> DoubleEndedIterator for Flatten<I>
+ where I: DoubleEndedIterator, U: DoubleEndedIterator,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+ Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+ {
+ self.inner.try_rfold(init, fold)
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.inner.rfold(init, fold)
+ }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U> FusedIterator for Flatten<I>
+ where I: FusedIterator, U: Iterator,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
+
+/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
+fn flatten_compat<I, U>(iter: I) -> FlattenCompat<I, U> {
+ FlattenCompat { iter, frontiter: None, backiter: None }
+}
+
+/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
+/// this type.
+#[derive(Clone, Debug)]
+struct FlattenCompat<I, U> {
+ iter: I,
+ frontiter: Option<U>,
+ backiter: Option<U>,
+}
+
+impl<I, U> Iterator for FlattenCompat<I, U>
+ where I: Iterator, U: Iterator,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+{
+ type Item = U::Item;
+
#[inline]
fn next(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.frontiter {
- if let Some(x) = inner.by_ref().next() {
- return Some(x)
- }
+ if let elt@Some(_) = inner.next() { return elt }
}
- match self.iter.next().map(&mut self.f) {
+ match self.iter.next() {
None => return self.backiter.as_mut().and_then(|it| it.next()),
- next => self.frontiter = next.map(IntoIterator::into_iter),
+ Some(inner) => self.frontiter = Some(inner.into_iter()),
}
}
}
self.frontiter = None;
{
- let f = &mut self.f;
let frontiter = &mut self.frontiter;
init = self.iter.try_fold(init, |acc, x| {
- let mut mid = f(x).into_iter();
+ let mut mid = x.into_iter();
let r = mid.try_fold(acc, &mut fold);
*frontiter = Some(mid);
r
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.frontiter.into_iter()
- .chain(self.iter.map(self.f).map(U::into_iter))
+ .chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.fold(init, |acc, iter| iter.fold(acc, &mut fold))
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> where
- F: FnMut(I::Item) -> U,
- U: IntoIterator,
- U::IntoIter: DoubleEndedIterator
+impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
+ where I: DoubleEndedIterator, U: DoubleEndedIterator,
+ I::Item: IntoIterator<IntoIter = U, Item = U::Item>
{
#[inline]
fn next_back(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.backiter {
- if let Some(y) = inner.next_back() {
- return Some(y)
- }
+ if let elt@Some(_) = inner.next_back() { return elt }
}
- match self.iter.next_back().map(&mut self.f) {
+ match self.iter.next_back() {
None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
next => self.backiter = next.map(IntoIterator::into_iter),
}
self.backiter = None;
{
- let f = &mut self.f;
let backiter = &mut self.backiter;
init = self.iter.try_rfold(init, |acc, x| {
- let mut mid = f(x).into_iter();
+ let mut mid = x.into_iter();
let r = mid.try_rfold(acc, &mut fold);
*backiter = Some(mid);
r
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.frontiter.into_iter()
- .chain(self.iter.map(self.f).map(U::into_iter))
+ .chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
}
}
-#[unstable(feature = "fused", issue = "35602")]
-impl<I, U, F> FusedIterator for FlatMap<I, U, F>
- where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
-
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
#![feature(doc_spotlight)]
#![feature(rustc_const_unstable)]
#![feature(iterator_repeat_with)]
+#![feature(iterator_flatten)]
#[prelude_import]
#[allow(unused)]
assert_eq!(i, 0);
}
+#[test]
+fn test_iterator_flatten() {
+ let xs = [0, 3, 6];
+ let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
+ let mut i = 0;
+ for x in it {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
+
+/// Test `Flatten::fold` with items already picked off the front and back,
+/// to make sure all parts of the `Flatten` are folded correctly.
+#[test]
+fn test_iterator_flatten_fold() {
+ let xs = [0, 3, 6];
+ let ys = [1, 2, 3, 4, 5, 6, 7];
+ let mut it = xs.iter().map(|&x| x..x+3).flatten();
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.fold(0, |i, x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let mut it = xs.iter().map(|&x| x..x+3).flatten();
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.rfold(ys.len(), |i, x| {
+ assert_eq!(x, ys[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
#[test]
fn test_inspect() {
let xs = [1, 2, 3, 4];
assert_eq!(it.next_back(), None);
}
+#[test]
+fn test_double_ended_flatten() {
+ let u = [0,1];
+ let v = [5,6,7,8];
+ let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &5);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next_back(), None);
+}
+
#[test]
fn test_double_ended_range() {
assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
assert_eq!(iter.try_rfold(0, i8::checked_add), None);
assert_eq!(iter.next_back(), Some(35));
}
+
+#[test]
+fn test_flatten_try_folds() {
+ let f = &|acc, x| i32::checked_add(acc*2/3, x);
+ let mr = &|x| (5*x)..(5*x + 5);
+ assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
+ assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
+ let mut iter = (0..10).map(mr).flatten();
+ iter.next(); iter.next_back(); // have front and back iters in progress
+ assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+ let mut iter = (0..10).map(|x| (4*x)..(4*x + 4)).flatten();
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(17));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_functor_laws() {
+ // identity:
+ fn identity<T>(x: T) -> T { x }
+ assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
+
+ // composition:
+ fn f(x: usize) -> usize { x + 3 }
+ fn g(x: usize) -> usize { x * 2 }
+ fn h(x: usize) -> usize { g(f(x)) }
+ assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
+}
+
+#[test]
+fn test_monad_laws_left_identity() {
+ fn f(x: usize) -> impl Iterator<Item = usize> {
+ (0..10).map(move |y| x * y)
+ }
+ assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
+}
+
+#[test]
+fn test_monad_laws_right_identity() {
+ assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
+}
+
+#[test]
+fn test_monad_laws_associativity() {
+ fn f(x: usize) -> impl Iterator<Item = usize> { 0..x }
+ fn g(x: usize) -> impl Iterator<Item = usize> { (0..x).rev() }
+ assert_eq!((0..10).flat_map(f).flat_map(g).sum::<usize>(),
+ (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>());
+}
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iterator_try_fold)]
+#![feature(iterator_flatten)]
+#![feature(conservative_impl_trait)]
#![feature(iter_rfind)]
#![feature(iter_rfold)]
#![feature(iterator_repeat_with)]
[eval_always] CollectAndPartitionTranslationItems,
[] ExportName(DefId),
[] ContainsExternIndicator(DefId),
- [] IsTranslatedFunction(DefId),
+ [] IsTranslatedItem(DefId),
[] CodegenUnit(InternedString),
[] CompileCodegenUnit(InternedString),
[input] OutputFilenames,
/// nodes and edges as well as all fingerprints of nodes that have them.
previous: PreviousDepGraph,
- colors: RefCell<FxHashMap<DepNode, DepNodeColor>>,
+ colors: RefCell<DepNodeColorMap>,
/// When we load, there may be `.o` files, cached mir, or other such
/// things available to us. If we find that they are not dirty, we
// Pre-allocate the fingerprints array. We over-allocate a little so
// that we hopefully don't have to re-allocate during this compilation
// session.
+ let prev_graph_node_count = prev_graph.node_count();
+
let fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO,
- (prev_graph.node_count() * 115) / 100);
+ (prev_graph_node_count * 115) / 100);
DepGraph {
data: Some(Rc::new(DepGraphData {
previous_work_products: RefCell::new(FxHashMap()),
dep_node_debug: RefCell::new(FxHashMap()),
current: RefCell::new(CurrentDepGraph::new()),
previous: prev_graph,
- colors: RefCell::new(FxHashMap()),
+ colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)),
loaded_from_cache: RefCell::new(FxHashMap()),
})),
fingerprints: Rc::new(RefCell::new(fingerprints)),
R: HashStable<HCX>,
{
if let Some(ref data) = self.data {
- debug_assert!(!data.colors.borrow().contains_key(&key));
-
push(&data.current, key);
if cfg!(debug_assertions) {
profq_msg(ProfileQueriesMsg::TaskBegin(key.clone()))
}
// Determine the color of the new DepNode.
- {
- let prev_fingerprint = data.previous.fingerprint_of(&key);
+ if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
+ let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
- let color = if Some(current_fingerprint) == prev_fingerprint {
+ let color = if current_fingerprint == prev_fingerprint {
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};
- let old_value = data.colors.borrow_mut().insert(key, color);
- debug_assert!(old_value.is_none(),
+ let mut colors = data.colors.borrow_mut();
+ debug_assert!(colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
insertion for {:?}", key);
+
+ colors.insert(prev_index, color);
}
(result, dep_node_index)
let mut fingerprints = self.fingerprints.borrow_mut();
let dep_node_index = DepNodeIndex::new(fingerprints.len());
fingerprints.push(fingerprint);
+
debug_assert!(fingerprints[dep_node_index] == fingerprint,
"DepGraph::with_task() - Assigned fingerprint to \
unexpected index for {:?}", key);
+
(result, dep_node_index)
} else {
(task(cx, arg), DepNodeIndex::INVALID)
.unwrap()
}
+ #[inline]
+ pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
+ if let Some(ref data) = self.data {
+ data.current.borrow_mut().node_to_node_index.contains_key(dep_node)
+ } else {
+ false
+ }
+ }
+
#[inline]
pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
match self.fingerprints.borrow().get(dep_node_index) {
}
pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
- self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned())
+ if let Some(ref data) = self.data {
+ if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
+ return data.colors.borrow().get(prev_index)
+ } else {
+ // This is a node that did not exist in the previous compilation
+ // session, so we consider it to be red.
+ return Some(DepNodeColor::Red)
+ }
+ }
+
+ None
}
pub fn try_mark_green<'tcx>(&self,
debug!("try_mark_green({:?}) - BEGIN", dep_node);
let data = self.data.as_ref().unwrap();
- debug_assert!(!data.colors.borrow().contains_key(dep_node));
debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
if dep_node.kind.is_input() {
}
};
+ debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
+
let mut current_deps = Vec::new();
for &dep_dep_node_index in prev_deps {
- let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
+ let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
- let dep_dep_node_color = data.colors.borrow().get(dep_dep_node).cloned();
match dep_dep_node_color {
Some(DepNodeColor::Green(node_index)) => {
// This dependency has been marked as green before, we are
// still fine and can continue with checking the other
// dependencies.
debug!("try_mark_green({:?}) --- found dependency {:?} to \
- be immediately green", dep_node, dep_dep_node);
+ be immediately green",
+ dep_node,
+ data.previous.index_to_node(dep_dep_node_index));
current_deps.push(node_index);
}
Some(DepNodeColor::Red) => {
// mark the DepNode as green and also don't need to bother
// with checking any of the other dependencies.
debug!("try_mark_green({:?}) - END - dependency {:?} was \
- immediately red", dep_node, dep_dep_node);
+ immediately red",
+ dep_node,
+ data.previous.index_to_node(dep_dep_node_index));
return None
}
None => {
+ let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
+
// We don't know the state of this dependency. If it isn't
// an input node, let's try to mark it green recursively.
if !dep_dep_node.kind.is_input() {
debug!("try_mark_green({:?}) --- trying to force \
dependency {:?}", dep_node, dep_dep_node);
if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) {
- let dep_dep_node_color = data.colors
- .borrow()
- .get(dep_dep_node)
- .cloned();
+ let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
+
match dep_dep_node_color {
Some(DepNodeColor::Green(node_index)) => {
debug!("try_mark_green({:?}) --- managed to \
}
// ... and finally storing a "Green" entry in the color map.
- let old_color = data.colors
- .borrow_mut()
- .insert(*dep_node, DepNodeColor::Green(dep_node_index));
- debug_assert!(old_color.is_none(),
+ let mut colors = data.colors.borrow_mut();
+ debug_assert!(colors.get(prev_dep_node_index).is_none(),
"DepGraph::try_mark_green() - Duplicate DepNodeColor \
insertion for {:?}", dep_node);
+ colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
+
debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
Some(dep_node_index)
}
- // Used in various assertions
- pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool {
- let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index];
- self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| {
- match color {
- DepNodeColor::Red => false,
- DepNodeColor::Green(_) => true,
- }
- }).unwrap_or(false)
+ // Returns true if the given node has been marked as green during the
+ // current compilation session. Used in various assertions
+ pub fn is_green(&self, dep_node: &DepNode) -> bool {
+ self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false)
}
// This method loads all on-disk cacheable query results into memory, so
pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let green_nodes: Vec<DepNode> = {
let data = self.data.as_ref().unwrap();
- data.colors.borrow().iter().filter_map(|(dep_node, color)| match color {
- DepNodeColor::Green(_) => {
- if dep_node.cache_on_disk(tcx) {
- Some(*dep_node)
- } else {
+ let colors = data.colors.borrow();
+ colors.values.indices().filter_map(|prev_index| {
+ match colors.get(prev_index) {
+ Some(DepNodeColor::Green(_)) => {
+ let dep_node = data.previous.index_to_node(prev_index);
+ if dep_node.cache_on_disk(tcx) {
+ Some(dep_node)
+ } else {
+ None
+ }
+ }
+ None |
+ Some(DepNodeColor::Red) => {
+ // We can skip red nodes because a node can only be marked
+ // as red if the query result was recomputed and thus is
+ // already in memory.
None
}
}
- DepNodeColor::Red => {
- // We can skip red nodes because a node can only be marked
- // as red if the query result was recomputed and thus is
- // already in memory.
- None
- }
}).collect()
};
node: DepNode,
},
}
+
+// A data structure that stores Option<DepNodeColor> values as a contiguous
+// array, using one u32 per entry.
+struct DepNodeColorMap {
+ values: IndexVec<SerializedDepNodeIndex, u32>,
+}
+
+const COMPRESSED_NONE: u32 = 0;
+const COMPRESSED_RED: u32 = 1;
+const COMPRESSED_FIRST_GREEN: u32 = 2;
+
+impl DepNodeColorMap {
+ fn new(size: usize) -> DepNodeColorMap {
+ DepNodeColorMap {
+ values: IndexVec::from_elem_n(COMPRESSED_NONE, size)
+ }
+ }
+
+ fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
+ match self.values[index] {
+ COMPRESSED_NONE => None,
+ COMPRESSED_RED => Some(DepNodeColor::Red),
+ value => Some(DepNodeColor::Green(DepNodeIndex(value - COMPRESSED_FIRST_GREEN)))
+ }
+ }
+
+ fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) {
+ self.values[index] = match color {
+ DepNodeColor::Red => COMPRESSED_RED,
+ DepNodeColor::Green(index) => index.0 + COMPRESSED_FIRST_GREEN,
+ }
+ }
+}
self.index[dep_node]
}
+ #[inline]
+ pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
+ self.index.get(dep_node).cloned()
+ }
+
#[inline]
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
self.index
// Desugar ExprIfLet
// From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
- ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
+ ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
// to:
//
// match <sub_expr> {
{
let body = self.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new()));
- let pat = self.lower_pat(pat);
- arms.push(self.arm(hir_vec![pat], body_expr));
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ arms.push(self.arm(pats, body_expr));
}
// _ => [<else_opt>|()]
// Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
- ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
+ ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
// to:
//
// [opt_ident]: loop {
// `<pat> => <body>`
let pat_arm = {
let body_expr = P(self.expr_block(body, ThinVec::new()));
- let pat = self.lower_pat(pat);
- self.arm(hir_vec![pat], body_expr)
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ self.arm(pats, body_expr)
};
// `_ => break`
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID};
use syntax::codemap::Spanned;
+use syntax::ext::base::MacroKind;
use syntax_pos::Span;
use hir::*;
use arena::TypedArena;
use std::cell::RefCell;
use std::io;
+use ty::TyCtxt;
pub mod blocks;
mod collector;
pub mod definitions;
mod hir_id_validator;
+
pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low;
pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High;
self.definitions.as_local_node_id(def_id.to_def_id()).unwrap()
}
+ pub fn describe_def(&self, node_id: NodeId) -> Option<Def> {
+ let node = if let Some(node) = self.find(node_id) {
+ node
+ } else {
+ return None
+ };
+
+ match node {
+ NodeItem(item) => {
+ let def_id = || {
+ self.local_def_id(item.id)
+ };
+
+ match item.node {
+ ItemStatic(_, m, _) => Some(Def::Static(def_id(),
+ m == MutMutable)),
+ ItemConst(..) => Some(Def::Const(def_id())),
+ ItemFn(..) => Some(Def::Fn(def_id())),
+ ItemMod(..) => Some(Def::Mod(def_id())),
+ ItemGlobalAsm(..) => Some(Def::GlobalAsm(def_id())),
+ ItemTy(..) => Some(Def::TyAlias(def_id())),
+ ItemEnum(..) => Some(Def::Enum(def_id())),
+ ItemStruct(..) => Some(Def::Struct(def_id())),
+ ItemUnion(..) => Some(Def::Union(def_id())),
+ ItemTrait(..) => Some(Def::Trait(def_id())),
+ ItemTraitAlias(..) => {
+ bug!("trait aliases are not yet implemented (see issue #41517)")
+ },
+ ItemExternCrate(_) |
+ ItemUse(..) |
+ ItemForeignMod(..) |
+ ItemImpl(..) => None,
+ }
+ }
+ NodeForeignItem(item) => {
+ let def_id = self.local_def_id(item.id);
+ match item.node {
+ ForeignItemFn(..) => Some(Def::Fn(def_id)),
+ ForeignItemStatic(_, m) => Some(Def::Static(def_id, m)),
+ ForeignItemType => Some(Def::TyForeign(def_id)),
+ }
+ }
+ NodeTraitItem(item) => {
+ let def_id = self.local_def_id(item.id);
+ match item.node {
+ TraitItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
+ TraitItemKind::Method(..) => Some(Def::Method(def_id)),
+ TraitItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
+ }
+ }
+ NodeImplItem(item) => {
+ let def_id = self.local_def_id(item.id);
+ match item.node {
+ ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
+ ImplItemKind::Method(..) => Some(Def::Method(def_id)),
+ ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
+ }
+ }
+ NodeVariant(variant) => {
+ let def_id = self.local_def_id(variant.node.data.id());
+ Some(Def::Variant(def_id))
+ }
+ NodeField(_) |
+ NodeExpr(_) |
+ NodeStmt(_) |
+ NodeTy(_) |
+ NodeTraitRef(_) |
+ NodePat(_) |
+ NodeBinding(_) |
+ NodeStructCtor(_) |
+ NodeLifetime(_) |
+ NodeVisibility(_) |
+ NodeBlock(_) => None,
+ NodeLocal(local) => {
+ Some(Def::Local(local.id))
+ }
+ NodeMacroDef(macro_def) => {
+ Some(Def::Macro(self.local_def_id(macro_def.id),
+ MacroKind::Bang))
+ }
+ NodeTyParam(param) => {
+ Some(Def::TyParam(self.local_def_id(param.id)))
+ }
+ }
+ }
+
fn entry_count(&self) -> usize {
self.map.len()
}
}
}
}
+
+pub fn describe_def(tcx: TyCtxt, def_id: DefId) -> Option<Def> {
+ if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
+ tcx.hir.describe_def(node_id)
+ } else {
+ bug!("Calling local describe_def query provider for upstream DefId: {:?}",
+ def_id)
+ }
+}
use syntax::util::ThinVec;
use syntax::util::parser::ExprPrecedence;
use ty::AdtKind;
+use ty::maps::Providers;
use rustc_data_structures::indexed_vec;
// Map from the NodeId of a glob import to a list of items which are actually
// imported.
pub type GlobMap = NodeMap<FxHashSet<Name>>;
+
+
+pub fn provide(providers: &mut Providers) {
+ providers.describe_def = map::describe_def;
+}
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
- self.as_type().hash_stable(hcx, hasher);
- self.as_region().hash_stable(hcx, hasher);
+ self.unpack().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'gcx> HashStable<StableHashingContext<'gcx>>
+for ty::subst::UnpackedKind<'gcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'gcx>,
+ hasher: &mut StableHasher<W>) {
+ match self {
+ ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
+ ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
+ }
}
}
use ty::{self, Ty};
use ty::fold::{BottomUpFolder, TypeFoldable};
use ty::outlives::Component;
-use ty::subst::{Kind, Substs};
+use ty::subst::{Kind, UnpackedKind, Substs};
use util::nodemap::DefIdMap;
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
let index = region_def.index as usize;
// Get the value supplied for this region from the substs.
- let subst_arg = anon_defn.substs[index].as_region().unwrap();
+ let subst_arg = anon_defn.substs.region_at(index);
// Compute the least upper bound of it with the other regions.
debug!("constrain_anon_types: least_region={:?}", least_region);
// All other regions, we map them appropriately to their adjusted
// indices, erroring if we find any lifetimes that were not mapped
// into the new set.
- _ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) {
+ _ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into())
+ .map(|k| k.unpack()) {
r1
} else {
// No mapping was found. This means that
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use hir::def_id::DefId;
use syntax::ast::NodeId;
use syntax::symbol::InternedString;
use ty::{Instance, TyCtxt};
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum MonoItem<'tcx> {
Fn(Instance<'tcx>),
- Static(NodeId),
+ Static(DefId),
GlobalAsm(NodeId),
}
MonoItem::Fn(ref instance) => {
instance.hash_stable(hcx, hasher);
}
- MonoItem::Static(node_id) |
+ MonoItem::Static(def_id) => {
+ def_id.hash_stable(hcx, hasher);
+ }
MonoItem::GlobalAsm(node_id) => {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
node_id.hash_stable(hcx, hasher);
}).collect(),
ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))],
};
- if found.len()== expected.len() {
+ if found.len() == expected.len() {
self.report_closure_arg_mismatch(span,
found_span,
found_trait_ref,
_ => ArgKind::Arg("_".to_owned(), "_".to_owned())
}).collect::<Vec<ArgKind>>())
}
+ hir::map::NodeVariant(&hir::Variant {
+ span,
+ node: hir::Variant_ {
+ data: hir::VariantData::Tuple(ref fields, _),
+ ..
+ },
+ ..
+ }) => {
+ (self.tcx.sess.codemap().def_span(span),
+ fields.iter().map(|field| {
+ ArgKind::Arg(format!("{}", field.name), "_".to_string())
+ }).collect::<Vec<_>>())
+ }
_ => panic!("non-FnLike node found: {:?}", node),
}
}
/// either identifying an `impl` (e.g., `impl Eq for int`) that
/// provides the required vtable, or else finding a bound that is in
/// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Obligation<'tcx, T> {
pub cause: ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
/// Why did we incur this obligation? Used for error reporting.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ObligationCause<'tcx> {
pub span: Span,
}
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from span.
MiscObligation,
BlockTailExpression(ast::NodeId),
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DerivedObligationCause<'tcx> {
/// The trait reference of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
/// ### The type parameter `N`
///
/// See explanation on `VtableImplData`.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
pub nested: Vec<N>
}
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct VtableAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>
}
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct VtableBuiltinData<N> {
pub nested: Vec<N>
}
use super::Obligation;
use super::ObligationCause;
use super::PredicateObligation;
+use super::Selection;
use super::SelectionContext;
use super::SelectionError;
use super::VtableClosureData;
pub err: ty::error::TypeError<'tcx>
}
-#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(PartialEq, Eq, Debug)]
enum ProjectionTyCandidate<'tcx> {
// from a where-clause in the env or object type
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
TraitDef(ty::PolyProjectionPredicate<'tcx>),
// from a "impl" (or a "pseudo-impl" returned by select)
- Select,
+ Select(Selection<'tcx>),
}
-struct ProjectionTyCandidateSet<'tcx> {
- vec: Vec<ProjectionTyCandidate<'tcx>>,
- ambiguous: bool
+enum ProjectionTyCandidateSet<'tcx> {
+ None,
+ Single(ProjectionTyCandidate<'tcx>),
+ Ambiguous,
+ Error(SelectionError<'tcx>),
+}
+
+impl<'tcx> ProjectionTyCandidateSet<'tcx> {
+ fn mark_ambiguous(&mut self) {
+ *self = ProjectionTyCandidateSet::Ambiguous;
+ }
+
+ fn mark_error(&mut self, err: SelectionError<'tcx>) {
+ *self = ProjectionTyCandidateSet::Error(err);
+ }
+
+ // Returns true if the push was successful, or false if the candidate
+ // was discarded -- this could be because of ambiguity, or because
+ // a higher-priority candidate is already there.
+ fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool {
+ use self::ProjectionTyCandidateSet::*;
+ use self::ProjectionTyCandidate::*;
+ match self {
+ None => {
+ *self = Single(candidate);
+ true
+ }
+ Single(current) => {
+ // No duplicates are expected.
+ assert_ne!(current, &candidate);
+ // Prefer where-clauses. As in select, if there are multiple
+ // candidates, we prefer where-clause candidates over impls. This
+ // may seem a bit surprising, since impls are the source of
+ // "truth" in some sense, but in fact some of the impls that SEEM
+ // applicable are not, because of nested obligations. Where
+ // clauses are the safer choice. See the comment on
+ // `select::SelectionCandidate` and #21974 for more details.
+ match (current, candidate) {
+ (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; }
+ (ParamEnv(..), _) => {}
+ (_, ParamEnv(..)) => { unreachable!(); }
+ (_, _) => { *self = Ambiguous; }
+ }
+ false
+ }
+ Ambiguous | Error(..) => {
+ false
+ }
+ }
+ }
}
/// Evaluates constraints of the form:
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
}
- let mut candidates = ProjectionTyCandidateSet {
- vec: Vec::new(),
- ambiguous: false,
- };
+ let mut candidates = ProjectionTyCandidateSet::None;
+ // Make sure that the following procedures are kept in order. ParamEnv
+ // needs to be first because it has highest priority, and Select checks
+ // the return value of push_candidate which assumes it's ran at last.
assemble_candidates_from_param_env(selcx,
obligation,
&obligation_trait_ref,
&obligation_trait_ref,
&mut candidates);
- if let Err(e) = assemble_candidates_from_impls(selcx,
- obligation,
- &obligation_trait_ref,
- &mut candidates) {
- return Err(ProjectionTyError::TraitSelectionError(e));
- }
-
- debug!("{} candidates, ambiguous={}",
- candidates.vec.len(),
- candidates.ambiguous);
-
- // Inherent ambiguity that prevents us from even enumerating the
- // candidates.
- if candidates.ambiguous {
- return Err(ProjectionTyError::TooManyCandidates);
- }
-
- // Drop duplicates.
- //
- // Note: `candidates.vec` seems to be on the critical path of the
- // compiler. Replacing it with an HashSet was also tried, which would
- // render the following dedup unnecessary. The original comment indicated
- // that it was 9% slower, but that data is now obsolete and a new
- // benchmark should be performed.
- candidates.vec.sort_unstable();
- candidates.vec.dedup();
-
- // Prefer where-clauses. As in select, if there are multiple
- // candidates, we prefer where-clause candidates over impls. This
- // may seem a bit surprising, since impls are the source of
- // "truth" in some sense, but in fact some of the impls that SEEM
- // applicable are not, because of nested obligations. Where
- // clauses are the safer choice. See the comment on
- // `select::SelectionCandidate` and #21974 for more details.
- if candidates.vec.len() > 1 {
- debug!("retaining param-env candidates only from {:?}", candidates.vec);
- candidates.vec.retain(|c| match *c {
- ProjectionTyCandidate::ParamEnv(..) => true,
- ProjectionTyCandidate::TraitDef(..) |
- ProjectionTyCandidate::Select => false,
- });
- debug!("resulting candidate set: {:?}", candidates.vec);
- if candidates.vec.len() != 1 {
- return Err(ProjectionTyError::TooManyCandidates);
- }
- }
-
- assert!(candidates.vec.len() <= 1);
+ assemble_candidates_from_impls(selcx,
+ obligation,
+ &obligation_trait_ref,
+ &mut candidates);
+
+ match candidates {
+ ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
+ confirm_candidate(selcx,
+ obligation,
+ &obligation_trait_ref,
+ candidate))),
+ ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
+ selcx.tcx().mk_projection(
+ obligation.predicate.item_def_id,
+ obligation.predicate.substs))),
+ // Error occurred while trying to processing impls.
+ ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)),
+ // Inherent ambiguity that prevents us from even enumerating the
+ // candidates.
+ ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates),
- match candidates.vec.pop() {
- Some(candidate) => {
- Ok(ProjectedTy::Progress(
- confirm_candidate(selcx,
- obligation,
- &obligation_trait_ref,
- candidate)))
- }
- None => Ok(ProjectedTy::NoProgress(
- selcx.tcx().mk_projection(
- obligation.predicate.item_def_id,
- obligation.predicate.substs)))
}
}
ty::TyInfer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
- candidate_set.ambiguous = true;
+ candidate_set.mark_ambiguous();
return;
}
_ => { return; }
debug!("assemble_candidates_from_predicates: predicate={:?}",
predicate);
match predicate {
- ty::Predicate::Projection(ref data) => {
+ ty::Predicate::Projection(data) => {
let same_def_id =
data.0.projection_ty.item_def_id == obligation.predicate.item_def_id;
data, is_match, same_def_id);
if is_match {
- candidate_set.vec.push(ctor(data.clone()));
+ candidate_set.push_candidate(ctor(data));
}
}
- _ => { }
+ _ => {}
}
}
}
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
- -> Result<(), SelectionError<'tcx>>
{
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
- selcx.infcx().probe(|_| {
+ let _ = selcx.infcx().commit_if_ok(|_| {
let vtable = match selcx.select(&trait_obligation) {
Ok(Some(vtable)) => vtable,
Ok(None) => {
- candidate_set.ambiguous = true;
- return Ok(());
+ candidate_set.mark_ambiguous();
+ return Err(());
}
Err(e) => {
debug!("assemble_candidates_from_impls: selection error {:?}",
e);
- return Err(e);
+ candidate_set.mark_error(e);
+ return Err(());
}
};
- match vtable {
+ let eligible = match &vtable {
super::VtableClosure(_) |
super::VtableGenerator(_) |
super::VtableFnPointer(_) |
super::VtableObject(_) => {
debug!("assemble_candidates_from_impls: vtable={:?}",
vtable);
-
- candidate_set.vec.push(ProjectionTyCandidate::Select);
+ true
}
- super::VtableImpl(ref impl_data) => {
+ super::VtableImpl(impl_data) => {
// We have to be careful when projecting out of an
// impl because of specialization. If we are not in
// trans (i.e., projection mode is not "any"), and the
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default() ||
- selcx.tcx().impl_is_default(node_item.node.def_id())
+ selcx.tcx().impl_is_default(node_item.node.def_id())
};
// Only reveal a specializable default if we're past type-checking
// and the obligations is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
- let new_candidate = if !is_default {
- Some(ProjectionTyCandidate::Select)
+ if !is_default {
+ true
} else if obligation.param_env.reveal == Reveal::All {
assert!(!poly_trait_ref.needs_infer());
if !poly_trait_ref.needs_subst() {
- Some(ProjectionTyCandidate::Select)
+ true
} else {
- None
+ false
}
} else {
- None
- };
-
- candidate_set.vec.extend(new_candidate);
+ false
+ }
}
super::VtableParam(..) => {
// This case tell us nothing about the value of an
// in the compiler: a trait predicate (`T : SomeTrait`) and a
// projection. And the projection where clause is handled
// in `assemble_candidates_from_param_env`.
+ false
}
super::VtableAutoImpl(..) |
super::VtableBuiltin(..) => {
"Cannot project an associated type from `{:?}`",
vtable);
}
- }
+ };
- Ok(())
- })
+ if eligible {
+ if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) {
+ Ok(())
+ } else {
+ Err(())
+ }
+ } else {
+ Err(())
+ }
+ });
}
fn confirm_candidate<'cx, 'gcx, 'tcx>(
confirm_param_env_candidate(selcx, obligation, poly_projection)
}
- ProjectionTyCandidate::Select => {
- confirm_select_candidate(selcx, obligation, obligation_trait_ref)
+ ProjectionTyCandidate::Select(vtable) => {
+ confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable)
}
}
}
fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- obligation_trait_ref: &ty::TraitRef<'tcx>)
+ obligation_trait_ref: &ty::TraitRef<'tcx>,
+ vtable: Selection<'tcx>)
-> Progress<'tcx>
{
- let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
- let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
- let vtable = match selcx.select(&trait_obligation) {
- Ok(Some(vtable)) => vtable,
- _ => {
- span_bug!(
- obligation.cause.span,
- "Failed to select `{:?}`",
- trait_obligation);
- }
- };
-
match vtable {
super::VtableImpl(data) =>
confirm_impl_candidate(selcx, obligation, data),
use syntax::abi::Abi;
use hir;
use lint;
-use util::nodemap::FxHashMap;
+use util::nodemap::{FxHashMap, FxHashSet};
struct InferredObligationsSnapshotVecDelegate<'tcx> {
phantom: PhantomData<&'tcx i32>,
let trait_ref = &mut trait_pred.trait_ref;
let unit_substs = trait_ref.substs;
let mut never_substs = Vec::with_capacity(unit_substs.len());
- never_substs.push(From::from(tcx.types.never));
+ never_substs.push(tcx.types.never.into());
never_substs.extend(&unit_substs[1..]);
trait_ref.substs = tcx.intern_substs(&never_substs);
}
// unsized parameters is equal to the target.
let params = substs_a.iter().enumerate().map(|(i, &k)| {
if ty_params.contains(i) {
- Kind::from(substs_b.type_at(i))
+ substs_b.type_at(i).into()
} else {
k
}
// that order.
let predicates = tcx.predicates_of(def_id);
assert_eq!(predicates.parent, None);
- let predicates = predicates.predicates.iter().flat_map(|predicate| {
+ let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| {
let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
&predicate.subst(tcx, substs));
predicate.obligations.into_iter().chain(
predicate: predicate.value
}))
}).collect();
+ // We are performing deduplication here to avoid exponential blowups
+ // (#38528) from happening, but the real cause of the duplication is
+ // unknown. What we know is that the deduplication avoids exponential
+ // amount of predicates being propogated when processing deeply nested
+ // types.
+ let mut seen = FxHashSet();
+ predicates.retain(|i| seen.insert(i.clone()));
self.infcx().plug_leaks(skol_map, snapshot, predicates)
}
}
let sig = substs.closure_sig(closure_did, tcx);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
assert_eq!(sig.inputs().len(), 1);
- let substs = tcx.mk_substs([
- Kind::from(self_ty),
- Kind::from(sig.inputs()[0]),
- ].iter().cloned());
+ let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned());
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
Instance { def, substs }
[] fn export_name: ExportName(DefId) -> Option<Symbol>,
[] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
[] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel,
- [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool,
+ [] fn is_translated_item: IsTranslatedItem(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
[] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
[] fn output_filenames: output_filenames_node(CrateNum)
return None
};
- let mut cnum_map = self.cnum_map.borrow_mut();
- if cnum_map.is_none() {
+ // Initialize the cnum_map if it is not initialized yet.
+ if self.cnum_map.borrow().is_none() {
+ let mut cnum_map = self.cnum_map.borrow_mut();
*cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
}
-
- let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut();
- let mut file_index_to_file = self.file_index_to_file.borrow_mut();
+ let cnum_map = self.cnum_map.borrow();
let mut decoder = CacheDecoder {
tcx,
opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
codemap: self.codemap,
cnum_map: cnum_map.as_ref().unwrap(),
- file_index_to_file: &mut file_index_to_file,
+ file_index_to_file: &self.file_index_to_file,
file_index_to_stable_id: &self.file_index_to_stable_id,
- synthetic_expansion_infos: &mut synthetic_expansion_infos,
+ synthetic_expansion_infos: &self.synthetic_expansion_infos,
};
match decode_tagged(&mut decoder, dep_node_index) {
opaque: opaque::Decoder<'x>,
codemap: &'x CodeMap,
cnum_map: &'x IndexVec<CrateNum, Option<CrateNum>>,
- synthetic_expansion_infos: &'x mut FxHashMap<AbsoluteBytePos, SyntaxContext>,
- file_index_to_file: &'x mut FxHashMap<FileMapIndex, Rc<FileMap>>,
+ synthetic_expansion_infos: &'x RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
+ file_index_to_file: &'x RefCell<FxHashMap<FileMapIndex, Rc<FileMap>>>,
file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
}
impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
- fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc<FileMap> {
+ fn file_index_to_file(&self, index: FileMapIndex) -> Rc<FileMap> {
let CacheDecoder {
- ref mut file_index_to_file,
+ ref file_index_to_file,
ref file_index_to_stable_id,
ref codemap,
..
} = *self;
- file_index_to_file.entry(index).or_insert_with(|| {
+ file_index_to_file.borrow_mut().entry(index).or_insert_with(|| {
let stable_id = file_index_to_stable_id[&index];
codemap.filemap_by_stable_id(stable_id)
.expect("Failed to lookup FileMap in new context.")
let pos = AbsoluteBytePos::new(self.opaque.position());
let expn_info: ExpnInfo = Decodable::decode(self)?;
let ctxt = SyntaxContext::allocate_directly(expn_info);
- self.synthetic_expansion_infos.insert(pos, ctxt);
+ self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt);
ctxt
}
TAG_EXPANSION_INFO_SHORTHAND => {
let pos = AbsoluteBytePos::decode(self)?;
- if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() {
+ let cached_ctxt = self.synthetic_expansion_infos
+ .borrow()
+ .get(&pos)
+ .cloned();
+
+ if let Some(ctxt) = cached_ctxt {
ctxt
} else {
let expn_info = self.with_position(pos.to_usize(), |this| {
ExpnInfo::decode(this)
})?;
let ctxt = SyntaxContext::allocate_directly(expn_info);
- self.synthetic_expansion_infos.insert(pos, ctxt);
+ self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt);
ctxt
}
}
let span = self.sess.codemap().def_span(span);
let mut err =
struct_span_err!(self.sess, span, E0391,
- "unsupported cyclic reference between types/traits detected");
+ "cyclic dependency detected");
err.span_label(span, "cyclic reference");
err.span_note(self.sess.codemap().def_span(stack[0].0),
}
match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) {
Some(dep_node_index) => {
- debug_assert!(self.dep_graph.is_green(dep_node_index));
+ debug_assert!(self.dep_graph.is_green(&dep_node));
self.dep_graph.read_index(dep_node_index);
Some(dep_node_index)
}
dep_node: &DepNode)
-> Result<$V, CycleError<'a, $tcx>>
{
- debug_assert!(tcx.dep_graph.is_green(dep_node_index));
+ debug_assert!(tcx.dep_graph.is_green(dep_node));
// First we try to load the result from the on-disk cache
let result = if Self::cache_on_disk(key) &&
span: Span,
dep_node: DepNode)
-> Result<($V, DepNodeIndex), CycleError<'a, $tcx>> {
- debug_assert!(tcx.dep_graph.node_color(&dep_node).is_none());
+ debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node));
profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin);
let res = tcx.cycle_check(span, Query::$name(key), || {
DepKind::ContainsExternIndicator => {
force!(contains_extern_indicator, def_id!());
}
- DepKind::IsTranslatedFunction => { force!(is_translated_function, def_id!()); }
+ DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); }
DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); }
DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); }
use serialize::{self, Encodable, Encoder};
use std::cell::RefCell;
use std::cmp;
-use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
}
}
-impl<'tcx> Ord for TyS<'tcx> {
- #[inline]
- fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
- // (self as *const _).cmp(other as *const _)
- (self as *const TyS<'tcx>).cmp(&(other as *const TyS<'tcx>))
- }
-}
-impl<'tcx> PartialOrd for TyS<'tcx> {
- #[inline]
- fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
impl<'tcx> TyS<'tcx> {
pub fn is_primitive_ty(&self) -> bool {
match self.sty {
}
impl<T> Eq for Slice<T> {}
-impl<T> Ord for Slice<T> {
- #[inline]
- fn cmp(&self, other: &Slice<T>) -> Ordering {
- (&self.0 as *const [T]).cmp(&(&other.0 as *const [T]))
- }
-}
-impl<T> PartialOrd for Slice<T> {
- #[inline]
- fn partial_cmp(&self, other: &Slice<T>) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
impl<T> Hash for Slice<T> {
fn hash<H: Hasher>(&self, s: &mut H) {
(self.as_ptr(), self.len()).hash(s)
/// equality between arbitrary types. Processing an instance of
/// Form #2 eventually yields one of these `ProjectionPredicate`
/// instances to normalize the LHS.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct ProjectionPredicate<'tcx> {
pub projection_ty: ProjectionTy<'tcx>,
pub ty: Ty<'tcx>,
}
}
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AdtKind { Struct, Union, Enum }
bitflags! {
use hir::def_id::DefId;
use middle::const_val::ConstVal;
use traits::Reveal;
-use ty::subst::{Kind, Substs};
+use ty::subst::{UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::{TypeVisitor, TypeFolder};
use ty::error::{ExpectedFound, TypeError};
let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
let variance = variances.map_or(ty::Invariant, |v| v[i]);
- if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) {
- Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?))
- } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) {
- Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?))
- } else {
- bug!()
+ match (a.unpack(), b.unpack()) {
+ (UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => {
+ Ok(relation.relate_with_variance(variance, &a_lt, &b_lt)?.into())
+ }
+ (UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
+ Ok(relation.relate_with_variance(variance, &a_ty, &b_ty)?.into())
+ }
+ (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
}
});
use middle::const_val::ConstVal;
use middle::region;
use rustc_data_structures::indexed_vec::Idx;
-use ty::subst::{Substs, Subst};
+use ty::subst::{Substs, Subst, Kind, UnpackedKind};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
-use ty::subst::Kind;
use std::iter;
use std::cmp::Ordering;
let generics = tcx.generics_of(def_id);
let parent_len = generics.parent_count();
SplitClosureSubsts {
- closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"),
- closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"),
+ closure_kind_ty: self.substs.type_at(parent_len),
+ closure_sig_ty: self.substs.type_at(parent_len + 1),
upvar_kinds: &self.substs[parent_len + 2..],
}
}
impl Iterator<Item=Ty<'tcx>> + 'tcx
{
let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
- upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
+ upvar_kinds.iter().map(|t| {
+ if let UnpackedKind::Type(ty) = t.unpack() {
+ ty
+ } else {
+ bug!("upvar should be type")
+ }
+ })
}
/// Returns the closure kind for this closure; may return a type
ty::TraitRef {
def_id: self.def_id,
substs: tcx.mk_substs(
- iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned()))
+ iter::once(self_ty.into()).chain(self.substs.iter().cloned()))
}
}
}
/// erase, or otherwise "discharge" these bound regions, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Binder<T>(pub T);
impl<T> Binder<T> {
/// Represents the projection of an associated type. In explicit UFCS
/// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct ProjectionTy<'tcx> {
/// The parameters of the associated item.
pub substs: &'tcx Substs<'tcx>,
projection_ty: ty::ProjectionTy {
item_def_id: self.item_def_id,
substs: tcx.mk_substs(
- iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())),
+ iter::once(self_ty.into()).chain(self.substs.iter().cloned())),
},
ty: self.ty,
}
use syntax_pos::{Span, DUMMY_SP};
use rustc_data_structures::accumulate_vec::AccumulateVec;
+use core::intrinsics;
use core::nonzero::NonZero;
use std::fmt;
use std::iter;
/// To reduce memory usage, a `Kind` is a interned pointer,
/// with the lowest 2 bits being reserved for a tag to
/// indicate the type (`Ty` or `Region`) it points to.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Kind<'tcx> {
ptr: NonZero<usize>,
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
const TYPE_TAG: usize = 0b00;
const REGION_TAG: usize = 0b01;
-impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
- fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
- // Ensure we can use the tag bits.
- assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+pub enum UnpackedKind<'tcx> {
+ Lifetime(ty::Region<'tcx>),
+ Type(Ty<'tcx>),
+}
+
+impl<'tcx> UnpackedKind<'tcx> {
+ fn pack(self) -> Kind<'tcx> {
+ let (tag, ptr) = match self {
+ UnpackedKind::Lifetime(lt) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
+ (REGION_TAG, lt as *const _ as usize)
+ }
+ UnpackedKind::Type(ty) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+ (TYPE_TAG, ty as *const _ as usize)
+ }
+ };
- let ptr = ty as *const _ as usize;
Kind {
ptr: unsafe {
- NonZero::new_unchecked(ptr | TYPE_TAG)
+ NonZero::new_unchecked(ptr | tag)
},
marker: PhantomData
}
impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
fn from(r: ty::Region<'tcx>) -> Kind<'tcx> {
- // Ensure we can use the tag bits.
- assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
+ UnpackedKind::Lifetime(r).pack()
+ }
+}
- let ptr = r as *const _ as usize;
- Kind {
- ptr: unsafe {
- NonZero::new_unchecked(ptr | REGION_TAG)
- },
- marker: PhantomData
- }
+impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
+ fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
+ UnpackedKind::Type(ty).pack()
}
}
impl<'tcx> Kind<'tcx> {
#[inline]
- unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
+ pub fn unpack(self) -> UnpackedKind<'tcx> {
let ptr = self.ptr.get();
- if ptr & TAG_MASK == tag {
- Some(&*((ptr & !TAG_MASK) as *const _))
- } else {
- None
- }
- }
-
- #[inline]
- pub fn as_type(self) -> Option<Ty<'tcx>> {
- unsafe {
- self.downcast(TYPE_TAG)
- }
- }
-
- #[inline]
- pub fn as_region(self) -> Option<ty::Region<'tcx>> {
unsafe {
- self.downcast(REGION_TAG)
+ match ptr & TAG_MASK {
+ REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
+ TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
+ _ => intrinsics::unreachable()
+ }
}
}
}
impl<'tcx> fmt::Debug for Kind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- if let Some(ty) = self.as_type() {
- write!(f, "{:?}", ty)
- } else if let Some(r) = self.as_region() {
- write!(f, "{:?}", r)
- } else {
- write!(f, "<unknown @ {:p}>", self.ptr.get() as *const ())
+ match self.unpack() {
+ UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
+ UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
}
}
}
impl<'tcx> fmt::Display for Kind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- if let Some(ty) = self.as_type() {
- write!(f, "{}", ty)
- } else if let Some(r) = self.as_region() {
- write!(f, "{}", r)
- } else {
- // FIXME(RFC 2000): extend this if/else chain when we support const generic.
- unimplemented!();
+ match self.unpack() {
+ UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
+ UnpackedKind::Type(ty) => write!(f, "{}", ty),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- if let Some(ty) = self.as_type() {
- Kind::from(ty.fold_with(folder))
- } else if let Some(r) = self.as_region() {
- Kind::from(r.fold_with(folder))
- } else {
- bug!()
+ match self.unpack() {
+ UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
+ UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- if let Some(ty) = self.as_type() {
- ty.visit_with(visitor)
- } else if let Some(r) = self.as_region() {
- r.visit_with(visitor)
- } else {
- bug!()
+ match self.unpack() {
+ UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
+ UnpackedKind::Type(ty) => ty.visit_with(visitor),
}
}
}
impl<'tcx> Encodable for Kind<'tcx> {
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
e.emit_enum("Kind", |e| {
- if let Some(ty) = self.as_type() {
- e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
- e.emit_enum_variant_arg(0, |e| ty.encode(e))
- })
- } else if let Some(r) = self.as_region() {
- e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
- e.emit_enum_variant_arg(0, |e| r.encode(e))
- })
- } else {
- bug!()
+ match self.unpack() {
+ UnpackedKind::Lifetime(lt) => {
+ e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
+ e.emit_enum_variant_arg(0, |e| lt.encode(e))
+ })
+ }
+ UnpackedKind::Type(ty) => {
+ e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
+ e.emit_enum_variant_arg(0, |e| ty.encode(e))
+ })
+ }
}
})
}
let def = types.next().unwrap();
let ty = mk_type(def, substs);
assert_eq!(def.index as usize, substs.len());
- substs.push(Kind::from(ty));
+ substs.push(ty.into());
}
for def in &defs.regions {
#[inline]
pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
- self.iter().filter_map(|k| k.as_type())
+ self.iter().filter_map(|k| {
+ if let UnpackedKind::Type(ty) = k.unpack() {
+ Some(ty)
+ } else {
+ None
+ }
+ })
}
#[inline]
pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
- self.iter().filter_map(|k| k.as_region())
+ self.iter().filter_map(|k| {
+ if let UnpackedKind::Lifetime(lt) = k.unpack() {
+ Some(lt)
+ } else {
+ None
+ }
+ })
}
#[inline]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
- self[i].as_type().unwrap_or_else(|| {
+ if let UnpackedKind::Type(ty) = self[i].unpack() {
+ ty
+ } else {
bug!("expected type for param #{} in {:?}", i, self);
- })
+ }
}
#[inline]
pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
- self[i].as_region().unwrap_or_else(|| {
+ if let UnpackedKind::Lifetime(lt) = self[i].unpack() {
+ lt
+ } else {
bug!("expected region for param #{} in {:?}", i, self);
- })
+ }
}
#[inline]
// the specialized routine `ty::replace_late_regions()`.
match *r {
ty::ReEarlyBound(data) => {
- let r = self.substs.get(data.index as usize)
- .and_then(|k| k.as_region());
+ let r = self.substs.get(data.index as usize).map(|k| k.unpack());
match r {
- Some(r) => {
- self.shift_region_through_binders(r)
+ Some(UnpackedKind::Lifetime(lt)) => {
+ self.shift_region_through_binders(lt)
}
- None => {
+ _ => {
let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
span,
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
// Look up the type in the substitutions. It really should be in there.
- let opt_ty = self.substs.get(p.idx as usize)
- .and_then(|k| k.as_type());
+ let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack());
let ty = match opt_ty {
- Some(t) => t,
- None => {
+ Some(UnpackedKind::Type(ty)) => ty,
+ _ => {
let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
span,
ty::TraitRef {
def_id: trait_ref.def_id,
substs: tcx.mk_substs(
- iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned()))
+ iter::once(self_ty.into()).chain(trait_ref.substs.iter().cloned()))
}
})
}
use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeVisitor;
-use ty::subst::{Subst, Kind};
+use ty::subst::{Subst, UnpackedKind};
use ty::TypeVariants::*;
use util::common::ErrorReported;
use middle::lang_items;
let result = item_substs.iter().zip(impl_substs.iter())
.filter(|&(_, &k)| {
- if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() {
- !impl_generics.region_param(ebr, self).pure_wrt_drop
- } else if let Some(&ty::TyS {
- sty: ty::TypeVariants::TyParam(ref pt), ..
- }) = k.as_type() {
- !impl_generics.type_param(pt, self).pure_wrt_drop
- } else {
- // not a type or region param - this should be reported
- // as an error.
- false
+ match k.unpack() {
+ UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
+ !impl_generics.region_param(ebr, self).pure_wrt_drop
+ }
+ UnpackedKind::Type(&ty::TyS {
+ sty: ty::TypeVariants::TyParam(ref pt), ..
+ }) => {
+ !impl_generics.type_param(pt, self).pure_wrt_drop
+ }
+ UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => {
+ // not a type or region param - this should be reported
+ // as an error.
+ false
+ }
}
}).map(|(&item_param, _)| item_param).collect();
debug!("destructor_constraint({:?}) = {:?}", def.did, result);
// Objects must be alive in order for their destructor
// to be called.
ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
- outlives: vec![Kind::from(ty)],
+ outlives: vec![ty.into()],
dtorck_types: vec![],
}),
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
+ eliminate_frame_pointer: false, // FIXME 43575
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
+ ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
("i686-unknown-netbsd", i686_unknown_netbsd),
+ ("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd),
--- /dev/null
+// Copyright 2012 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::netbsd_base::opts();
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+ base.max_atomic_width = Some(32);
+
+ // see #36994
+ base.exe_allocation_crate = None;
+
+ Ok(Target {
+ llvm_target: "powerpc-unknown-netbsd".to_string(),
+ target_endian: "big".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+ arch: "powerpc".to_string(),
+ target_os: "netbsd".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
--- /dev/null
+// Copyright 2018 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::linux_base::opts();
+ base.cpu = "v9".to_string();
+ base.max_atomic_width = Some(64);
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
+ base.exe_allocation_crate = None;
+
+ Ok(Target {
+ llvm_target: "sparc-unknown-linux-gnu".to_string(),
+ target_endian: "big".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(),
+ arch: "sparc".to_string(),
+ target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
ty::TyAdt(adt, substs) => {
if adt.is_box() {
// Use T as the sub pattern type of Box<T>.
- vec![substs[0].as_type().unwrap()]
+ vec![substs.type_at(0)]
} else {
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
let is_visible = adt.is_enum()
impl BitSlice for [Word] {
/// Clears bit at `idx` to 0; returns true iff this changed `self.`
+ #[inline]
fn clear_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("clear_bit: words={} idx={}",
}
/// Sets bit at `idx` to 1; returns true iff this changed `self.`
+ #[inline]
fn set_bit(&mut self, idx: usize) -> bool {
let words = self;
debug!("set_bit: words={} idx={}",
}
/// Extracts value of bit at `idx` in `self`.
+ #[inline]
fn get_bit(&self, idx: usize) -> bool {
let words = self;
let BitLookup { word, bit_mask, .. } = bit_lookup(idx);
}
impl Idx for usize {
+ #[inline]
fn new(idx: usize) -> Self { idx }
+ #[inline]
fn index(self) -> usize { self }
}
impl Idx for u32 {
+ #[inline]
fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 }
+ #[inline]
fn index(self) -> usize { self as usize }
}
pub struct $type($($pub)* u32);
impl Idx for $type {
+ #[inline]
fn new(value: usize) -> Self {
assert!(value < ($max) as usize);
$type(value as u32)
}
+ #[inline]
fn index(self) -> usize {
self.0 as usize
}
use rustc_privacy;
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
-use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats};
+use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
use rustc_const_eval::{self, check_match};
use super::Compilation;
&mut resolver,
sess.opts.test,
krate,
- sess.diagnostic())
+ sess.diagnostic(),
+ &sess.features.borrow())
});
// If we're actually rustdoc then there's no need to actually compile
}
pub fn default_provide(providers: &mut ty::maps::Providers) {
+ hir::provide(providers);
borrowck::provide(providers);
mir::provide(providers);
reachable::provide(providers);
"loop checking",
|| loops::check_crate(sess, &hir_map));
- time(time_passes,
- "static item recursion checking",
- || static_recursion::check_crate(sess, &hir_map))?;
-
let mut local_providers = ty::maps::Providers::default();
default_provide(&mut local_providers);
trans.provide(&mut local_providers);
use rustc_lint;
use rustc_resolve::MakeGlobMap;
use rustc::middle::region;
-use rustc::ty::subst::{Kind, Subst};
+use rustc::ty::subst::Subst;
use rustc::traits::{ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::maps::OnDiskCache;
env.t_fn(&[t_param], env.t_nil())
};
- let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
+ let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = fn(&'a isize)
env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
};
- let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
+ let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = (&'a isize, fn(&'a isize))
env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
};
- let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]);
+ let substs = env.infcx.tcx.intern_substs(&[re_bound1.into()]);
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = fn(&'a isize)
NON_SNAKE_CASE,
NON_UPPER_CASE_GLOBALS);
+ add_lint_group!(sess,
+ "nonstandard_style",
+ NON_CAMEL_CASE_TYPES,
+ NON_SNAKE_CASE,
+ NON_UPPER_CASE_GLOBALS);
+
add_lint_group!(sess,
"unused",
UNUSED_IMPORTS,
let id = tcx.hir.as_local_node_id(def_id).unwrap();
debug!("run_pass: {:?}", def_id);
+ // When NLL is enabled, the borrow checker runs the typeck
+ // itself, so we don't need this MIR pass anymore.
+ if tcx.sess.nll() {
+ return;
+ }
+
if tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors.
self.gather_move(&Place::Local(RETURN_PLACE));
}
- TerminatorKind::Assert { .. } |
- TerminatorKind::SwitchInt { .. } => {
- // branching terminators - these don't move anything
+ TerminatorKind::Assert { ref cond, .. } => {
+ self.gather_operand(cond);
+ }
+
+ TerminatorKind::SwitchInt { ref discr, .. } => {
+ self.gather_operand(discr);
}
TerminatorKind::Yield { ref value, .. } => {
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
-use rustc::ty::subst::{Subst, Substs, Kind};
+use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use syntax::codemap::{self, DUMMY_SP};
ty: Ty<'tcx>,
) -> ty::Instance<'tcx> {
let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
- let substs = tcx.intern_substs(&[Kind::from(ty)]);
+ let substs = tcx.intern_substs(&[ty.into()]);
ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
}
let recursion_depth_reset;
match starting_point {
- MonoItem::Static(node_id) => {
- let def_id = tcx.hir.local_def_id(node_id);
+ MonoItem::Static(def_id) => {
let instance = Instance::mono(tcx, def_id);
// Sanity check whether this ended up being collected accidentally
let tcx = self.tcx;
let instance = Instance::mono(tcx, static_.def_id);
if should_monomorphize_locally(tcx, &instance) {
- let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap();
- self.output.push(MonoItem::Static(node_id));
+ self.output.push(MonoItem::Static(static_.def_id));
}
self.super_static(static_, context, location);
self.output.push(MonoItem::GlobalAsm(item.id));
}
hir::ItemStatic(..) => {
+ let def_id = self.tcx.hir.local_def_id(item.id);
debug!("RootCollector: ItemStatic({})",
- def_id_to_string(self.tcx,
- self.tcx.hir.local_def_id(item.id)));
- self.output.push(MonoItem::Static(item.id));
+ def_id_to_string(self.tcx, def_id));
+ self.output.push(MonoItem::Static(def_id));
}
hir::ItemConst(..) => {
// const items only generate mono items if they are
fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName {
match *self.as_mono_item() {
MonoItem::Fn(instance) => tcx.symbol_name(instance),
- MonoItem::Static(node_id) => {
- let def_id = tcx.hir.local_def_id(node_id);
+ MonoItem::Static(def_id) => {
tcx.symbol_name(Instance::mono(tcx, def_id))
}
MonoItem::GlobalAsm(node_id) => {
fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
let def_id = match *self.as_mono_item() {
MonoItem::Fn(ref instance) => instance.def_id(),
- MonoItem::Static(node_id) => tcx.hir.local_def_id(node_id),
+ MonoItem::Static(def_id) => def_id,
MonoItem::GlobalAsm(..) => return None,
};
debug!("is_instantiable({:?})", self);
let (def_id, substs) = match *self.as_mono_item() {
MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
- MonoItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
+ MonoItem::Static(def_id) => (def_id, Substs::empty()),
// global asm never has predicates
MonoItem::GlobalAsm(..) => return true
};
}
fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
- let hir_map = &tcx.hir;
-
return match *self.as_mono_item() {
MonoItem::Fn(instance) => {
to_string_internal(tcx, "fn ", instance)
},
- MonoItem::Static(node_id) => {
- let def_id = hir_map.local_def_id(node_id);
+ MonoItem::Static(def_id) => {
let instance = Instance::new(def_id, tcx.intern_substs(&[]));
to_string_internal(tcx, "static ", instance)
},
MonoItem::Fn(Instance { def, .. }) => {
tcx.hir.as_local_node_id(def.def_id())
}
- MonoItem::Static(node_id) |
+ MonoItem::Static(def_id) => {
+ tcx.hir.as_local_node_id(def_id)
+ }
MonoItem::GlobalAsm(node_id) => {
Some(node_id)
}
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs([
Kind::from(self_ty),
- Kind::from(sig.inputs()[0]),
+ sig.inputs()[0].into(),
].iter().cloned());
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
-> ty::Instance<'tcx>
{
let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
- let substs = tcx.intern_substs(&[Kind::from(ty)]);
+ let substs = tcx.intern_substs(&[ty.into()]);
Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap()
}
}
}
}
- MonoItem::Static(node_id) |
+ MonoItem::Static(def_id) => {
+ tcx.hir.as_local_node_id(def_id)
+ }
MonoItem::GlobalAsm(node_id) => {
Some(node_id)
}
};
(Linkage::External, visibility)
}
- MonoItem::Static(node_id) |
+ MonoItem::Static(def_id) => {
+ let visibility = if tcx.is_exported_symbol(def_id) {
+ can_be_internalized = false;
+ default_visibility(def_id)
+ } else {
+ Visibility::Hidden
+ };
+ (Linkage::External, visibility)
+ }
MonoItem::GlobalAsm(node_id) => {
let def_id = tcx.hir.local_def_id(node_id);
let visibility = if tcx.is_exported_symbol(def_id) {
Some(def_id)
}
- MonoItem::Static(node_id) |
+ MonoItem::Static(def_id) => Some(def_id),
MonoItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)),
}
}
if used_unsafe.contains(&parent_id) {
Some(("block".to_string(), parent_id))
} else if let Some(hir::map::NodeItem(&hir::Item {
- node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
+ node: hir::ItemFn(_, fn_unsafety, _, _, _, _),
..
})) = tcx.hir.find(parent_id) {
- Some(("fn".to_string(), parent_id))
+ match fn_unsafety {
+ hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
+ hir::Unsafety::Normal => None,
+ }
} else {
is_enclosed(tcx, used_unsafe, parent_id)
}
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
-use rustc::ty::subst::{Kind, Substs};
+use rustc::ty::subst::Substs;
use util::dump_mir;
use util::liveness::{self, LivenessMode};
use rustc_const_math::ConstInt;
// Compute GeneratorState<yield_ty, return_ty>
let state_did = tcx.lang_items().gen_state().unwrap();
let state_adt_ref = tcx.adt_def(state_did);
- let state_substs = tcx.mk_substs([Kind::from(yield_ty),
- Kind::from(mir.return_ty())].iter());
+ let state_substs = tcx.mk_substs([yield_ty.into(),
+ mir.return_ty().into()].iter());
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
}
}
+// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
+// Nested `impl Trait` _is_ allowed in associated type position,
+// e.g `impl Iterator<Item=impl Debug>`
+struct NestedImplTraitVisitor<'a> {
+ session: &'a Session,
+ outer_impl_trait: Option<Span>,
+}
+
+impl<'a> NestedImplTraitVisitor<'a> {
+ fn with_impl_trait<F>(&mut self, outer_impl_trait: Option<Span>, f: F)
+ where F: FnOnce(&mut NestedImplTraitVisitor<'a>)
+ {
+ let old_outer_impl_trait = self.outer_impl_trait;
+ self.outer_impl_trait = outer_impl_trait;
+ f(self);
+ self.outer_impl_trait = old_outer_impl_trait;
+ }
+}
+
+
+impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
+ fn visit_ty(&mut self, t: &'a Ty) {
+ if let TyKind::ImplTrait(_) = t.node {
+ if let Some(outer_impl_trait) = self.outer_impl_trait {
+ struct_span_err!(self.session, t.span, E0666,
+ "nested `impl Trait` is not allowed")
+ .span_label(outer_impl_trait, "outer `impl Trait`")
+ .span_label(t.span, "nested `impl Trait` here")
+ .emit();
+
+ }
+ self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
+ } else {
+ visit::walk_ty(self, t);
+ }
+ }
+ fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a PathParameters) {
+ match *path_parameters {
+ PathParameters::AngleBracketed(ref params) => {
+ for type_ in ¶ms.types {
+ self.visit_ty(type_);
+ }
+ for type_binding in ¶ms.bindings {
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
+ // are allowed to contain nested `impl Trait`.
+ self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty));
+ }
+ }
+ PathParameters::Parenthesized(ref params) => {
+ for type_ in ¶ms.inputs {
+ self.visit_ty(type_);
+ }
+ if let Some(ref type_) = params.output {
+ // `-> Foo` syntax is essentially an associated type binding,
+ // so it is also allowed to contain nested `impl Trait`.
+ self.with_impl_trait(None, |this| visit::walk_ty(this, type_));
+ }
+ }
+ }
+ }
+}
+
+// Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
+struct ImplTraitProjectionVisitor<'a> {
+ session: &'a Session,
+ is_banned: bool,
+}
+
+impl<'a> ImplTraitProjectionVisitor<'a> {
+ fn with_ban<F>(&mut self, f: F)
+ where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>)
+ {
+ let old_is_banned = self.is_banned;
+ self.is_banned = true;
+ f(self);
+ self.is_banned = old_is_banned;
+ }
+}
+
+impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
+ fn visit_ty(&mut self, t: &'a Ty) {
+ match t.node {
+ TyKind::ImplTrait(_) => {
+ if self.is_banned {
+ struct_span_err!(self.session, t.span, E0667,
+ "`impl Trait` is not allowed in path parameters")
+ .emit();
+ }
+ }
+ TyKind::Path(ref qself, ref path) => {
+ // We allow these:
+ // - `Option<impl Trait>`
+ // - `option::Option<impl Trait>`
+ // - `option::Option<T>::Foo<impl Trait>
+ //
+ // But not these:
+ // - `<impl Trait>::Foo`
+ // - `option::Option<impl Trait>::Foo`.
+ //
+ // To implement this, we disallow `impl Trait` from `qself`
+ // (for cases like `<impl Trait>::Foo>`)
+ // but we allow `impl Trait` in `PathParameters`
+ // iff there are no more PathSegments.
+ if let Some(ref qself) = *qself {
+ // `impl Trait` in `qself` is always illegal
+ self.with_ban(|this| this.visit_ty(&qself.ty));
+ }
+
+ for (i, segment) in path.segments.iter().enumerate() {
+ // Allow `impl Trait` iff we're on the final path segment
+ if i == (path.segments.len() - 1) {
+ visit::walk_path_segment(self, path.span, segment);
+ } else {
+ self.with_ban(|this|
+ visit::walk_path_segment(this, path.span, segment));
+ }
+ }
+ }
+ _ => visit::walk_ty(self, t),
+ }
+ }
+}
+
pub fn check_crate(session: &Session, krate: &Crate) {
+ visit::walk_crate(
+ &mut NestedImplTraitVisitor {
+ session,
+ outer_impl_trait: None,
+ }, krate);
+
+ visit::walk_crate(
+ &mut ImplTraitProjectionVisitor {
+ session,
+ is_banned: false,
+ }, krate);
+
visit::walk_crate(&mut AstValidator { session: session }, krate)
}
Please note that negative impls are only allowed for auto traits.
"##,
-E0265: r##"
-This error indicates that a static or constant references itself.
-All statics and constants need to resolve to a value in an acyclic manner.
-
-For example, neither of the following can be sensibly compiled:
-
-```compile_fail,E0265
-const X: u32 = X;
-```
-
-```compile_fail,E0265
-const X: u32 = Y;
-const Y: u32 = X;
-```
-"##,
-
E0267: r##"
This error indicates the use of a loop keyword (`break` or `continue`) inside a
closure but outside of any loop. Erroneous code example:
E0567, // auto traits can not have generic parameters
E0568, // auto traits can not have super traits
E0642, // patterns aren't allowed in methods without bodies
+ E0666, // nested `impl Trait` is illegal
+ E0667, // `impl Trait` in projections
}
pub mod hir_stats;
pub mod loops;
mod mir_stats;
-pub mod static_recursion;
__build_diagnostic_array! { librustc_passes, DIAGNOSTICS }
+++ /dev/null
-// Copyright 2014 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.
-
-// This compiler pass detects constants that refer to themselves
-// recursively.
-
-use rustc::hir::map as hir_map;
-use rustc::session::Session;
-use rustc::hir::def::{Def, CtorKind};
-use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::{NodeMap, NodeSet};
-
-use syntax::ast;
-use syntax_pos::Span;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir;
-
-struct CheckCrateVisitor<'a, 'hir: 'a> {
- sess: &'a Session,
- hir_map: &'a hir_map::Map<'hir>,
- // `discriminant_map` is a cache that associates the `NodeId`s of local
- // variant definitions with the discriminant expression that applies to
- // each one. If the variant uses the default values (starting from `0`),
- // then `None` is stored.
- discriminant_map: NodeMap<Option<hir::BodyId>>,
- detected_recursive_ids: NodeSet,
-}
-
-impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
- fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
- NestedVisitorMap::None
- }
-
- fn visit_item(&mut self, it: &'hir hir::Item) {
- match it.node {
- hir::ItemStatic(..) |
- hir::ItemConst(..) => {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
- recursion_visitor.visit_item(it);
- }
- hir::ItemEnum(ref enum_def, ref generics) => {
- // We could process the whole enum, but handling the variants
- // with discriminant expressions one by one gives more specific,
- // less redundant output.
- for variant in &enum_def.variants {
- if let Some(_) = variant.node.disr_expr {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
- recursion_visitor.populate_enum_discriminants(enum_def);
- recursion_visitor.visit_variant(variant, generics, it.id);
- }
- }
- }
- _ => {}
- }
- intravisit::walk_item(self, it)
- }
-
- fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) {
- match ti.node {
- hir::TraitItemKind::Const(_, ref default) => {
- if let Some(_) = *default {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
- recursion_visitor.visit_trait_item(ti);
- }
- }
- _ => {}
- }
- intravisit::walk_trait_item(self, ti)
- }
-
- fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
- match ii.node {
- hir::ImplItemKind::Const(..) => {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
- recursion_visitor.visit_impl_item(ii);
- }
- _ => {}
- }
- intravisit::walk_impl_item(self, ii)
- }
-}
-
-pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>)
- -> Result<(), ErrorReported>
-{
- let mut visitor = CheckCrateVisitor {
- sess,
- hir_map,
- discriminant_map: NodeMap(),
- detected_recursive_ids: NodeSet(),
- };
- sess.track_errors(|| {
- // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
- hir_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
- })
-}
-
-struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
- sess: &'b Session,
- hir_map: &'b hir_map::Map<'hir>,
- discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
- idstack: Vec<ast::NodeId>,
- detected_recursive_ids: &'a mut NodeSet,
-}
-
-impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
- fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self {
- CheckItemRecursionVisitor {
- sess: v.sess,
- hir_map: v.hir_map,
- discriminant_map: &mut v.discriminant_map,
- idstack: Vec::new(),
- detected_recursive_ids: &mut v.detected_recursive_ids,
- }
- }
- fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F, span: Span)
- where F: Fn(&mut Self)
- {
- if self.idstack.iter().any(|&x| x == id) {
- if self.detected_recursive_ids.contains(&id) {
- return;
- }
- self.detected_recursive_ids.insert(id);
- let any_static = self.idstack.iter().any(|&x| {
- if let hir_map::NodeItem(item) = self.hir_map.get(x) {
- if let hir::ItemStatic(..) = item.node {
- true
- } else {
- false
- }
- } else {
- false
- }
- });
- if !any_static {
- struct_span_err!(self.sess, span, E0265, "recursive constant")
- .span_label(span, "recursion not allowed in constant")
- .emit();
- }
- return;
- }
- self.idstack.push(id);
- f(self);
- self.idstack.pop();
- }
- // If a variant has an expression specifying its discriminant, then it needs
- // to be checked just like a static or constant. However, if there are more
- // variants with no explicitly specified discriminant, those variants will
- // increment the same expression to get their values.
- //
- // So for every variant, we need to track whether there is an expression
- // somewhere in the enum definition that controls its discriminant. We do
- // this by starting from the end and searching backward.
- fn populate_enum_discriminants(&mut self, enum_definition: &'hir hir::EnumDef) {
- // Get the map, and return if we already processed this enum or if it
- // has no variants.
- match enum_definition.variants.first() {
- None => {
- return;
- }
- Some(variant) if self.discriminant_map.contains_key(&variant.node.data.id()) => {
- return;
- }
- _ => {}
- }
-
- // Go through all the variants.
- let mut variant_stack: Vec<ast::NodeId> = Vec::new();
- for variant in enum_definition.variants.iter().rev() {
- variant_stack.push(variant.node.data.id());
- // When we find an expression, every variant currently on the stack
- // is affected by that expression.
- if let Some(expr) = variant.node.disr_expr {
- for id in &variant_stack {
- self.discriminant_map.insert(*id, Some(expr));
- }
- variant_stack.clear()
- }
- }
- // If we are at the top, that always starts at 0, so any variant on the
- // stack has a default value and does not need to be checked.
- for id in &variant_stack {
- self.discriminant_map.insert(*id, None);
- }
- }
-}
-
-impl<'a, 'b: 'a, 'hir: 'b> Visitor<'hir> for CheckItemRecursionVisitor<'a, 'b, 'hir> {
- fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
- NestedVisitorMap::OnlyBodies(&self.hir_map)
- }
- fn visit_item(&mut self, it: &'hir hir::Item) {
- self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span);
- }
-
- fn visit_enum_def(&mut self,
- enum_definition: &'hir hir::EnumDef,
- generics: &'hir hir::Generics,
- item_id: ast::NodeId,
- _: Span) {
- self.populate_enum_discriminants(enum_definition);
- intravisit::walk_enum_def(self, enum_definition, generics, item_id);
- }
-
- fn visit_variant(&mut self,
- variant: &'hir hir::Variant,
- _: &'hir hir::Generics,
- _: ast::NodeId) {
- let variant_id = variant.node.data.id();
- let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
- span_bug!(variant.span,
- "`check_static_recursion` attempted to visit \
- variant with unknown discriminant")
- });
- // If `maybe_expr` is `None`, that's because no discriminant is
- // specified that affects this variant. Thus, no risk of recursion.
- if let Some(expr) = maybe_expr {
- let expr = &self.hir_map.body(expr).value;
- self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
- }
- }
-
- fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) {
- self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti), ti.span);
- }
-
- fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
- self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span);
- }
-
- fn visit_path(&mut self, path: &'hir hir::Path, _: ast::NodeId) {
- match path.def {
- Def::Static(def_id, _) |
- Def::AssociatedConst(def_id) |
- Def::Const(def_id) => {
- if let Some(node_id) = self.hir_map.as_local_node_id(def_id) {
- match self.hir_map.get(node_id) {
- hir_map::NodeItem(item) => self.visit_item(item),
- hir_map::NodeTraitItem(item) => self.visit_trait_item(item),
- hir_map::NodeImplItem(item) => self.visit_impl_item(item),
- hir_map::NodeForeignItem(_) => {}
- _ => {
- span_bug!(path.span,
- "expected item, found {}",
- self.hir_map.node_to_string(node_id));
- }
- }
- }
- }
- // For variants, we only want to check expressions that
- // affect the specific variant used, but we need to check
- // the whole enum definition to see what expression that
- // might be (if any).
- Def::VariantCtor(variant_id, CtorKind::Const) => {
- if let Some(variant_id) = self.hir_map.as_local_node_id(variant_id) {
- let variant = self.hir_map.expect_variant(variant_id);
- let enum_id = self.hir_map.get_parent(variant_id);
- let enum_item = self.hir_map.expect_item(enum_id);
- if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node {
- self.populate_enum_discriminants(enum_def);
- self.visit_variant(variant, generics, enum_id);
- } else {
- span_bug!(path.span,
- "`check_static_recursion` found \
- non-enum in Def::VariantCtor");
- }
- }
- }
- _ => (),
- }
- intravisit::walk_path(self, path);
- }
-}
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
use syntax::parse::token;
+use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use errors::{DiagnosticBuilder, DiagnosticId};
// check that all of the arms in an or-pattern have exactly the
// same set of bindings, with the same binding modes for each.
- fn check_consistent_bindings(&mut self, arm: &Arm) {
- if arm.pats.is_empty() {
+ fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
+ if pats.is_empty() {
return;
}
let mut missing_vars = FxHashMap();
let mut inconsistent_vars = FxHashMap();
- for (i, p) in arm.pats.iter().enumerate() {
+ for (i, p) in pats.iter().enumerate() {
let map_i = self.binding_mode_map(&p);
- for (j, q) in arm.pats.iter().enumerate() {
+ for (j, q) in pats.iter().enumerate() {
if i == j {
continue;
}
self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
}
- // This has to happen *after* we determine which
- // pat_idents are variants
- self.check_consistent_bindings(arm);
+ // This has to happen *after* we determine which pat_idents are variants
+ self.check_consistent_bindings(&arm.pats);
walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&arm.body);
&ident.node.name.as_str())
);
}
- Some(..) if pat_src == PatternSource::Match => {
+ Some(..) if pat_src == PatternSource::Match ||
+ pat_src == PatternSource::IfLet ||
+ pat_src == PatternSource::WhileLet => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
visit::walk_expr(self, expr);
}
- ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
+ ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
self.visit_expr(subexpression);
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
- self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap());
+ let mut bindings_list = FxHashMap();
+ for pat in pats {
+ self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
+ }
+ // This has to happen *after* we determine which pat_idents are variants
+ self.check_consistent_bindings(pats);
self.visit_block(if_block);
self.ribs[ValueNS].pop();
});
}
- ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
+ ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
this.visit_expr(subexpression);
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
- this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+ let mut bindings_list = FxHashMap();
+ for pat in pats {
+ this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
+ }
+ // This has to happen *after* we determine which pat_idents are variants
+ this.check_consistent_bindings(pats);
this.visit_block(block);
this.ribs[ValueNS].pop();
});
}
}
+ fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
+ let mut collector = PathCollector::new();
+ for pattern in pats {
+ // collect paths from the arm's patterns
+ collector.visit_pat(&pattern);
+ self.visit_pat(&pattern);
+ }
+
+ // process collected paths
+ for (id, i, sp, immut) in collector.collected_idents {
+ match self.save_ctxt.get_path_def(id) {
+ HirDef::Local(id) => {
+ let mut value = if immut == ast::Mutability::Immutable {
+ self.span.snippet(sp).to_string()
+ } else {
+ "<mutable>".to_string()
+ };
+ let hir_id = self.tcx.hir.node_to_hir_id(id);
+ let typ = self.save_ctxt
+ .tables
+ .node_id_to_type_opt(hir_id)
+ .map(|t| t.to_string())
+ .unwrap_or(String::new());
+ value.push_str(": ");
+ value.push_str(&typ);
+
+ if !self.span.filter_generated(Some(sp), sp) {
+ let qualname = format!("{}${}", i.to_string(), id);
+ let id = ::id_from_node_id(id, &self.save_ctxt);
+ let span = self.span_from_span(sp);
+
+ self.dumper.dump_def(
+ &Access {
+ public: false,
+ reachable: false,
+ },
+ Def {
+ kind: DefKind::Local,
+ id,
+ span,
+ name: i.to_string(),
+ qualname,
+ value: typ,
+ parent: None,
+ children: vec![],
+ decl_id: None,
+ docs: String::new(),
+ sig: None,
+ attributes: vec![],
+ },
+ );
+ }
+ }
+ HirDef::StructCtor(..) |
+ HirDef::VariantCtor(..) |
+ HirDef::Const(..) |
+ HirDef::AssociatedConst(..) |
+ HirDef::Struct(..) |
+ HirDef::Variant(..) |
+ HirDef::TyAlias(..) |
+ HirDef::AssociatedTy(..) |
+ HirDef::SelfTy(..) => {
+ self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
+ }
+ def => error!(
+ "unexpected definition kind when processing collected idents: {:?}",
+ def
+ ),
+ }
+ }
+
+ for (id, ref path) in collector.collected_paths {
+ self.process_path(id, path);
+ }
+ }
fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
// The local could declare multiple new vars, we must walk the
v.nest_scope(ex.id, |v| v.visit_expr(body))
});
}
- ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
- ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
+ ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value);
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
self.visit_expr(subexpression);
visit::walk_block(self, block);
}
- ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
- let value = self.span.snippet(subexpression.span);
- self.process_var_decl(pattern, value);
+ ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
+ self.process_var_decl_multi(pats);
+ debug!("for loop, walk sub-expr: {:?}", subexpression.node);
+ self.visit_expr(subexpression);
+ visit::walk_block(self, block);
+ }
+ ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
+ self.process_var_decl_multi(pats);
self.visit_expr(subexpression);
visit::walk_block(self, block);
opt_else.as_ref().map(|el| self.visit_expr(el));
}
fn visit_arm(&mut self, arm: &'l ast::Arm) {
- let mut collector = PathCollector::new();
- for pattern in &arm.pats {
- // collect paths from the arm's patterns
- collector.visit_pat(&pattern);
- self.visit_pat(&pattern);
- }
-
- // process collected paths
- for (id, i, sp, immut) in collector.collected_idents {
- match self.save_ctxt.get_path_def(id) {
- HirDef::Local(id) => {
- let mut value = if immut == ast::Mutability::Immutable {
- self.span.snippet(sp).to_string()
- } else {
- "<mutable>".to_string()
- };
- let hir_id = self.tcx.hir.node_to_hir_id(id);
- let typ = self.save_ctxt
- .tables
- .node_id_to_type_opt(hir_id)
- .map(|t| t.to_string())
- .unwrap_or(String::new());
- value.push_str(": ");
- value.push_str(&typ);
-
- if !self.span.filter_generated(Some(sp), sp) {
- let qualname = format!("{}${}", i.to_string(), id);
- let id = ::id_from_node_id(id, &self.save_ctxt);
- let span = self.span_from_span(sp);
-
- self.dumper.dump_def(
- &Access {
- public: false,
- reachable: false,
- },
- Def {
- kind: DefKind::Local,
- id,
- span,
- name: i.to_string(),
- qualname,
- value: typ,
- parent: None,
- children: vec![],
- decl_id: None,
- docs: String::new(),
- sig: None,
- attributes: vec![],
- },
- );
- }
- }
- HirDef::StructCtor(..) |
- HirDef::VariantCtor(..) |
- HirDef::Const(..) |
- HirDef::AssociatedConst(..) |
- HirDef::Struct(..) |
- HirDef::Variant(..) |
- HirDef::TyAlias(..) |
- HirDef::AssociatedTy(..) |
- HirDef::SelfTy(..) => {
- self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
- }
- def => error!(
- "unexpected definition kind when processing collected idents: {:?}",
- def
- ),
- }
- }
-
- for (id, ref path) in collector.collected_paths {
- self.process_path(id, path);
- }
+ self.process_var_decl_multi(&arm.pats);
walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&arm.body);
}
// We keep track of the following two counts - the depth of nesting of
// angle brackets, and the depth of nesting of square brackets. For the
// angle bracket count, we only count tokens which occur outside of any
- // square brackets (i.e. bracket_count == 0). The intutition here is
+ // square brackets (i.e. bracket_count == 0). The intuition here is
// that we want to count angle brackets in the type, but not any which
// could be in expression context (because these could mean 'less than',
// etc.).
}
prev = next;
}
- if angle_count != 0 || bracket_count != 0 {
- let loc = self.sess.codemap().lookup_char_pos(span.lo());
- span_bug!(
- span,
- "Mis-counted brackets when breaking path? Parsing '{}' \
- in {}, line {}",
- self.snippet(span),
- loc.file.name,
- loc.line
- );
+ #[cfg(debug_assertions)] {
+ if angle_count != 0 || bracket_count != 0 {
+ let loc = self.sess.codemap().lookup_char_pos(span.lo());
+ span_bug!(
+ span,
+ "Mis-counted brackets when breaking path? Parsing '{}' \
+ in {}, line {}",
+ self.snippet(span),
+ loc.file.name,
+ loc.line
+ );
+ }
}
- if result.is_none() && prev.tok.is_ident() && angle_count == 0 {
+ if result.is_none() && prev.tok.is_ident() {
return Some(prev.sp);
}
result
use rustc::ty::layout::{HasDataLayout, LayoutOf};
use libc::c_uint;
-use std::{cmp, iter};
+use std::cmp;
pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
pub fn align(&self, cx: &CodegenCx) -> Align {
self.unit.align(cx)
}
-
- pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
- let llunit = self.unit.llvm_type(cx);
-
- if self.total <= self.unit.size {
- return llunit;
- }
-
- let count = self.total.bytes() / self.unit.size.bytes();
- let rem_bytes = self.total.bytes() % self.unit.size.bytes();
-
- if rem_bytes == 0 {
- return Type::array(&llunit, count);
- }
-
- // Only integers can be really split further.
- assert_eq!(self.unit.kind, RegKind::Integer);
-
- let args: Vec<_> = (0..count).map(|_| llunit)
- .chain(iter::once(Type::ix(cx, rem_bytes * 8)))
- .collect();
-
- Type::struct_(cx, &args, false)
- }
}
pub trait LayoutExt<'tcx> {
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum CastTarget {
- Uniform(Uniform),
- Pair(Reg, Reg)
+pub struct CastTarget {
+ pub prefix: [Option<RegKind>; 8],
+ pub prefix_chunk: Size,
+ pub rest: Uniform,
}
impl From<Reg> for CastTarget {
fn from(unit: Reg) -> CastTarget {
- CastTarget::Uniform(Uniform::from(unit))
+ CastTarget::from(Uniform::from(unit))
}
}
impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
- CastTarget::Uniform(uniform)
+ CastTarget {
+ prefix: [None; 8],
+ prefix_chunk: Size::from_bytes(0),
+ rest: uniform
+ }
}
}
impl CastTarget {
- pub fn size(&self, cx: &CodegenCx) -> Size {
- match *self {
- CastTarget::Uniform(u) => u.total,
- CastTarget::Pair(a, b) => {
- (a.size.abi_align(a.align(cx)) + b.size)
- .abi_align(self.align(cx))
- }
+ pub fn pair(a: Reg, b: Reg) -> CastTarget {
+ CastTarget {
+ prefix: [Some(a.kind), None, None, None, None, None, None, None],
+ prefix_chunk: a.size,
+ rest: Uniform::from(b)
}
}
+ pub fn size(&self, cx: &CodegenCx) -> Size {
+ (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
+ .abi_align(self.rest.align(cx)) + self.rest.total
+ }
+
pub fn align(&self, cx: &CodegenCx) -> Align {
- match *self {
- CastTarget::Uniform(u) => u.align(cx),
- CastTarget::Pair(a, b) => {
- cx.data_layout().aggregate_align
- .max(a.align(cx))
- .max(b.align(cx))
- }
- }
+ self.prefix.iter()
+ .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx)))
+ .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
+ |acc, align| acc.max(align))
}
pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
- match *self {
- CastTarget::Uniform(u) => u.llvm_type(cx),
- CastTarget::Pair(a, b) => {
- Type::struct_(cx, &[
- a.llvm_type(cx),
- b.llvm_type(cx)
- ], false)
+ let rest_ll_unit = self.rest.unit.llvm_type(cx);
+ let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes();
+ let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes();
+
+ if self.prefix.iter().all(|x| x.is_none()) {
+ // Simplify to a single unit when there is no prefix and size <= unit size
+ if self.rest.total <= self.rest.unit.size {
+ return rest_ll_unit;
+ }
+
+ // Simplify to array when all chunks are the same size and type
+ if rem_bytes == 0 {
+ return Type::array(&rest_ll_unit, rest_count);
}
}
+
+ // Create list of fields in the main structure
+ let mut args: Vec<_> =
+ self.prefix.iter().flat_map(|option_kind| option_kind.map(
+ |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
+ .chain((0..rest_count).map(|_| rest_ll_unit))
+ .collect();
+
+ // Append final integer
+ if rem_bytes != 0 {
+ // Only integers can be really split further.
+ assert_eq!(self.rest.unit.kind, RegKind::Integer);
+ args.push(Type::ix(cx, rem_bytes * 8));
+ }
+
+ Type::struct_(cx, &args, false)
}
}
// extensions
+ pub fn get_args(&self) -> &[OsString] {
+ &self.args
+ }
+
pub fn take_args(&mut self) -> Vec<OsString> {
mem::replace(&mut self.args, Vec::new())
}
prog = time(sess.time_passes(), "running linker", || {
exec_linker(sess, &mut cmd, tmpdir)
});
- if !retry_on_segfault || i > 3 {
- break
- }
let output = match prog {
Ok(ref output) => output,
Err(_) => break,
let mut out = output.stderr.clone();
out.extend(&output.stdout);
let out = String::from_utf8_lossy(&out);
+
+ // Check to see if the link failed with "unrecognized command line option:
+ // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
+ // reperform the link step without the -no-pie option. This is safe because
+ // if the linker doesn't support -no-pie then it should not default to
+ // linking executables as pie. Different versions of gcc seem to use
+ // different quotes in the error message so don't check for them.
+ if sess.target.target.options.linker_is_gnu &&
+ (out.contains("unrecognized command line option") ||
+ out.contains("unknown argument")) &&
+ out.contains("-no-pie") &&
+ cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
+ info!("linker output: {:?}", out);
+ warn!("Linker does not support -no-pie command line option. Retrying without.");
+ for arg in cmd.take_args() {
+ if arg.to_string_lossy() != "-no-pie" {
+ cmd.arg(arg);
+ }
+ }
+ info!("{:?}", &cmd);
+ continue;
+ }
+ if !retry_on_segfault || i > 3 {
+ break
+ }
let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
let msg_bus = "clang: error: unable to execute command: Bus error: 10";
if !(out.contains(msg_segv) || out.contains(msg_bus)) {
let used_link_args = &trans.crate_info.link_args;
- if crate_type == config::CrateTypeExecutable &&
- t.options.position_independent_executables {
- let empty_vec = Vec::new();
- let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
- let more_args = &sess.opts.cg.link_arg;
- let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
-
- if get_reloc_model(sess) == llvm::RelocMode::PIC
- && !sess.crt_static() && !args.any(|x| *x == "-static") {
+ if crate_type == config::CrateTypeExecutable {
+ let mut position_independent_executable = false;
+
+ if t.options.position_independent_executables {
+ let empty_vec = Vec::new();
+ let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
+ let more_args = &sess.opts.cg.link_arg;
+ let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
+
+ if get_reloc_model(sess) == llvm::RelocMode::PIC
+ && !sess.crt_static() && !args.any(|x| *x == "-static") {
+ position_independent_executable = true;
+ }
+ }
+
+ if position_independent_executable {
cmd.position_independent_executable();
+ } else {
+ // recent versions of gcc can be configured to generate position
+ // independent executables by default. We have to pass -no-pie to
+ // explicitly turn that off.
+ if sess.target.target.options.linker_is_gnu {
+ cmd.no_position_independent_executable();
+ }
}
}
fn add_object(&mut self, path: &Path);
fn gc_sections(&mut self, keep_metadata: bool);
fn position_independent_executable(&mut self);
+ fn no_position_independent_executable(&mut self);
fn partial_relro(&mut self);
fn full_relro(&mut self);
fn optimize(&mut self);
fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
+ fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
fn partial_relro(&mut self) { self.linker_arg("-z,relro"); }
fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); }
fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
// noop
}
+ fn no_position_independent_executable(&mut self) {
+ // noop
+ }
+
fn partial_relro(&mut self) {
// noop
}
// noop
}
+ fn no_position_independent_executable(&mut self) {
+ // noop
+ }
+
fn partial_relro(&mut self) {
// noop
}
let translation_items: DefIdSet = items.iter().filter_map(|trans_item| {
match *trans_item {
MonoItem::Fn(ref instance) => Some(instance.def_id()),
+ MonoItem::Static(def_id) => Some(def_id),
_ => None,
}
}).collect();
}
}
-fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool {
+fn is_translated_item(tcx: TyCtxt, id: DefId) -> bool {
let (all_trans_items, _) =
tcx.collect_and_partition_translation_items(LOCAL_CRATE);
all_trans_items.contains(&id)
providers.collect_and_partition_translation_items =
collect_and_partition_translation_items;
- providers.is_translated_function = is_translated_function;
+ providers.is_translated_item = is_translated_item;
providers.codegen_unit = |tcx, name| {
let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
+use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
use context::CodegenCx;
+use rustc::ty::layout::{self, Size};
-use rustc::ty::layout::Size;
+fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
+ // Always sign extend u32 values on 64-bit mips
+ if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
+ if let layout::Int(i, signed) = scalar.value {
+ if !signed && i.size().bits() == 32 {
+ if let PassMode::Direct(ref mut attrs) = arg.mode {
+ attrs.set(ArgAttribute::SExt);
+ return;
+ }
+ }
+ }
+ }
+
+ arg.extend_integer_width_to(bits);
+}
+
+fn bits_to_int_reg(bits: u64) -> Reg {
+ if bits <= 8 {
+ Reg::i8()
+ } else if bits <= 16 {
+ Reg::i16()
+ } else if bits <= 32 {
+ Reg::i32()
+ } else {
+ Reg::i64()
+ }
+}
-fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- ret: &mut ArgType<'tcx>,
- offset: &mut Size) {
+fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
+ match ret.layout.field(cx, i).abi {
+ layout::Abi::Scalar(ref scalar) => match scalar.value {
+ layout::F32 => Some(Reg::f32()),
+ layout::F64 => Some(Reg::f64()),
+ _ => None
+ },
+ _ => None
+ }
+}
+
+fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
if !ret.layout.is_aggregate() {
- ret.extend_integer_width_to(64);
+ extend_integer_width_mips(ret, 64);
+ return;
+ }
+
+ let size = ret.layout.size;
+ let bits = size.bits();
+ if bits <= 128 {
+ // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
+ // use of float registers to structures (not unions) containing exactly one or two
+ // float fields.
+
+ if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
+ if ret.layout.fields.count() == 1 {
+ if let Some(reg) = float_reg(cx, ret, 0) {
+ ret.cast_to(reg);
+ return;
+ }
+ } else if ret.layout.fields.count() == 2 {
+ if let Some(reg0) = float_reg(cx, ret, 0) {
+ if let Some(reg1) = float_reg(cx, ret, 1) {
+ ret.cast_to(CastTarget::pair(reg0, reg1));
+ return;
+ }
+ }
+ }
+ }
+
+ // Cast to a uniform int structure
+ ret.cast_to(Uniform {
+ unit: bits_to_int_reg(bits),
+ total: size
+ });
} else {
ret.make_indirect();
- *offset += cx.tcx.data_layout.pointer_size;
}
}
-fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) {
+fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+ if !arg.layout.is_aggregate() {
+ extend_integer_width_mips(arg, 64);
+ return;
+ }
+
let dl = &cx.tcx.data_layout;
let size = arg.layout.size;
- let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
+ let mut prefix = [None; 8];
+ let mut prefix_index = 0;
- if arg.layout.is_aggregate() {
- arg.cast_to(Uniform {
- unit: Reg::i64(),
- total: size
- });
- if !offset.is_abi_aligned(align) {
- arg.pad_with(Reg::i64());
+ match arg.layout.fields {
+ layout::FieldPlacement::Array { .. } => {
+ // Arrays are passed indirectly
+ arg.make_indirect();
+ return;
}
- } else {
- arg.extend_integer_width_to(64);
- }
+ layout::FieldPlacement::Union(_) => {
+ // Unions and are always treated as a series of 64-bit integer chunks
+ },
+ layout::FieldPlacement::Arbitrary { .. } => {
+ // Structures are split up into a series of 64-bit integer chunks, but any aligned
+ // doubles not part of another aggregate are passed as floats.
+ let mut last_offset = Size::from_bytes(0);
+
+ for i in 0..arg.layout.fields.count() {
+ let field = arg.layout.field(cx, i);
+ let offset = arg.layout.fields.offset(i);
+
+ // We only care about aligned doubles
+ if let layout::Abi::Scalar(ref scalar) = field.abi {
+ if let layout::F64 = scalar.value {
+ if offset.is_abi_aligned(dl.f64_align) {
+ // Insert enough integers to cover [last_offset, offset)
+ assert!(last_offset.is_abi_aligned(dl.f64_align));
+ for _ in 0..((offset - last_offset).bits() / 64)
+ .min((prefix.len() - prefix_index) as u64) {
+
+ prefix[prefix_index] = Some(RegKind::Integer);
+ prefix_index += 1;
+ }
+
+ if prefix_index == prefix.len() {
+ break;
+ }
+
+ prefix[prefix_index] = Some(RegKind::Float);
+ prefix_index += 1;
+ last_offset = offset + Reg::f64().size;
+ }
+ }
+ }
+ }
+ }
+ };
- *offset = offset.abi_align(align) + size.abi_align(align);
+ // Extract first 8 chunks as the prefix
+ let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
+ arg.cast_to(CastTarget {
+ prefix: prefix,
+ prefix_chunk: Size::from_bytes(8),
+ rest: Uniform { unit: Reg::i64(), total: rest_size }
+ });
}
pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
- let mut offset = Size::from_bytes(0);
if !fty.ret.is_ignore() {
- classify_ret_ty(cx, &mut fty.ret, &mut offset);
+ classify_ret_ty(cx, &mut fty.ret);
}
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
- classify_arg_ty(cx, arg, &mut offset);
+ classify_arg_ty(cx, arg);
}
}
let mut target = CastTarget::from(lo);
if size > offset {
if let Some(hi) = reg_component(cls, &mut i, size - offset) {
- target = CastTarget::Pair(lo, hi);
+ target = CastTarget::pair(lo, hi);
}
}
assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);
unsafe {
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
- if cx.tcx.is_translated_function(instance_def_id) {
+ if cx.tcx.is_translated_item(instance_def_id) {
if instance_def_id.is_local() {
if !cx.tcx.is_exported_symbol(instance_def_id) {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{HasDataLayout, LayoutOf};
-use rustc::ty::subst::Kind;
use rustc::hir;
use libc::{c_uint, c_char};
sig.map_bound(|sig| {
let state_did = tcx.lang_items().gen_state().unwrap();
let state_adt_ref = tcx.adt_def(state_did);
- let state_substs = tcx.mk_substs([Kind::from(sig.yield_ty),
- Kind::from(sig.return_ty)].iter());
+ let state_substs = tcx.mk_substs([sig.yield_ty.into(),
+ sig.return_ty.into()].iter());
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
tcx.mk_fn_sig(iter::once(env_ty),
use rustc::middle::const_val::ConstEvalErr;
use debuginfo;
use base;
-use monomorphize::{MonoItem, MonoItemExt};
+use monomorphize::MonoItem;
use common::{CodegenCx, val_ty};
use declare;
use monomorphize::Instance;
return g;
}
+ let defined_in_current_codegen_unit = cx.codegen_unit
+ .items()
+ .contains_key(&MonoItem::Static(def_id));
+ assert!(!defined_in_current_codegen_unit,
+ "consts::get_static() should always hit the cache for \
+ statics defined in the same CGU, but did not for `{:?}`",
+ def_id);
+
let ty = instance.ty(cx.tcx);
+ let sym = cx.tcx.symbol_name(instance);
+
let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) {
let llty = cx.layout_of(ty).llvm_type(cx);
hir_map::NodeItem(&hir::Item {
ref attrs, span, node: hir::ItemStatic(..), ..
}) => {
- let sym = MonoItem::Static(id).symbol_name(cx.tcx);
-
- let defined_in_current_codegen_unit = cx.codegen_unit
- .items()
- .contains_key(&MonoItem::Static(id));
- assert!(!defined_in_current_codegen_unit);
-
if declare::get_declared_value(cx, &sym[..]).is_some() {
span_bug!(span, "trans: Conflicting symbol names for static?");
}
hir_map::NodeForeignItem(&hir::ForeignItem {
ref attrs, span, node: hir::ForeignItemStatic(..), ..
}) => {
- let sym = cx.tcx.symbol_name(instance);
+
let g = if let Some(name) =
attr::first_attr_value_str_by_name(&attrs, "linkage") {
// If this is a static with a linkage specified, then we need to handle
g
} else {
- let sym = cx.tcx.symbol_name(instance);
-
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
// FIXME(nagisa): investigate whether it can be changed into define_global
let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx));
// statically in the final application, we always mark such symbols as 'dllimport'.
// If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to
// make things work.
- unsafe {
- llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
+ //
+ // However, in some scenarios we defer emission of statics to downstream
+ // crates, so there are cases where a static with an upstream DefId
+ // is actually present in the current crate. We can find out via the
+ // is_translated_item query.
+ if !cx.tcx.is_translated_item(def_id) {
+ unsafe {
+ llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
+ }
}
}
g
}
pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- m: hir::Mutability,
- id: ast::NodeId,
+ def_id: DefId,
+ is_mutable: bool,
attrs: &[ast::Attribute])
-> Result<ValueRef, ConstEvalErr<'tcx>> {
unsafe {
- let def_id = cx.tcx.hir.local_def_id(id);
let g = get_static(cx, def_id);
let v = ::mir::trans_static_initializer(cx, def_id)?;
// As an optimization, all shared statics which do not have interior
// mutability are placed into read-only memory.
- if m != hir::MutMutable {
+ if !is_mutable {
if cx.type_is_freeze(ty) {
llvm::LLVMSetGlobalConstant(g, llvm::True);
}
}
- debuginfo::create_global_var_metadata(cx, id, g);
+ debuginfo::create_global_var_metadata(cx, def_id, g);
if attr::contains_name(attrs, "thread_local") {
llvm::set_thread_local_mode(g, cx.tls_model);
use super::utils::{debug_context, DIB, span_start,
get_namespace_for_item, create_DIArray, is_node_local_to_unit};
-use super::namespace::mangled_name_of_item;
+use super::namespace::mangled_name_of_instance;
use super::type_names::compute_debuginfo_type_name;
use super::{CrateDebugContext};
use abi;
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_global_var_metadata(cx: &CodegenCx,
- node_id: ast::NodeId,
+ def_id: DefId,
global: ValueRef) {
if cx.dbg_cx.is_none() {
return;
}
let tcx = cx.tcx;
- let node_def_id = tcx.hir.local_def_id(node_id);
- let no_mangle = attr::contains_name(&tcx.get_attrs(node_def_id), "no_mangle");
+ let no_mangle = attr::contains_name(&tcx.get_attrs(def_id), "no_mangle");
// We may want to remove the namespace scope if we're in an extern block, see:
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952
- let var_scope = get_namespace_for_item(cx, node_def_id);
- let span = cx.tcx.def_span(node_def_id);
+ let var_scope = get_namespace_for_item(cx, def_id);
+ let span = cx.tcx.def_span(def_id);
let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP {
let loc = span_start(cx, span);
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
};
- let is_local_to_unit = is_node_local_to_unit(cx, node_id);
- let variable_type = Instance::mono(cx.tcx, node_def_id).ty(cx.tcx);
+ let is_local_to_unit = is_node_local_to_unit(cx, def_id);
+ let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx);
let type_metadata = type_metadata(cx, variable_type, span);
- let var_name = tcx.item_name(node_def_id).to_string();
+ let var_name = tcx.item_name(def_id).to_string();
let var_name = CString::new(var_name).unwrap();
let linkage_name = if no_mangle {
None
} else {
- let linkage_name = mangled_name_of_item(cx, node_id);
+ let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id));
Some(CString::new(linkage_name.to_string()).unwrap())
};
let linkage_name = mangled_name_of_instance(cx, instance);
let scope_line = span_start(cx, span).line;
-
- let local_id = cx.tcx.hir.as_local_node_id(instance.def_id());
- let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id));
+ let is_local_to_unit = is_node_local_to_unit(cx, def_id);
let function_name = CString::new(name).unwrap();
let linkage_name = CString::new(linkage_name.to_string()).unwrap();
let mut flags = DIFlags::FlagPrototyped;
+
+ let local_id = cx.tcx.hir.as_local_node_id(def_id);
match *cx.sess().entry_fn.borrow() {
Some((id, _)) => {
if local_id == Some(id) {
use super::utils::{DIB, debug_context};
use monomorphize::Instance;
use rustc::ty;
-use syntax::ast;
use llvm;
use llvm::debuginfo::DIScope;
tcx.symbol_name(instance)
}
-pub fn mangled_name_of_item<'a, 'tcx>(
- cx: &CodegenCx<'a, 'tcx>,
- node_id: ast::NodeId,
-) -> ty::SymbolName {
- let tcx = cx.tcx;
- let node_def_id = tcx.hir.local_def_id(node_id);
- let instance = Instance::mono(tcx, node_def_id);
- tcx.symbol_name(instance)
-}
-
pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope {
if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
return scope;
use common::{CodegenCx};
use syntax_pos::{self, Span};
-use syntax::ast;
-pub fn is_node_local_to_unit(cx: &CodegenCx, node_id: ast::NodeId) -> bool
+pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool
{
// The is_local_to_unit flag indicates whether a function is local to the
// current compilation unit (i.e. if it is *static* in the C-sense). The
// visible). It might better to use the `exported_items` set from
// `driver::CrateAnalysis` in the future, but (atm) this set is not
// available in the translation pass.
- let def_id = cx.tcx.hir.local_def_id(node_id);
!cx.tcx.is_exported_symbol(def_id)
}
llvm_args.as_ptr());
}
-// WARNING: the features must be known to LLVM or the feature
-// detection code will walk past the end of the feature array,
-// leading to crashes.
+// WARNING: the features after applying `to_llvm_feature` must be known
+// to LLVM or the feature detection code will walk past the end of the feature
+// array, leading to crashes.
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
-const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
- "sse2", "sse3", "sse4.1", "sse4.2",
- "ssse3", "tbm", "lzcnt", "popcnt",
- "sse4a", "rdrnd", "rdseed", "fma",
- "xsave", "xsaveopt", "xsavec",
- "xsaves", "aes", "pclmulqdq",
- "avx512bw", "avx512cd",
- "avx512dq", "avx512er",
- "avx512f", "avx512ifma",
- "avx512pf", "avx512vbmi",
- "avx512vl", "avx512vpopcntdq",
- "mmx", "fxsr"];
+const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
+ "avx512cd", "avx512dq", "avx512er",
+ "avx512f", "avx512ifma", "avx512pf",
+ "avx512vbmi", "avx512vl", "avx512vpopcntdq",
+ "bmi", "bmi2", "fma", "fxsr",
+ "lzcnt", "mmx", "pclmulqdq",
+ "popcnt", "rdrand", "rdseed",
+ "sse", "sse2", "sse3", "sse4.1",
+ "sse4.2", "sse4a", "ssse3",
+ "tbm", "xsave", "xsavec",
+ "xsaveopt", "xsaves"];
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
pub fn to_llvm_feature(s: &str) -> &str {
match s {
"pclmulqdq" => "pclmul",
+ "rdrand" => "rdrnd",
s => s,
}
}
use monomorphize::Instance;
use type_of::LayoutLlvmExt;
use rustc::hir;
+use rustc::hir::def::Def;
+use rustc::hir::def_id::DefId;
use rustc::mir::mono::{Linkage, Visibility};
use rustc::ty::TypeFoldable;
use rustc::ty::layout::LayoutOf;
-use syntax::ast;
use syntax::attr;
use std::fmt;
cx.codegen_unit.name());
match *self.as_mono_item() {
- MonoItem::Static(node_id) => {
+ MonoItem::Static(def_id) => {
let tcx = cx.tcx;
- let item = tcx.hir.expect_item(node_id);
- if let hir::ItemStatic(_, m, _) = item.node {
- match consts::trans_static(&cx, m, item.id, &item.attrs) {
- Ok(_) => { /* Cool, everything's alright. */ },
- Err(err) => {
- err.report(tcx, item.span, "static");
- }
- };
- } else {
- span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
- }
+ let is_mutable = match tcx.describe_def(def_id) {
+ Some(Def::Static(_, is_mutable)) => is_mutable,
+ Some(other) => {
+ bug!("Expected Def::Static, found {:?}", other)
+ }
+ None => {
+ bug!("Expected Def::Static for {:?}, found nothing", def_id)
+ }
+ };
+ let attrs = tcx.get_attrs(def_id);
+
+ match consts::trans_static(&cx, def_id, is_mutable, &attrs) {
+ Ok(_) => { /* Cool, everything's alright. */ },
+ Err(err) => {
+ err.report(tcx, tcx.def_span(def_id), "static");
+ }
+ };
}
MonoItem::GlobalAsm(node_id) => {
let item = cx.tcx.hir.expect_item(node_id);
debug!("symbol {}", &symbol_name);
match *self.as_mono_item() {
- MonoItem::Static(node_id) => {
- predefine_static(cx, node_id, linkage, visibility, &symbol_name);
+ MonoItem::Static(def_id) => {
+ predefine_static(cx, def_id, linkage, visibility, &symbol_name);
}
MonoItem::Fn(instance) => {
predefine_fn(cx, instance, linkage, visibility, &symbol_name);
impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {}
fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- node_id: ast::NodeId,
+ def_id: DefId,
linkage: Linkage,
visibility: Visibility,
symbol_name: &str) {
- let def_id = cx.tcx.hir.local_def_id(node_id);
let instance = Instance::mono(cx.tcx, def_id);
let ty = instance.ty(cx.tcx);
let llty = cx.layout_of(ty).llvm_type(cx);
let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| {
- cx.sess().span_fatal(cx.tcx.hir.span(node_id),
+ cx.sess().span_fatal(cx.tcx.def_span(def_id),
&format!("symbol `{}` is already defined", symbol_name))
});
use hir::def_id::DefId;
use middle::resolve_lifetime as rl;
use namespace::Namespace;
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
use rustc::traits;
use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::wf::object_region_bounds;
// Replace all lifetimes with 'static
for subst in &mut substs {
- if let Some(_) = subst.as_region() {
+ if let UnpackedKind::Lifetime(_) = subst.unpack() {
*subst = Kind::from(&RegionKind::ReStatic);
}
}
// Fill in our own generics with the resolved lifetimes
assert_eq!(lifetimes.len(), generics.own_count());
- substs.extend(lifetimes.iter().map(|lt|
- Kind::from(self.ast_region_to_region(lt, None))));
+ substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None))));
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
err.emit();
}
}
+ } else if let PatKind::Ref(..) = pat.node {
+ // When you encounter a `&pat` pattern, reset to "by
+ // value". This is so that `x` and `y` here are by value,
+ // as they appear to be:
+ //
+ // ```
+ // match &(&22, &44) {
+ // (&x, &y) => ...
+ // }
+ // ```
+ //
+ // cc #46688
+ def_bm = ty::BindByValue(hir::MutImmutable);
}
// Lose mutability now that we know binding mode and discriminant type.
use rustc::infer::{self, InferOk};
use rustc::infer::outlives::env::OutlivesEnvironment;
use rustc::middle::region;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::{self, Reveal, ObligationCause};
use util::common::ErrorReported;
}
for outlive in outlives {
- if let Some(r) = outlive.as_region() {
- rcx.sub_regions(origin(), parent_scope, r);
- } else if let Some(ty) = outlive.as_type() {
- rcx.type_must_outlive(origin(), ty, parent_scope);
+ match outlive.unpack() {
+ UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt),
+ UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
}
}
}
use super::{FnCtxt, Needs};
use super::method::MethodCallee;
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef};
+use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin;
use errors;
let mutbl = match mt.mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded binary ops.
- allow_two_phase_borrow: false,
+ // Allow two-phase borrows for binops in initial deployment
+ // since they desugar to methods
+ allow_two_phase_borrow: true,
}
};
let autoref = Adjustment {
let mutbl = match mt.mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded binary ops.
- allow_two_phase_borrow: false,
+ // Allow two-phase borrows for binops in initial deployment
+ // since they desugar to methods
+ allow_two_phase_borrow: true,
}
};
let autoref = Adjustment {
if let Some(missing_trait) = missing_trait {
if missing_trait == "std::ops::Add" &&
- self.check_str_addition(expr, lhs_expr, lhs_ty,
+ self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
rhs_ty, &mut err) {
// This has nothing here because it means we did string
// concatenation (e.g. "Hello " + "World!"). This means
fn check_str_addition(&self,
expr: &'gcx hir::Expr,
lhs_expr: &'gcx hir::Expr,
+ rhs_expr: &'gcx hir::Expr,
lhs_ty: Ty<'tcx>,
rhs_ty: Ty<'tcx>,
err: &mut errors::DiagnosticBuilder) -> bool {
+ let codemap = self.tcx.sess.codemap();
+ let msg = "`to_owned()` can be used to create an owned `String` \
+ from a string reference. String concatenation \
+ appends the string on the right to the string \
+ on the left and may require reallocation. This \
+ requires ownership of the string on the left";
// If this function returns true it means a note was printed, so we don't need
// to print the normal "implementation of `std::ops::Add` might be missing" note
- let mut is_string_addition = false;
- if let TyRef(_, l_ty) = lhs_ty.sty {
- if let TyRef(_, r_ty) = rhs_ty.sty {
- if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
- err.span_label(expr.span,
- "`+` can't be used to concatenate two `&str` strings");
- let codemap = self.tcx.sess.codemap();
- let suggestion =
- match codemap.span_to_snippet(lhs_expr.span) {
- Ok(lstring) => format!("{}.to_owned()", lstring),
- _ => format!("<expression>")
- };
- err.span_suggestion(lhs_expr.span,
- &format!("`to_owned()` can be used to create an owned `String` \
- from a string reference. String concatenation \
- appends the string on the right to the string \
- on the left and may require reallocation. This \
- requires ownership of the string on the left"), suggestion);
- is_string_addition = true;
- }
-
+ match (&lhs_ty.sty, &rhs_ty.sty) {
+ (&TyRef(_, ref l_ty), &TyRef(_, ref r_ty))
+ if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => {
+ err.span_label(expr.span,
+ "`+` can't be used to concatenate two `&str` strings");
+ match codemap.span_to_snippet(lhs_expr.span) {
+ Ok(lstring) => err.span_suggestion(lhs_expr.span,
+ msg,
+ format!("{}.to_owned()", lstring)),
+ _ => err.help(msg),
+ };
+ true
}
-
+ (&TyRef(_, ref l_ty), &TyAdt(..))
+ if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => {
+ err.span_label(expr.span,
+ "`+` can't be used to concatenate a `&str` with a `String`");
+ match codemap.span_to_snippet(lhs_expr.span) {
+ Ok(lstring) => err.span_suggestion(lhs_expr.span,
+ msg,
+ format!("{}.to_owned()", lstring)),
+ _ => err.help(msg),
+ };
+ match codemap.span_to_snippet(rhs_expr.span) {
+ Ok(rstring) => {
+ err.span_suggestion(rhs_expr.span,
+ "you also need to borrow the `String` on the right to \
+ get a `&str`",
+ format!("&{}", rstring));
+ }
+ _ => {}
+ };
+ true
+ }
+ _ => false,
}
-
- is_string_addition
}
pub fn check_user_unop(&self,
//! We walk the set of items and, for each member, generate new constraints.
use hir::def_id::DefId;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use syntax::ast;
use rustc::hir;
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
variance_decl,
variance_i);
- if let Some(ty) = k.as_type() {
- self.add_constraints_from_ty(current, ty, variance_i);
- } else if let Some(r) = k.as_region() {
- self.add_constraints_from_region(current, r, variance_i);
- } else {
- bug!();
+ match k.unpack() {
+ UnpackedKind::Lifetime(lt) => {
+ self.add_constraints_from_region(current, lt, variance_i)
+ }
+ UnpackedKind::Type(ty) => {
+ self.add_constraints_from_ty(current, ty, variance_i)
+ }
}
}
}
}
pub fn record_extern_trait(cx: &DocContext, did: DefId) {
- cx.external_traits.borrow_mut().entry(did).or_insert_with(|| {
- build_external_trait(cx, did)
- });
+ if cx.external_traits.borrow().contains_key(&did) ||
+ cx.active_extern_traits.borrow().contains(&did)
+ {
+ return;
+ }
+
+ cx.active_extern_traits.borrow_mut().push(did);
+
+ let trait_ = build_external_trait(cx, did);
+
+ cx.external_traits.borrow_mut().insert(did, trait_);
+ cx.active_extern_traits.borrow_mut().remove_item(&did);
}
pub renderinfo: RefCell<RenderInfo>,
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,
+ /// Used while populating `external_traits` to ensure we don't process the same trait twice at
+ /// the same time.
+ pub active_extern_traits: RefCell<Vec<DefId>>,
// The current set of type and lifetime substitutions,
// for expanding type aliases at the HIR level:
populated_all_crate_impls: Cell::new(false),
access_levels: RefCell::new(access_levels),
external_traits: Default::default(),
+ active_extern_traits: Default::default(),
renderinfo: Default::default(),
ty_substs: Default::default(),
lt_substs: Default::default(),
/// # Examples
///
/// ```
- /// #![feature(entry_and_modify)]
/// use std::collections::HashMap;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
/// .or_insert(42);
/// assert_eq!(map["poneyland"], 43);
/// ```
- #[unstable(feature = "entry_and_modify", issue = "44733")]
+ #[stable(feature = "entry_and_modify", since = "1.26.0")]
pub fn and_modify<F>(self, mut f: F) -> Self
where F: FnMut(&mut V)
{
// The runtime entry point and a few unstable public functions used by the
// compiler
pub mod rt;
-// The trait to support returning arbitrary types in the main function
-mod termination;
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-pub use self::termination::Termination;
// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
/// 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 `..`.
+ /// Returns [`None`] if the path terminates in `..`.
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
///
::sys::os::getpid()
}
+#[cfg(target_arch = "wasm32")]
+mod exit {
+ pub const SUCCESS: i32 = 0;
+ pub const FAILURE: i32 = 1;
+}
+#[cfg(not(target_arch = "wasm32"))]
+mod exit {
+ use libc;
+ pub const SUCCESS: i32 = libc::EXIT_SUCCESS;
+ pub const FAILURE: i32 = libc::EXIT_FAILURE;
+}
+
+/// A trait for implementing arbitrary return types in the `main` function.
+///
+/// The c-main function only supports to return integers as return type.
+/// So, every type implementing the `Termination` trait has to be converted
+/// to an integer.
+///
+/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
+/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
+#[cfg_attr(not(test), lang = "termination")]
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[rustc_on_unimplemented =
+ "`main` can only return types that implement {Termination}, not `{Self}`"]
+pub trait Termination {
+ /// Is called to get the representation of the value as status code.
+ /// This status code is returned to the operating system.
+ fn report(self) -> i32;
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for () {
+ fn report(self) -> i32 { exit::SUCCESS }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl<T: Termination, E: fmt::Debug> Termination for Result<T, E> {
+ fn report(self) -> i32 {
+ match self {
+ Ok(val) => val.report(),
+ Err(err) => {
+ eprintln!("Error: {:?}", err);
+ exit::FAILURE
+ }
+ }
+ }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for ! {
+ fn report(self) -> i32 { unreachable!(); }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for bool {
+ fn report(self) -> i32 {
+ if self { exit::SUCCESS } else { exit::FAILURE }
+ }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for i32 {
+ fn report(self) -> i32 {
+ self
+ }
+}
+
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
mod tests {
use io::prelude::*;
#[cfg(not(test))]
#[lang = "start"]
-fn lang_start<T: ::termination::Termination + 'static>
+fn lang_start<T: ::process::Termination + 'static>
(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
{
lang_start_internal(&move || main().report(), argc, argv)
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
-use time::Duration;
+use time::{Duration, Instant};
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
}
}
+ /// Blocks the current thread until this condition variable receives a
+ /// notification and the required condition is met. Spurious wakeups are
+ /// ignored and this function will only return once the condition has been
+ /// met.
+ ///
+ /// This function will atomically unlock the mutex specified (represented by
+ /// `guard`) and block the current thread. This means that any calls
+ /// to [`notify_one`] or [`notify_all`] which happen logically after the
+ /// mutex is unlocked are candidates to wake this thread up. When this
+ /// function call returns, the lock specified will have been re-acquired.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the mutex being waited on is
+ /// poisoned when this thread re-acquires the lock. For more information,
+ /// see information about [poisoning] on the [`Mutex`] type.
+ ///
+ /// [`notify_one`]: #method.notify_one
+ /// [`notify_all`]: #method.notify_all
+ /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+ /// [`Mutex`]: ../sync/struct.Mutex.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(wait_until)]
+ ///
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// // As long as the value inside the `Mutex` is false, we wait.
+ /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap();
+ /// ```
+ #[unstable(feature = "wait_until", issue = "47960")]
+ pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+ mut condition: F)
+ -> LockResult<MutexGuard<'a, T>>
+ where F: FnMut(&mut T) -> bool {
+ while !condition(&mut *guard) {
+ guard = self.wait(guard)?;
+ }
+ Ok(guard)
+ }
+
+
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
- /// the system time.
+ /// the system time. This function is susceptible to spurious wakeups.
+ /// Condition variables normally have a boolean predicate associated with
+ /// them, and the predicate must always be checked each time this function
+ /// returns to protect against spurious wakeups. Additionally, it is
+ /// typically desirable for the time-out to not exceed some duration in
+ /// spite of spurious wakes, thus the sleep-duration is decremented by the
+ /// amount slept. Alternatively, use the `wait_timeout_until` method
+ /// to wait until a condition is met with a total time-out regardless
+ /// of spurious wakes.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: #method.wait
+ /// [`wait_timeout_until`]: #method.wait_timeout_until
/// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
///
/// # Examples
}
}
+ /// Waits on this condition variable for a notification, timing out after a
+ /// specified duration. Spurious wakes will not cause this function to
+ /// return.
+ ///
+ /// The semantics of this function are equivalent to [`wait_until`] except
+ /// that the thread will be blocked for roughly no longer than `dur`. This
+ /// method should not be used for precise timing due to anomalies such as
+ /// preemption or platform differences that may not cause the maximum
+ /// amount of time waited to be precisely `dur`.
+ ///
+ /// Note that the best effort is made to ensure that the time waited is
+ /// measured with a monotonic clock, and not affected by the changes made to
+ /// the system time.
+ ///
+ /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+ /// known to have elapsed without the condition being met.
+ ///
+ /// Like [`wait_until`], the lock specified will be re-acquired when this
+ /// function returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait_until`]: #method.wait_until
+ /// [`wait_timeout`]: #method.wait_timeout
+ /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(wait_timeout_until)]
+ ///
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // wait for the thread to start up
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let result = cvar.wait_timeout_until(
+ /// lock.lock().unwrap(),
+ /// Duration::from_millis(100),
+ /// |&mut started| started,
+ /// ).unwrap();
+ /// if result.1.timed_out() {
+ /// // timed-out without the condition ever evaluating to true.
+ /// }
+ /// // access the locked mutex via result.0
+ /// ```
+ #[unstable(feature = "wait_timeout_until", issue = "47960")]
+ pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+ dur: Duration, mut condition: F)
+ -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
+ where F: FnMut(&mut T) -> bool {
+ let start = Instant::now();
+ loop {
+ if condition(&mut *guard) {
+ return Ok((guard, WaitTimeoutResult(false)));
+ }
+ let timeout = match dur.checked_sub(start.elapsed()) {
+ Some(timeout) => timeout,
+ None => return Ok((guard, WaitTimeoutResult(true))),
+ };
+ guard = self.wait_timeout(guard, timeout)?.0;
+ }
+ }
+
/// Wakes up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
#[cfg(test)]
mod tests {
+ /// #![feature(wait_until)]
use sync::mpsc::channel;
use sync::{Condvar, Mutex, Arc};
use sync::atomic::{AtomicBool, Ordering};
}
}
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_until() {
+ let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ let pair2 = pair.clone();
+
+ // Inside of our lock, spawn a new thread, and then wait for it to start.
+ thread::spawn(move|| {
+ let &(ref lock, ref cvar) = &*pair2;
+ let mut started = lock.lock().unwrap();
+ *started = true;
+ // We notify the condvar that the value has changed.
+ cvar.notify_one();
+ });
+
+ // Wait for the thread to start up.
+ let &(ref lock, ref cvar) = &*pair;
+ let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
+ *started
+ });
+ assert!(*guard.unwrap());
+ }
+
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wait() {
}
}
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_timeout_until_wait() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ let g = m.lock().unwrap();
+ let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap();
+ // no spurious wakeups. ensure it timed-out
+ assert!(wait.timed_out());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_timeout_until_instant_satisfy() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ let g = m.lock().unwrap();
+ let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap();
+ // ensure it didn't time-out even if we were not given any time.
+ assert!(!wait.timed_out());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_timeout_until_wake() {
+ let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ let pair_copy = pair.clone();
+
+ let &(ref m, ref c) = &*pair;
+ let g = m.lock().unwrap();
+ let _t = thread::spawn(move || {
+ let &(ref lock, ref cvar) = &*pair_copy;
+ let mut started = lock.lock().unwrap();
+ thread::sleep(Duration::from_millis(1));
+ *started = true;
+ cvar.notify_one();
+ });
+ let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| {
+ notified
+ }).unwrap();
+ // ensure it didn't time-out even if we were not given any time.
+ assert!(!wait.timed_out());
+ assert!(*g2);
+ }
+
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wake() {
+++ /dev/null
-// 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 fmt::Debug;
-#[cfg(target_arch = "wasm32")]
-mod exit {
- pub const SUCCESS: i32 = 0;
- pub const FAILURE: i32 = 1;
-}
-#[cfg(not(target_arch = "wasm32"))]
-mod exit {
- use libc;
- pub const SUCCESS: i32 = libc::EXIT_SUCCESS;
- pub const FAILURE: i32 = libc::EXIT_FAILURE;
-}
-
-/// A trait for implementing arbitrary return types in the `main` function.
-///
-/// The c-main function only supports to return integers as return type.
-/// So, every type implementing the `Termination` trait has to be converted
-/// to an integer.
-///
-/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
-/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
-#[cfg_attr(not(test), lang = "termination")]
-#[unstable(feature = "termination_trait", issue = "43301")]
-#[rustc_on_unimplemented =
- "`main` can only return types that implement {Termination}, not `{Self}`"]
-pub trait Termination {
- /// Is called to get the representation of the value as status code.
- /// This status code is returned to the operating system.
- fn report(self) -> i32;
-}
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-impl Termination for () {
- fn report(self) -> i32 { exit::SUCCESS }
-}
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-impl<T: Termination, E: Debug> Termination for Result<T, E> {
- fn report(self) -> i32 {
- match self {
- Ok(val) => val.report(),
- Err(err) => {
- eprintln!("Error: {:?}", err);
- exit::FAILURE
- }
- }
- }
-}
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-impl Termination for ! {
- fn report(self) -> i32 { unreachable!(); }
-}
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-impl Termination for bool {
- fn report(self) -> i32 {
- if self { exit::SUCCESS } else { exit::FAILURE }
- }
-}
-
-#[unstable(feature = "termination_trait", issue = "43301")]
-impl Termination for i32 {
- fn report(self) -> i32 {
- self
- }
-}
/// `if let pat = expr { block } else { expr }`
///
/// This is desugared to a `match` expression.
- IfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
+ IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
/// A while loop, with an optional label
///
/// `'label: while expr { block }`
/// `'label: while let pat = expr { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
- WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>),
+ WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
/// A for loop, with an optional label
///
/// `'label: for pat in expr { block }`
types: Vec<P<ast::Ty>>,
bindings: Vec<ast::TypeBinding> )
-> ast::Path {
- use syntax::parse::token;
-
let last_identifier = idents.pop().unwrap();
let mut segments: Vec<ast::PathSegment> = Vec::new();
- if global &&
- !idents.first().map_or(false, |&ident| token::Ident(ident).is_path_segment_keyword()) {
- segments.push(ast::PathSegment::crate_root(span));
- }
segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, span)));
let parameters = if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
None
};
segments.push(ast::PathSegment { identifier: last_identifier, span, parameters });
- ast::Path { span, segments }
+ let path = ast::Path { span, segments };
+
+ if global { path.default_to_global() } else { path }
}
/// Constructs a qualified path.
// `foo.rs` as an alternative to `foo/mod.rs`
(active, non_modrs_mods, "1.24.0", Some(44660)),
- // Nested `impl Trait`
- (active, nested_impl_trait, "1.24.0", Some(34511)),
-
// Termination trait in main (RFC 1937)
(active, termination_trait, "1.24.0", Some(43301)),
// Use `?` as the Kleene "at most one" operator
(active, macro_at_most_once_rep, "1.25.0", Some(48075)),
+
+ // Multiple patterns with `|` in `if let` and `while let`
+ (active, if_while_or_patterns, "1.26.0", Some(48215)),
);
declare_features! (
}
}
-// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
-// Nested `impl Trait` _is_ allowed in associated type position,
-// e.g `impl Iterator<Item=impl Debug>`
-struct NestedImplTraitVisitor<'a> {
- context: &'a Context<'a>,
- is_in_impl_trait: bool,
-}
-
-impl<'a> NestedImplTraitVisitor<'a> {
- fn with_impl_trait<F>(&mut self, is_in_impl_trait: bool, f: F)
- where F: FnOnce(&mut NestedImplTraitVisitor<'a>)
- {
- let old_is_in_impl_trait = self.is_in_impl_trait;
- self.is_in_impl_trait = is_in_impl_trait;
- f(self);
- self.is_in_impl_trait = old_is_in_impl_trait;
- }
-}
-
-
-impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
- fn visit_ty(&mut self, t: &'a ast::Ty) {
- if let ast::TyKind::ImplTrait(_) = t.node {
- if self.is_in_impl_trait {
- gate_feature_post!(&self, nested_impl_trait, t.span,
- "nested `impl Trait` is experimental"
- );
- }
- self.with_impl_trait(true, |this| visit::walk_ty(this, t));
- } else {
- visit::walk_ty(self, t);
- }
- }
- fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a ast::PathParameters) {
- match *path_parameters {
- ast::PathParameters::AngleBracketed(ref params) => {
- for type_ in ¶ms.types {
- self.visit_ty(type_);
- }
- for type_binding in ¶ms.bindings {
- // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
- // are allowed to contain nested `impl Trait`.
- self.with_impl_trait(false, |this| visit::walk_ty(this, &type_binding.ty));
- }
- }
- ast::PathParameters::Parenthesized(ref params) => {
- for type_ in ¶ms.inputs {
- self.visit_ty(type_);
- }
- if let Some(ref type_) = params.output {
- // `-> Foo` syntax is essentially an associated type binding,
- // so it is also allowed to contain nested `impl Trait`.
- self.with_impl_trait(false, |this| visit::walk_ty(this, type_));
- }
- }
- }
- }
-}
-
impl<'a> PostExpansionVisitor<'a> {
- fn whole_crate_feature_gates(&mut self, krate: &ast::Crate) {
- visit::walk_crate(
- &mut NestedImplTraitVisitor {
- context: self.context,
- is_in_impl_trait: false,
- }, krate);
-
+ fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) {
for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() {
if !span.allows_unstable() {
let cx = &self.context;
ast::ExprKind::Catch(_) => {
gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
}
+ ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
+ if pats.len() > 1 {
+ gate_feature_post!(&self, if_while_or_patterns, e.span,
+ "multiple patterns in `if let` and `while let` are unstable");
+ }
+ }
_ => {}
}
visit::walk_expr(self, e);
folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x)))
}
- ExprKind::IfLet(pat, expr, tr, fl) => {
- ExprKind::IfLet(folder.fold_pat(pat),
+ ExprKind::IfLet(pats, expr, tr, fl) => {
+ ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)),
folder.fold_expr(expr),
folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x)))
folder.fold_block(body),
opt_label.map(|label| folder.fold_label(label)))
}
- ExprKind::WhileLet(pat, expr, body, opt_label) => {
- ExprKind::WhileLet(folder.fold_pat(pat),
+ ExprKind::WhileLet(pats, expr, body, opt_label) => {
+ ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)),
folder.fold_expr(expr),
folder.fold_block(body),
opt_label.map(|label| folder.fold_label(label)))
}
}
-// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
-// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
-fn can_continue_type_after_ident(t: &token::Token) -> bool {
+/// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+/// `IDENT<<u8 as Trait>::AssocTy>`.
+///
+/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes
+/// that IDENT is not the ident of a fn trait
+fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool {
t == &token::ModSep || t == &token::Lt ||
- t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+ t == &token::BinOp(token::Shl)
}
/// Information about the path to a module.
pub fn token_is_bare_fn_keyword(&mut self) -> bool {
self.check_keyword(keywords::Fn) ||
self.check_keyword(keywords::Unsafe) ||
- self.check_keyword(keywords::Extern)
+ self.check_keyword(keywords::Extern) && self.is_extern_non_path()
}
fn eat_label(&mut self) -> Option<Label> {
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
TyKind::ImplTrait(bounds)
} else if self.check_keyword(keywords::Dyn) &&
- self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+ self.look_ahead(1, |t| t.can_begin_bound() &&
+ !can_continue_type_after_non_fn_ident(t)) {
self.bump(); // `dyn`
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_ty_param_bounds()?;
-> PResult<'a, P<Expr>> {
let lo = self.prev_span;
self.expect_keyword(keywords::Let)?;
- let pat = self.parse_pat()?;
+ let pats = self.parse_pats()?;
self.expect(&token::Eq)?;
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let thn = self.parse_block()?;
} else {
(thn.span, None)
};
- Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
+ Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
}
// `move |args| expr`
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
self.expect_keyword(keywords::Let)?;
- let pat = self.parse_pat()?;
+ let pats = self.parse_pats()?;
self.expect(&token::Eq)?;
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
- return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs));
+ return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
}
// parse `loop {...}`, `loop` token already eaten
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
// UNSAFE FUNCTION ITEM
self.bump(); // `unsafe`
+ // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic
+ self.check(&token::OpenDelim(token::Brace));
let abi = if self.eat_keyword(keywords::Extern) {
self.parse_opt_abi()?.unwrap_or(Abi::C)
} else {
self.print_else(e.as_ref().map(|e| &**e))
}
// "another else-if-let"
- ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
+ ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1)?;
self.ibox(0)?;
self.s.word(" else if let ")?;
- self.print_pat(pat)?;
+ self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
self.print_else(elseopt)
}
- pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
+ pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
elseopt: Option<&ast::Expr>) -> io::Result<()> {
self.head("if let")?;
- self.print_pat(pat)?;
+ self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
}
- ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
- self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
+ ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
+ self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
}
ast::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.s.space()?;
self.print_block_with_attrs(blk, attrs)?;
}
- ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
+ ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
self.word_space(":")?;
}
self.head("while let")?;
- self.print_pat(pat)?;
+ self.print_pats(pats)?;
self.s.space()?;
self.word_space("=")?;
self.print_expr_as_cond(expr)?;
self.ann.post(self, NodePat(pat))
}
+ fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> {
+ let mut first = true;
+ for p in pats {
+ if first {
+ first = false;
+ } else {
+ self.s.space()?;
+ self.word_space("|")?;
+ }
+ self.print_pat(p)?;
+ }
+ Ok(())
+ }
+
fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
// I have no idea why this check is necessary, but here it
// is :(
self.ibox(0)?;
self.maybe_print_comment(arm.pats[0].span.lo())?;
self.print_outer_attributes(&arm.attrs)?;
- let mut first = true;
- for p in &arm.pats {
- if first {
- first = false;
- } else {
- self.s.space()?;
- self.word_space("|")?;
- }
- self.print_pat(p)?;
- }
+ self.print_pats(&arm.pats)?;
self.s.space()?;
if let Some(ref e) = arm.guard {
self.word_space("if")?;
use ext::expand::ExpansionConfig;
use ext::hygiene::{Mark, SyntaxContext};
use fold::Folder;
+use feature_gate::Features;
use util::move_map::MoveMap;
use fold;
use parse::{token, ParseSess};
reexport_test_harness_main: Option<Symbol>,
is_libtest: bool,
ctxt: SyntaxContext,
+ features: &'a Features,
// top-level re-export submodule, filled out after folding is finished
toplevel_reexport: Option<Ident>,
resolver: &mut Resolver,
should_test: bool,
krate: ast::Crate,
- span_diagnostic: &errors::Handler) -> ast::Crate {
+ span_diagnostic: &errors::Handler,
+ features: &Features) -> ast::Crate {
// Check for #[reexport_test_harness_main = "some_name"] which
// creates a `use some_name = __test::main;`. This needs to be
// unconditional, so that the attribute is still marked as used in
"reexport_test_harness_main");
if should_test {
- generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic)
+ generate_test_harness(sess, resolver, reexport_test_harness_main,
+ krate, span_diagnostic, features)
} else {
krate
}
resolver: &mut Resolver,
reexport_test_harness_main: Option<Symbol>,
krate: ast::Crate,
- sd: &errors::Handler) -> ast::Crate {
+ sd: &errors::Handler,
+ features: &Features) -> ast::Crate {
// Remove the entry points
let mut cleaner = EntryPointCleaner { depth: 0 };
let krate = cleaner.fold_crate(krate);
let mark = Mark::fresh(Mark::root());
+ let mut econfig = ExpansionConfig::default("test".to_string());
+ econfig.features = Some(features);
+
let cx = TestCtxt {
span_diagnostic: sd,
- ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver),
+ ext_cx: ExtCtxt::new(sess, econfig, resolver),
path: Vec::new(),
testfns: Vec::new(),
reexport_test_harness_main,
is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false),
toplevel_reexport: None,
ctxt: SyntaxContext::empty().apply_mark(mark),
+ features,
};
mark.set_expn_info(ExpnInfo {
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
let has_test_attr = attr::contains_name(&i.attrs, "test");
- fn has_test_signature(i: &ast::Item) -> HasTestSignature {
+ fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
match i.node {
- ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
- let no_output = match decl.output {
- ast::FunctionRetTy::Default(..) => true,
- ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
- _ => false
- };
- if decl.inputs.is_empty()
- && no_output
- && !generics.is_parameterized() {
- Yes
- } else {
- No
+ ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
+ // If the termination trait is active, the compiler will check that the output
+ // type implements the `Termination` trait as `libtest` enforces that.
+ let output_matches = if cx.features.termination_trait {
+ true
+ } else {
+ let no_output = match decl.output {
+ ast::FunctionRetTy::Default(..) => true,
+ ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
+ _ => false
+ };
+
+ no_output && !generics.is_parameterized()
+ };
+
+ if decl.inputs.is_empty() && output_matches {
+ Yes
+ } else {
+ No
+ }
}
- }
- _ => NotEvenAFunction,
+ _ => NotEvenAFunction,
}
}
- if has_test_attr {
+ let has_test_signature = if has_test_attr {
let diag = cx.span_diagnostic;
- match has_test_signature(i) {
- Yes => {},
- No => diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"),
- NotEvenAFunction => diag.span_err(i.span,
- "only functions may be used as tests"),
+ match has_test_signature(cx, i) {
+ Yes => true,
+ No => {
+ if cx.features.termination_trait {
+ diag.span_err(i.span, "functions used as tests can not have any arguments");
+ } else {
+ diag.span_err(i.span, "functions used as tests must have signature fn() -> ()");
+ }
+ false
+ },
+ NotEvenAFunction => {
+ diag.span_err(i.span, "only functions may be used as tests");
+ false
+ },
}
- }
+ } else {
+ false
+ };
- has_test_attr && has_test_signature(i) == Yes
+ has_test_attr && has_test_signature
}
fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
let has_bench_attr = attr::contains_name(&i.attrs, "bench");
- fn has_test_signature(i: &ast::Item) -> bool {
+ fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool {
match i.node {
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
let input_cnt = decl.inputs.len();
- let no_output = match decl.output {
- ast::FunctionRetTy::Default(..) => true,
- ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
- _ => false
+
+ // If the termination trait is active, the compiler will check that the output
+ // type implements the `Termination` trait as `libtest` enforces that.
+ let output_matches = if cx.features.termination_trait {
+ true
+ } else {
+ let no_output = match decl.output {
+ ast::FunctionRetTy::Default(..) => true,
+ ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
+ _ => false
+ };
+ let tparm_cnt = generics.params.iter()
+ .filter(|param| param.is_type_param())
+ .count();
+
+ no_output && tparm_cnt == 0
};
- let tparm_cnt = generics.params.iter()
- .filter(|param| param.is_type_param())
- .count();
// NB: inadequate check, but we're running
// well before resolve, can't get too deep.
- input_cnt == 1
- && no_output && tparm_cnt == 0
+ input_cnt == 1 && output_matches
}
_ => false
}
}
- if has_bench_attr && !has_test_signature(i) {
+ let has_bench_signature = has_bench_signature(cx, i);
+
+ if has_bench_attr && !has_bench_signature {
let diag = cx.span_diagnostic;
- diag.span_err(i.span, "functions used as benches must have signature \
- `fn(&mut Bencher) -> ()`");
+
+ if cx.features.termination_trait {
+ diag.span_err(i.span, "functions used as benches must have signature \
+ `fn(&mut Bencher) -> impl Termination`");
+ } else {
+ diag.span_err(i.span, "functions used as benches must have signature \
+ `fn(&mut Bencher) -> ()`");
+ }
}
- has_bench_attr && has_test_signature(i)
+ has_bench_attr && has_bench_signature
}
fn is_ignored(i: &ast::Item) -> bool {
field("should_panic", fail_expr),
field("allow_fail", allow_fail_expr)]);
-
- let mut visible_path = match cx.toplevel_reexport {
- Some(id) => vec![id],
+ let mut visible_path = vec![];
+ if cx.features.extern_absolute_paths {
+ visible_path.push(keywords::Crate.ident());
+ }
+ match cx.toplevel_reexport {
+ Some(id) => visible_path.push(id),
None => {
let diag = cx.span_diagnostic;
diag.bug("expected to find top-level re-export name, but found None");
};
visible_path.extend(path);
- let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path));
+ // Rather than directly give the test function to the test
+ // harness, we create a wrapper like one of the following:
+ //
+ // || test::assert_test_result(real_function()) // for test
+ // |b| test::assert_test_result(real_function(b)) // for bench
+ //
+ // this will coerce into a fn pointer that is specialized to the
+ // actual return type of `real_function` (Typically `()`, but not always).
+ let fn_expr = {
+ // construct `real_function()` (this will be inserted into the overall expr)
+ let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path));
+ // construct path `test::assert_test_result`
+ let assert_test_result = test_path("assert_test_result");
+ if test.bench {
+ // construct `|b| {..}`
+ let b_ident = Ident::with_empty_ctxt(Symbol::gensym("b"));
+ let b_expr = ecx.expr_ident(span, b_ident);
+ ecx.lambda(
+ span,
+ vec![b_ident],
+ // construct `assert_test_result(..)`
+ ecx.expr_call(
+ span,
+ ecx.expr_path(assert_test_result),
+ vec![
+ // construct `real_function(b)`
+ ecx.expr_call(
+ span,
+ real_function_expr,
+ vec![b_expr],
+ )
+ ],
+ ),
+ )
+ } else {
+ // construct `|| {..}`
+ ecx.lambda(
+ span,
+ vec![],
+ // construct `assert_test_result(..)`
+ ecx.expr_call(
+ span,
+ ecx.expr_path(assert_test_result),
+ vec![
+ // construct `real_function()`
+ ecx.expr_call(
+ span,
+ real_function_expr,
+ vec![],
+ )
+ ],
+ ),
+ )
+ }
+ };
let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" };
+
// self::test::$variant_name($fn_expr)
let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
- ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
- visitor.visit_pat(pattern);
+ ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
+ walk_list!(visitor, visit_pat, pats);
visitor.visit_expr(subexpression);
visitor.visit_block(if_block);
walk_list!(visitor, visit_expr, optional_else);
}
- ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => {
+ ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
- visitor.visit_pat(pattern);
+ walk_list!(visitor, visit_pat, pats);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
#![feature(set_stdio)]
#![feature(panic_unwind)]
#![feature(staged_api)]
+#![feature(termination_trait_lib)]
extern crate getopts;
extern crate term;
use std::io;
use std::iter::repeat;
use std::path::PathBuf;
+use std::process::Termination;
use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
pub mod test {
pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed,
TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName,
- DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests,
- parse_opts, StaticBenchFn, ShouldPanic, Options};
+ DynTestName, DynTestFn, assert_test_result, run_test, test_main, test_main_static,
+ filter_tests, parse_opts, StaticBenchFn, ShouldPanic, Options};
}
pub mod stats;
test_main(&args, owned_tests, Options::new())
}
+/// Invoked when unit tests terminate. Should panic if the unit
+/// test is considered a failure. By default, invokes `report()`
+/// and checks for a `0` result.
+pub fn assert_test_result<T: Termination>(result: T) {
+ assert_eq!(result.report(), 0);
+}
+
#[derive(Copy, Clone, Debug)]
pub enum ColorConfig {
AutoColor,
+++ /dev/null
-// Copyright 2013 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.
-
-// Helper functions used only in tests
-
-#include <stdint.h>
-#include <assert.h>
-#include <stdarg.h>
-
-// These functions are used in the unit tests for C ABI calls.
-
-uint32_t
-rust_dbg_extern_identity_u32(uint32_t u) {
- return u;
-}
-
-uint64_t
-rust_dbg_extern_identity_u64(uint64_t u) {
- return u;
-}
-
-double
-rust_dbg_extern_identity_double(double u) {
- return u;
-}
-
-char
-rust_dbg_extern_identity_u8(char u) {
- return u;
-}
-
-typedef void *(*dbg_callback)(void*);
-
-void *
-rust_dbg_call(dbg_callback cb, void *data) {
- return cb(data);
-}
-
-void rust_dbg_do_nothing() { }
-
-struct TwoU8s {
- uint8_t one;
- uint8_t two;
-};
-
-struct TwoU8s
-rust_dbg_extern_return_TwoU8s() {
- struct TwoU8s s;
- s.one = 10;
- s.two = 20;
- return s;
-}
-
-struct TwoU8s
-rust_dbg_extern_identity_TwoU8s(struct TwoU8s u) {
- return u;
-}
-
-struct TwoU16s {
- uint16_t one;
- uint16_t two;
-};
-
-struct TwoU16s
-rust_dbg_extern_return_TwoU16s() {
- struct TwoU16s s;
- s.one = 10;
- s.two = 20;
- return s;
-}
-
-struct TwoU16s
-rust_dbg_extern_identity_TwoU16s(struct TwoU16s u) {
- return u;
-}
-
-struct TwoU32s {
- uint32_t one;
- uint32_t two;
-};
-
-struct TwoU32s
-rust_dbg_extern_return_TwoU32s() {
- struct TwoU32s s;
- s.one = 10;
- s.two = 20;
- return s;
-}
-
-struct TwoU32s
-rust_dbg_extern_identity_TwoU32s(struct TwoU32s u) {
- return u;
-}
-
-struct TwoU64s {
- uint64_t one;
- uint64_t two;
-};
-
-struct TwoU64s
-rust_dbg_extern_return_TwoU64s() {
- struct TwoU64s s;
- s.one = 10;
- s.two = 20;
- return s;
-}
-
-struct TwoU64s
-rust_dbg_extern_identity_TwoU64s(struct TwoU64s u) {
- return u;
-}
-
-struct TwoDoubles {
- double one;
- double two;
-};
-
-struct TwoDoubles
-rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
- return u;
-}
-
-struct ManyInts {
- int8_t arg1;
- int16_t arg2;
- int32_t arg3;
- int16_t arg4;
- int8_t arg5;
- struct TwoU8s arg6;
-};
-
-// MSVC doesn't allow empty structs or unions
-#ifndef _MSC_VER
-struct Empty {
-};
-
-void
-rust_dbg_extern_empty_struct(struct ManyInts v1, struct Empty e, struct ManyInts v2) {
- assert(v1.arg1 == v2.arg1 + 1);
- assert(v1.arg2 == v2.arg2 + 1);
- assert(v1.arg3 == v2.arg3 + 1);
- assert(v1.arg4 == v2.arg4 + 1);
- assert(v1.arg5 == v2.arg5 + 1);
- assert(v1.arg6.one == v2.arg6.one + 1);
- assert(v1.arg6.two == v2.arg6.two + 1);
-}
-#endif
-
-intptr_t
-rust_get_test_int() {
- return 1;
-}
-
-char *
-rust_get_null_ptr() {
- return 0;
-}
-
-/* Debug helpers strictly to verify ABI conformance.
- *
- * FIXME (#2665): move these into a testcase when the testsuite
- * understands how to have explicit C files included.
- */
-
-struct quad {
- uint64_t a;
- uint64_t b;
- uint64_t c;
- uint64_t d;
-};
-
-struct floats {
- double a;
- uint8_t b;
- double c;
-};
-
-struct quad
-rust_dbg_abi_1(struct quad q) {
- struct quad qq = { q.c + 1,
- q.d - 1,
- q.a + 1,
- q.b - 1 };
- return qq;
-}
-
-struct floats
-rust_dbg_abi_2(struct floats f) {
- struct floats ff = { f.c + 1.0,
- 0xff,
- f.a - 1.0 };
- return ff;
-}
-
-int
-rust_dbg_static_mut = 3;
-
-void
-rust_dbg_static_mut_check_four() {
- assert(rust_dbg_static_mut == 4);
-}
-
-struct S {
- uint64_t x;
- uint64_t y;
- uint64_t z;
-};
-
-uint64_t get_x(struct S s) {
- return s.x;
-}
-
-uint64_t get_y(struct S s) {
- return s.y;
-}
-
-uint64_t get_z(struct S s) {
- return s.z;
-}
-
-uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
- return f.c;
-}
-
-// Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs
-// passed as variadic arguments.
-double rust_interesting_average(uint64_t n, ...) {
- va_list pairs;
- double sum = 0.0;
- int i;
- va_start(pairs, n);
- for(i = 0; i < n; i += 1) {
- sum += (double)va_arg(pairs, int64_t);
- sum += va_arg(pairs, double);
- }
- va_end(pairs);
- return sum / n;
-}
-
-int32_t rust_int8_to_int32(int8_t x) {
- return (int32_t)x;
-}
-
-typedef union LARGE_INTEGER {
- struct {
- uint32_t LowPart;
- uint32_t HighPart;
- };
- struct {
- uint32_t LowPart;
- uint32_t HighPart;
- } u;
- uint64_t QuadPart;
-} LARGE_INTEGER;
-
-LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
- li.LowPart += 1;
- li.HighPart += 1;
- li.u.LowPart += 1;
- li.u.HighPart += 1;
- li.QuadPart += 1;
- return li;
-}
-
-#if __SIZEOF_INT128__ == 16
-
-unsigned __int128 identity(unsigned __int128 a) {
- return a;
-}
-
-__int128 square(__int128 a) {
- return a * a;
-}
-
-__int128 sub(__int128 a, __int128 b) {
- return a - b;
-}
-
-#endif
--- /dev/null
+// Copyright 2013 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.
+
+// Helper functions used only in tests
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdarg.h>
+
+// These functions are used in the unit tests for C ABI calls.
+
+uint32_t
+rust_dbg_extern_identity_u32(uint32_t u) {
+ return u;
+}
+
+uint64_t
+rust_dbg_extern_identity_u64(uint64_t u) {
+ return u;
+}
+
+double
+rust_dbg_extern_identity_double(double u) {
+ return u;
+}
+
+char
+rust_dbg_extern_identity_u8(char u) {
+ return u;
+}
+
+typedef void *(*dbg_callback)(void*);
+
+void *
+rust_dbg_call(dbg_callback cb, void *data) {
+ return cb(data);
+}
+
+void rust_dbg_do_nothing() { }
+
+struct TwoU8s {
+ uint8_t one;
+ uint8_t two;
+};
+
+struct TwoU8s
+rust_dbg_extern_return_TwoU8s() {
+ struct TwoU8s s;
+ s.one = 10;
+ s.two = 20;
+ return s;
+}
+
+struct TwoU8s
+rust_dbg_extern_identity_TwoU8s(struct TwoU8s u) {
+ return u;
+}
+
+struct TwoU16s {
+ uint16_t one;
+ uint16_t two;
+};
+
+struct TwoU16s
+rust_dbg_extern_return_TwoU16s() {
+ struct TwoU16s s;
+ s.one = 10;
+ s.two = 20;
+ return s;
+}
+
+struct TwoU16s
+rust_dbg_extern_identity_TwoU16s(struct TwoU16s u) {
+ return u;
+}
+
+struct TwoU32s {
+ uint32_t one;
+ uint32_t two;
+};
+
+struct TwoU32s
+rust_dbg_extern_return_TwoU32s() {
+ struct TwoU32s s;
+ s.one = 10;
+ s.two = 20;
+ return s;
+}
+
+struct TwoU32s
+rust_dbg_extern_identity_TwoU32s(struct TwoU32s u) {
+ return u;
+}
+
+struct TwoU64s {
+ uint64_t one;
+ uint64_t two;
+};
+
+struct TwoU64s
+rust_dbg_extern_return_TwoU64s() {
+ struct TwoU64s s;
+ s.one = 10;
+ s.two = 20;
+ return s;
+}
+
+struct TwoU64s
+rust_dbg_extern_identity_TwoU64s(struct TwoU64s u) {
+ return u;
+}
+
+struct TwoDoubles {
+ double one;
+ double two;
+};
+
+struct TwoDoubles
+rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
+ return u;
+}
+
+struct ManyInts {
+ int8_t arg1;
+ int16_t arg2;
+ int32_t arg3;
+ int16_t arg4;
+ int8_t arg5;
+ struct TwoU8s arg6;
+};
+
+// MSVC doesn't allow empty structs or unions
+#ifndef _MSC_VER
+struct Empty {
+};
+
+void
+rust_dbg_extern_empty_struct(struct ManyInts v1, struct Empty e, struct ManyInts v2) {
+ assert(v1.arg1 == v2.arg1 + 1);
+ assert(v1.arg2 == v2.arg2 + 1);
+ assert(v1.arg3 == v2.arg3 + 1);
+ assert(v1.arg4 == v2.arg4 + 1);
+ assert(v1.arg5 == v2.arg5 + 1);
+ assert(v1.arg6.one == v2.arg6.one + 1);
+ assert(v1.arg6.two == v2.arg6.two + 1);
+}
+#endif
+
+intptr_t
+rust_get_test_int() {
+ return 1;
+}
+
+char *
+rust_get_null_ptr() {
+ return 0;
+}
+
+/* Debug helpers strictly to verify ABI conformance.
+ *
+ * FIXME (#2665): move these into a testcase when the testsuite
+ * understands how to have explicit C files included.
+ */
+
+struct quad {
+ uint64_t a;
+ uint64_t b;
+ uint64_t c;
+ uint64_t d;
+};
+
+struct floats {
+ double a;
+ uint8_t b;
+ double c;
+};
+
+struct quad
+rust_dbg_abi_1(struct quad q) {
+ struct quad qq = { q.c + 1,
+ q.d - 1,
+ q.a + 1,
+ q.b - 1 };
+ return qq;
+}
+
+struct floats
+rust_dbg_abi_2(struct floats f) {
+ struct floats ff = { f.c + 1.0,
+ 0xff,
+ f.a - 1.0 };
+ return ff;
+}
+
+int
+rust_dbg_static_mut = 3;
+
+void
+rust_dbg_static_mut_check_four() {
+ assert(rust_dbg_static_mut == 4);
+}
+
+struct S {
+ uint64_t x;
+ uint64_t y;
+ uint64_t z;
+};
+
+uint64_t get_x(struct S s) {
+ return s.x;
+}
+
+uint64_t get_y(struct S s) {
+ return s.y;
+}
+
+uint64_t get_z(struct S s) {
+ return s.z;
+}
+
+uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
+ return f.c;
+}
+
+// Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs
+// passed as variadic arguments.
+double rust_interesting_average(uint64_t n, ...) {
+ va_list pairs;
+ double sum = 0.0;
+ int i;
+ va_start(pairs, n);
+ for(i = 0; i < n; i += 1) {
+ sum += (double)va_arg(pairs, int64_t);
+ sum += va_arg(pairs, double);
+ }
+ va_end(pairs);
+ return sum / n;
+}
+
+int32_t rust_int8_to_int32(int8_t x) {
+ return (int32_t)x;
+}
+
+typedef union LARGE_INTEGER {
+ struct {
+ uint32_t LowPart;
+ uint32_t HighPart;
+ };
+ struct {
+ uint32_t LowPart;
+ uint32_t HighPart;
+ } u;
+ uint64_t QuadPart;
+} LARGE_INTEGER;
+
+LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
+ li.LowPart += 1;
+ li.HighPart += 1;
+ li.u.LowPart += 1;
+ li.u.HighPart += 1;
+ li.QuadPart += 1;
+ return li;
+}
+
+#if __SIZEOF_INT128__ == 16
+
+unsigned __int128 identity(unsigned __int128 a) {
+ return a;
+}
+
+__int128 square(__int128 a) {
+ return a * a;
+}
+
+__int128 sub(__int128 a, __int128 b) {
+ return a - b;
+}
+
+#endif
// #![feature(rustc_attrs)]
use std::ops::{Index, IndexMut};
-use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
-use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
// This is case outlined by Niko that we want to ensure we reject
// (at least initially).
//[lxl]~^^^ ERROR use of moved value: `*f`
//[nll]~^^^^ ERROR cannot move a value of type
//[nll]~^^^^^ ERROR cannot move a value of type
- //[nll]~^^^^^^ ERROR cannot move a value of type
- //[nll]~^^^^^^^ ERROR cannot move a value of type
- //[nll]~^^^^^^^^ ERROR use of moved value: `*f`
- //[g2p]~^^^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^^^^^^ ERROR use of moved value: `*f`
+ //[nll]~^^^^^^ ERROR use of moved value: `*f`
+ //[g2p]~^^^^^^^ ERROR cannot move a value of type
+ //[g2p]~^^^^^^^^ ERROR cannot move a value of type
+ //[g2p]~^^^^^^^^^ ERROR use of moved value: `*f`
}
twice_ten_sm(&mut |x| x + 1);
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
}
-struct A(i32);
-
-macro_rules! trivial_binop {
- ($Trait:ident, $m:ident) => {
- impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
- }
-}
-
-trivial_binop!(AddAssign, add_assign);
-trivial_binop!(SubAssign, sub_assign);
-trivial_binop!(MulAssign, mul_assign);
-trivial_binop!(DivAssign, div_assign);
-trivial_binop!(RemAssign, rem_assign);
-trivial_binop!(BitAndAssign, bitand_assign);
-trivial_binop!(BitOrAssign, bitor_assign);
-trivial_binop!(BitXorAssign, bitxor_assign);
-trivial_binop!(ShlAssign, shl_assign);
-trivial_binop!(ShrAssign, shr_assign);
-
-fn overloaded_binops() {
- let mut a = A(10);
- a += a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a -= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a *= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a /= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a &= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a |= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a ^= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a <<= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
- a >>= a.0;
- //[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
- //[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
-}
-
fn main() {
// As a reminder, this is the basic case we want to ensure we handle.
coerce_unsized();
coerce_index_op();
- overloaded_binops();
}
#![feature(specialization)]
trait Trait<T> { type Assoc; }
-//~^ unsupported cyclic reference between types/traits detected [E0391]
+//~^ cyclic dependency detected [E0391]
impl<T> Trait<T> for Vec<T> {
type Assoc = ();
+++ /dev/null
-// Copyright 2012 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.
-
-const a: isize = b; //~ ERROR recursive constant
-const b: isize = a; //~ ERROR recursive constant
-
-fn main() {
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unsupported cyclic reference between types/traits detected
+// error-pattern: cyclic dependency detected
#![feature(const_fn)]
struct A<T>
where T : Trait,
T : Add<T::Item>
- //~^ ERROR unsupported cyclic reference between types/traits detected
+ //~^ ERROR cyclic dependency detected
//~| ERROR associated type `Item` not found for `T`
{
data: T
// again references the trait.
trait Foo<X = Box<Foo>> {
- //~^ ERROR unsupported cyclic reference
+ //~^ ERROR cyclic dependency detected
}
fn main() { }
// Test a supertrait cycle where a trait extends itself.
trait Chromosome: Chromosome {
- //~^ ERROR unsupported cyclic reference
+ //~^ ERROR cyclic dependency detected
}
fn main() { }
//~^ ERROR cannot find type `dyn` in this scope
//~| ERROR cannot find type `dyn` in this scope
//~| ERROR Use of undeclared type or module `dyn`
-type A4 = dyn(dyn, dyn) -> dyn;
-//~^ ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
fn main() {}
+++ /dev/null
-// 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(conservative_impl_trait, universal_impl_trait)]
-
-use std::fmt::Debug;
-
-fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
-
-fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-//~^ ERROR nested `impl Trait` is experimental
-
-fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
-//~^ ERROR nested `impl Trait` is experimental
-
-fn bad_in_arg_position(_: impl Into<impl Debug>) { }
-//~^ ERROR nested `impl Trait` is experimental
-
-struct X;
-impl X {
- fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
- //~^ ERROR nested `impl Trait` is experimental
-}
-
-fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
- vec![|| println!("woot")].into_iter()
-}
-
-fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
- || 5
-}
-
-fn main() {}
//! A simple test for testing many permutations of allowedness of
//! impl Trait
-#![feature(conservative_impl_trait, nested_impl_trait, universal_impl_trait, dyn_trait)]
+#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)]
use std::fmt::Debug;
// Allowed
// Disallowed
fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+//~^^ ERROR nested `impl Trait` is not allowed
// Disallowed
fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
// Disallowed
fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+//~^^ ERROR nested `impl Trait` is not allowed
// Disallowed
fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
// except according to those terms.
type x = Vec<x>;
-//~^ ERROR unsupported cyclic reference
+//~^ ERROR cyclic dependency detected
fn main() { let b: x = Vec::new(); }
#[bench]
fn bar(x: isize) { }
//~^ ERROR mismatched types
-//~| expected type `for<'r> fn(&'r mut __test::test::Bencher)`
-//~| found type `fn(isize) {bar}`
-//~| expected mutable reference, found isize
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const FOO: usize = FOO; //~ ERROR recursive constant
+const FOO: usize = FOO; //~ ERROR E0391
fn main() {
let _x: [u8; FOO]; // caused stack overflow prior to fix
let _y: usize = 1 + {
- const BAR: usize = BAR; //~ ERROR recursive constant
+ const BAR: usize = BAR;
let _z: [u8; BAR]; // caused stack overflow prior to fix
1
};
+++ /dev/null
-// Copyright 2014 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.
-
-const A: usize = B; //~ ERROR: recursive constant
-const B: usize = A; //~ ERROR: recursive constant
-
-fn main() {}
// except according to those terms.
trait T : Iterator<Item=Self::Item>
-//~^ ERROR unsupported cyclic reference between types/traits detected
+//~^ ERROR cyclic dependency detected
//~| ERROR associated type `Item` not found for `Self`
{}
}
pub trait Processor: Subscriber<Input = Self::Input> {
- //~^ ERROR unsupported cyclic reference between types/traits detected [E0391]
+ //~^ ERROR cyclic dependency detected [E0391]
type Input;
}
}
fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR unsupported cyclic reference between types/traits detected
+//~^ ERROR cyclic dependency detected
//~| ERROR associated type `B` not found for `T`
fn main() { }
// except according to those terms.
trait Expr : PartialEq<Self::Item> {
- //~^ ERROR: unsupported cyclic reference between types/traits detected
+ //~^ ERROR: cyclic dependency detected
type Item;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unsupported cyclic reference between types/traits detected
+// error-pattern: cyclic dependency detected
// note-pattern: the cycle begins when computing layout of
// note-pattern: ...which then requires computing layout of
// note-pattern: ...which then again requires computing layout of
}
pub struct Foo<T = Box<Trait<DefaultFoo>>>;
-type DefaultFoo = Foo; //~ ERROR unsupported cyclic reference
+type DefaultFoo = Foo; //~ ERROR cyclic dependency detected
fn main() {
}
struct Foo {
bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- //~^ ERROR unsupported cyclic reference between types/traits detected
+ //~^ ERROR cyclic dependency detected
x: usize,
}
--- /dev/null
+// Copyright 2018 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.
+
+// This note is annotated because the purpose of the test
+// is to ensure that certain other notes are not generated.
+#![deny(unused_unsafe)] //~ NOTE
+
+// (test that no note is generated on this unsafe fn)
+pub unsafe fn a() {
+ fn inner() {
+ unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe`
+ //~^ NOTE
+ }
+
+ inner()
+}
+
+pub fn b() {
+ // (test that no note is generated on this unsafe block)
+ unsafe {
+ fn inner() {
+ unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe`
+ //~^ NOTE
+ }
+
+ let () = ::std::mem::uninitialized();
+
+ inner()
+ }
+}
+
+fn main() {}
+++ /dev/null
-// Copyright 2012 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.
-
-// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`.
-// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the
-// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to
-// exercise that logic in the macro parser.
-//
-// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but
-// included for consistency with `+` and `*`.
-//
-// This test focuses on error cases.
-
-#![feature(macro_at_most_once_rep)]
-
-macro_rules! foo {
- ($(a)?) => {}
-}
-
-macro_rules! baz {
- ($(a),?) => {} // comma separator is meaningless for `?`
-}
-
-macro_rules! barplus {
- ($(a)?+) => {}
-}
-
-macro_rules! barstar {
- ($(a)?*) => {}
-}
-
-pub fn main() {
- foo!(a?a?a); //~ ERROR no rules expected the token `?`
- foo!(a?a); //~ ERROR no rules expected the token `?`
- foo!(a?); //~ ERROR no rules expected the token `?`
- baz!(a?a?a); //~ ERROR no rules expected the token `?`
- baz!(a?a); //~ ERROR no rules expected the token `?`
- baz!(a?); //~ ERROR no rules expected the token `?`
- baz!(a,); //~ ERROR unexpected end of macro invocation
- baz!(a?a?a,); //~ ERROR no rules expected the token `?`
- baz!(a?a,); //~ ERROR no rules expected the token `?`
- baz!(a?,); //~ ERROR no rules expected the token `?`
- barplus!(); //~ ERROR unexpected end of macro invocation
- barplus!(a?); //~ ERROR unexpected end of macro invocation
- barstar!(a?); //~ ERROR unexpected end of macro invocation
-}
impl Tr for S where S<Self>: Copy {} // OK
impl Tr for S where Self::A: Copy {} // OK
-impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected
-impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
-impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
-impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
-impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr for Self {} //~ ERROR cyclic dependency detected
+impl Tr for S<Self> {} //~ ERROR cyclic dependency detected
+impl Self {} //~ ERROR cyclic dependency detected
+impl S<Self> {} //~ ERROR cyclic dependency detected
+impl Tr<Self::A> for S {} //~ ERROR cyclic dependency detected
fn main() {}
#![feature(termination_trait)]
fn main() -> char {
-//~^ ERROR: the trait bound `char: std::Termination` is not satisfied
+//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied
' '
}
struct ReturnType {}
-fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied
+fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied
ReturnType {}
}
--- /dev/null
+// 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(termination_trait)]
+
+// error-pattern:oh, dear
+
+fn main() -> ! {
+ panic!("oh, dear");
+}
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
$(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
+endif
+ifeq ($(filter systemz,$(LLVM_COMPONENTS)),systemz)
$(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
endif
--- /dev/null
+// Copyright 2018 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.
+
+// revisions: lxl nll
+
+#![cfg_attr(nll, feature(nll))]
+
+use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
+use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
+
+struct A(i32);
+
+macro_rules! trivial_binop {
+ ($Trait:ident, $m:ident) => {
+ impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
+ }
+}
+
+trivial_binop!(AddAssign, add_assign);
+trivial_binop!(SubAssign, sub_assign);
+trivial_binop!(MulAssign, mul_assign);
+trivial_binop!(DivAssign, div_assign);
+trivial_binop!(RemAssign, rem_assign);
+trivial_binop!(BitAndAssign, bitand_assign);
+trivial_binop!(BitOrAssign, bitor_assign);
+trivial_binop!(BitXorAssign, bitxor_assign);
+trivial_binop!(ShlAssign, shl_assign);
+trivial_binop!(ShrAssign, shr_assign);
+
+fn main() {
+ let mut a = A(10);
+ a += a.0;
+ a -= a.0;
+ a *= a.0;
+ a /= a.0;
+ a &= a.0;
+ a |= a.0;
+ a ^= a.0;
+ a <<= a.0;
+ a >>= a.0;
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-pretty `dyn ::foo` parses differently in the current epoch
+
#![feature(dyn_trait)]
use std::fmt::Display;
fn main() {
let x: &(dyn 'static + Display) = &BYTE;
let y: Box<dyn Display + 'static> = Box::new(BYTE);
+ let _: &dyn (Display) = &BYTE;
+ let _: &dyn (::std::fmt::Display) = &BYTE;
let xstr = format!("{}", x);
let ystr = format!("{}", y);
assert_eq!(xstr, "33");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait, nested_impl_trait)]
+#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait)]
#![allow(warnings)]
use std::fmt::Debug;
fn pass_through_elision_with_fn_path<T: Fn(&u32) -> &u32>(
x: &T
-) -> impl Into<&impl Fn(&u32) -> &u32> { x }
+) -> &impl Fn(&u32) -> &u32 { x }
-fn foo(x: &impl Debug) -> impl Into<&impl Debug> { x }
-fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> impl Into<&'a impl Debug> { x }
-fn foo_no_outer_impl(x: &impl Debug) -> &impl Debug { x }
-fn foo_explicit_arg<T: Debug>(x: &T) -> impl Into<&impl Debug> { x }
+fn foo(x: &impl Debug) -> &impl Debug { x }
+fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x }
+fn foo_explicit_arg<T: Debug>(x: &T) -> &impl Debug { x }
fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
--- /dev/null
+// 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.
+
+// compile-flags: --test
+
+#![feature(termination_trait)]
+#![feature(test)]
+
+extern crate test;
+use std::num::ParseIntError;
+use test::Bencher;
+
+#[test]
+fn is_a_num() -> Result<(), ParseIntError> {
+ let _: u32 = "22".parse()?;
+ Ok(())
+}
+
+#[test]
+#[should_panic]
+fn not_a_num() -> Result<(), ParseIntError> {
+ let _: u32 = "abc".parse()?;
+ Ok(())
+}
+
+#[bench]
+fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
+ Ok(())
+}
+
+#[bench]
+#[should_panic]
+fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
+ let _: u32 = "abc".parse()?;
+ Ok(())
+}
--- /dev/null
+// 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(match_default_bindings)]
+
+// Test that we "reset" the mode as we pass through a `&` pattern.
+//
+// cc #46688
+
+fn surprise(x: i32) {
+ assert_eq!(x, 2);
+}
+
+fn main() {
+ let x = &(1, &2);
+ let (_, &b) = x;
+ surprise(b);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub struct S;
#[derive(Debug)]
pub struct Z;
+
+pub trait Tr<'a> {}
use extern::xcrate::Z;
+type A = extern::xcrate::S;
+type B = for<'a> extern::xcrate::Tr<'a>;
+
fn f() {
use extern::xcrate;
use extern::xcrate as ycrate;
assert_eq!(format!("{:?}", s), "S");
let z = Z;
assert_eq!(format!("{:?}", z), "Z");
+ assert_eq!(A {}, extern::xcrate::S {});
}
--- /dev/null
+// 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.
+
+// Check that `#[test]` works with extern-absolute-paths enabled.
+//
+// Regression test for #47075.
+
+// compile-flags: --test
+
+#![feature(extern_absolute_paths)]
+
+#[test]
+fn test() {
+}
--- /dev/null
+// 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(if_while_or_patterns)]
+
+enum E {
+ V(u8),
+ U(u8),
+ W,
+}
+use E::*;
+
+fn main() {
+ let mut e = V(10);
+
+ if let V(x) | U(x) = e {
+ assert_eq!(x, 10);
+ }
+ while let V(x) | U(x) = e {
+ assert_eq!(x, 10);
+ e = W;
+ }
+}
+++ /dev/null
-// Copyright 2018 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(termination_trait)]
-
-use std::io::Error;
-
-fn main() -> Result<(), Box<Error>> {
- Ok(())
-}
--- /dev/null
+// Copyright 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.
+
+/// Woah, this trait links to [OtherTrait](OtherTrait)!
+pub trait SomeTrait {}
+
+/// Woah, this trait links to [SomeTrait](SomeTrait)!
+pub trait OtherTrait {}
--- /dev/null
+// Copyright 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.
+
+// aux-build:issue-48414.rs
+
+// ICE when resolving paths for a trait that linked to another trait, when both were in an external
+// crate
+
+#![crate_name = "base"]
+
+extern crate issue_48414;
+
+#[doc(inline)]
+pub use issue_48414::{SomeTrait, OtherTrait};
}
trait C: B { }
- //~^ ERROR unsupported cyclic reference
+ //~^ ERROR cyclic dependency detected
//~| cyclic reference
fn main() { }
-error[E0391]: unsupported cyclic reference between types/traits detected
+error[E0391]: cyclic dependency detected
--> $DIR/cycle-trait-supertrait-indirect.rs:20:1
|
20 | trait C: B { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
-#![feature(conservative_impl_trait, nested_impl_trait)]
+#![feature(conservative_impl_trait)]
trait Id<T> {}
trait Lt<'a> {}
impl<T> Id<T> for T {}
fn free_fn_capture_hrtb_in_impl_trait()
- -> impl for<'a> Id<impl Lt<'a>>
+ -> Box<for<'a> Id<impl Lt<'a>>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657]
{
()
struct Foo;
impl Foo {
fn impl_fn_capture_hrtb_in_impl_trait()
- -> impl for<'a> Id<impl Lt<'a>>
+ -> Box<for<'a> Id<impl Lt<'a>>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level
{
()
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
- --> $DIR/E0657.rs:20:32
+ --> $DIR/E0657.rs:20:31
|
-20 | -> impl for<'a> Id<impl Lt<'a>>
- | ^^
+20 | -> Box<for<'a> Id<impl Lt<'a>>>
+ | ^^
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
- --> $DIR/E0657.rs:29:36
+ --> $DIR/E0657.rs:29:35
|
-29 | -> impl for<'a> Id<impl Lt<'a>>
- | ^^
+29 | -> Box<for<'a> Id<impl Lt<'a>>>
+ | ^^
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 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.
+
+fn main() {
+ if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+ ;
+ }
+ while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+ break;
+ }
+}
--- /dev/null
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+ --> $DIR/feature-gate-if_while_or_patterns.rs:12:5
+ |
+12 | / if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+13 | | ;
+14 | | }
+ | |_____^
+ |
+ = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+ --> $DIR/feature-gate-if_while_or_patterns.rs:15:5
+ |
+15 | / while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+16 | | break;
+17 | | }
+ | |_____^
+ |
+ = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
// independently resolved and only require the concrete
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
- //~^ ERROR unsupported cyclic reference between types/traits detected
+ //~^ ERROR cyclic dependency detected
//~| cyclic reference
send(cycle2().clone());
24 | fn send<T: Send>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0391]: unsupported cyclic reference between types/traits detected
+error[E0391]: cyclic dependency detected
--> $DIR/auto-trait-leak.rs:44:1
|
44 | fn cycle1() -> impl Clone {
--- /dev/null
+// Copyright 2018 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(dyn_trait, conservative_impl_trait, universal_impl_trait)]
+
+use std::fmt::Debug;
+use std::option;
+
+fn parametrized_type_is_allowed() -> Option<impl Debug> {
+ Some(5i32)
+}
+
+fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
+ Some(5i32)
+}
+
+fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
+//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^^ ERROR ambiguous associated type
+ x.next().unwrap()
+}
+
+fn projection_with_named_trait_is_disallowed(x: impl Iterator)
+ -> <impl Iterator as Iterator>::Item
+//~^ ERROR `impl Trait` is not allowed in path parameters
+{
+ x.next().unwrap()
+}
+
+fn projection_with_named_trait_inside_path_is_disallowed()
+ -> <::std::ops::Range<impl Debug> as Iterator>::Item
+//~^ ERROR `impl Trait` is not allowed in path parameters
+{
+ (1i32..100).next().unwrap()
+}
+
+fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
+ -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
+//~^ ERROR `impl Trait` is not allowed in path parameters
+{
+ panic!()
+}
+
+fn main() {}
--- /dev/null
+error[E0667]: `impl Trait` is not allowed in path parameters
+ --> $DIR/impl_trait_projections.rs:23:51
+ |
+23 | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
+ | ^^^^^^^^^^^^^
+
+error[E0667]: `impl Trait` is not allowed in path parameters
+ --> $DIR/impl_trait_projections.rs:30:9
+ |
+30 | -> <impl Iterator as Iterator>::Item
+ | ^^^^^^^^^^^^^
+
+error[E0667]: `impl Trait` is not allowed in path parameters
+ --> $DIR/impl_trait_projections.rs:37:27
+ |
+37 | -> <::std::ops::Range<impl Debug> as Iterator>::Item
+ | ^^^^^^^^^^
+
+error[E0667]: `impl Trait` is not allowed in path parameters
+ --> $DIR/impl_trait_projections.rs:44:29
+ |
+44 | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
+ | ^^^^^^^^^^
+
+error[E0223]: ambiguous associated type
+ --> $DIR/impl_trait_projections.rs:23:50
+ |
+23 | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
+ | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
+ |
+ = note: specify the type using the syntax `<impl std::iter::Iterator as Trait>::Item`
+
+error: aborting due to 5 previous errors
+
}
trait t2 : t1 {
-//~^ ERROR unsupported cyclic reference between types/traits detected
+//~^ ERROR cyclic dependency detected
//~| cyclic reference
}
-error[E0391]: unsupported cyclic reference between types/traits detected
+error[E0391]: cyclic dependency detected
--> $DIR/issue-12511.rs:14:1
|
14 | trait t2 : t1 {
--- /dev/null
+// Copyright 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.
+
+// Check that an enum with recursion in the discriminant throws
+// the appropriate error (rather than, say, blowing the stack).
+enum X {
+ A = X::A as isize, //~ ERROR E0391
+}
+
+fn main() { }
--- /dev/null
+error[E0391]: cyclic dependency detected
+ --> $DIR/issue-23302-1.rs:14:9
+ |
+14 | A = X::A as isize, //~ ERROR E0391
+ | ^^^^^^^^^^^^^ cyclic reference
+ |
+note: the cycle begins when const-evaluating `X::A::{{initializer}}`...
+ --> $DIR/issue-23302-1.rs:14:5
+ |
+14 | A = X::A as isize, //~ ERROR E0391
+ | ^^^^^^^^^^^^^^^^^
+ = note: ...which then again requires const-evaluating `X::A::{{initializer}}`, completing the cycle.
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 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.
+
+// Since `Y::B` here defaults to `Y::A+1`, this is also a
+// recursive definition.
+enum Y {
+ A = Y::B as isize, //~ ERROR E0391
+ B,
+}
+
+fn main() { }
--- /dev/null
+error[E0391]: cyclic dependency detected
+ --> $DIR/issue-23302-2.rs:14:9
+ |
+14 | A = Y::B as isize, //~ ERROR E0391
+ | ^^^^^^^^^^^^^ cyclic reference
+ |
+note: the cycle begins when const-evaluating `Y::A::{{initializer}}`...
+ --> $DIR/issue-23302-2.rs:14:5
+ |
+14 | A = Y::B as isize, //~ ERROR E0391
+ | ^^^^^^^^^^^^^^^^^
+ = note: ...which then again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle.
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 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.
+
+const A: i32 = B; //~ ERROR E0391
+
+const B: i32 = A;
+
+fn main() { }
--- /dev/null
+error[E0391]: cyclic dependency detected
+ --> $DIR/issue-23302-3.rs:11:16
+ |
+11 | const A: i32 = B; //~ ERROR E0391
+ | ^ cyclic reference
+ |
+note: the cycle begins when processing `B`...
+ --> $DIR/issue-23302-3.rs:13:1
+ |
+13 | const B: i32 = A;
+ | ^^^^^^^^^^^^^^^^^
+note: ...which then requires processing `A`...
+ --> $DIR/issue-23302-3.rs:13:16
+ |
+13 | const B: i32 = A;
+ | ^
+ = note: ...which then again requires processing `B`, completing the cycle.
+
+error: aborting due to previous error
+
+++ /dev/null
-// Copyright 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.
-
-// Check that an enum with recursion in the discriminant throws
-// the appropriate error (rather than, say, blowing the stack).
-enum X {
- A = X::A as isize, //~ ERROR E0265
-}
-
-// Since `Y::B` here defaults to `Y::A+1`, this is also a
-// recursive definition.
-enum Y {
- A = Y::B as isize, //~ ERROR E0265
- B,
-}
-
-const A: i32 = B; //~ ERROR E0265
-
-const B: i32 = A; //~ ERROR E0265
-
-fn main() { }
+++ /dev/null
-error[E0265]: recursive constant
- --> $DIR/issue-23302.rs:14:9
- |
-14 | A = X::A as isize, //~ ERROR E0265
- | ^^^^^^^^^^^^^ recursion not allowed in constant
-
-error[E0265]: recursive constant
- --> $DIR/issue-23302.rs:20:9
- |
-20 | A = Y::B as isize, //~ ERROR E0265
- | ^^^^^^^^^^^^^ recursion not allowed in constant
-
-error[E0265]: recursive constant
- --> $DIR/issue-23302.rs:24:1
- |
-24 | const A: i32 = B; //~ ERROR E0265
- | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant
-
-error[E0265]: recursive constant
- --> $DIR/issue-23302.rs:26:1
- |
-26 | const B: i32 = A; //~ ERROR E0265
- | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant
-
-error: aborting due to 4 previous errors
-
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const A: i32 = Foo::B; //~ ERROR E0265
+const A: isize = Foo::B as isize;
enum Foo {
- B = A, //~ ERROR E0265
+ B = A, //~ ERROR E0391
}
-enum Bar {
- C = Bar::C, //~ ERROR E0265
-}
-
-const D: i32 = A;
-
fn main() {}
-error[E0265]: recursive constant
- --> $DIR/issue-36163.rs:11:1
- |
-11 | const A: i32 = Foo::B; //~ ERROR E0265
- | ^^^^^^^^^^^^^^^^^^^^^^ recursion not allowed in constant
-
-error[E0265]: recursive constant
+error[E0391]: cyclic dependency detected
--> $DIR/issue-36163.rs:14:9
|
-14 | B = A, //~ ERROR E0265
- | ^ recursion not allowed in constant
-
-error[E0265]: recursive constant
- --> $DIR/issue-36163.rs:18:9
+14 | B = A, //~ ERROR E0391
+ | ^ cyclic reference
+ |
+note: the cycle begins when const-evaluating `Foo::B::{{initializer}}`...
+ --> $DIR/issue-36163.rs:14:5
+ |
+14 | B = A, //~ ERROR E0391
+ | ^^^^^
+note: ...which then requires const-evaluating `A`...
+ --> $DIR/issue-36163.rs:14:9
|
-18 | C = Bar::C, //~ ERROR E0265
- | ^^^^^^ recursion not allowed in constant
+14 | B = A, //~ ERROR E0391
+ | ^
+ = note: ...which then again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle.
-error: aborting due to 3 previous errors
+error: aborting due to previous error
--- /dev/null
+// 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(unused)]
+#![feature(nll)]
+
+#[derive(Clone, Copy, Default)]
+struct S {
+ a: u8,
+ b: u8,
+}
+#[derive(Clone, Copy, Default)]
+struct Z {
+ c: u8,
+ d: u8,
+}
+
+union U {
+ s: S,
+ z: Z,
+}
+
+fn main() {
+ unsafe {
+ let mut u = U { s: Default::default() };
+
+ let mref = &mut u.s.a;
+ *mref = 22;
+
+ let nref = &u.z.c;
+ //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
+ println!("{} {}", mref, nref)
+ //~^ ERROR cannot borrow `u.s.a` as mutable because it is also borrowed as immutable [E0502]
+ }
+}
+
--- /dev/null
+error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable
+ --> $DIR/issue-45157.rs:37:20
+ |
+34 | let mref = &mut u.s.a;
+ | ---------- mutable borrow occurs here
+...
+37 | let nref = &u.z.c;
+ | ^^^^^^ immutable borrow occurs here
+
+error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable
+ --> $DIR/issue-45157.rs:39:27
+ |
+37 | let nref = &u.z.c;
+ | ------ immutable borrow occurs here
+38 | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
+39 | println!("{} {}", mref, nref)
+ | ^^^^ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
}
//~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593]
}
+
+enum Qux {
+ Bar(i32),
+}
+
+fn foo<F>(f: F)
+where
+ F: Fn(),
+{
+}
+
+fn main() {
+ foo(Qux::Bar);
+}
+//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593]
-error[E0601]: main function not found
-
error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
--> $DIR/issue-47706.rs:21:18
|
21 | self.foo.map(Foo::new)
| ^^^ expected function that takes 1 argument
+error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
+ --> $DIR/issue-47706.rs:37:5
+ |
+27 | Bar(i32),
+ | -------- takes 1 argument
+...
+37 | foo(Qux::Bar);
+ | ^^^ expected function that takes 0 arguments
+ |
+note: required by `foo`
+ --> $DIR/issue-47706.rs:30:1
+ |
+30 | / fn foo<F>(f: F)
+31 | | where
+32 | | F: Fn(),
+33 | | {
+34 | | }
+ | |_^
+
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2014–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.
+
+#![deny(nonstandard_style)]
+#![allow(dead_code)]
+
+fn CamelCase() {} //~ ERROR should have a snake
+
+#[allow(nonstandard_style)]
+mod test {
+ fn CamelCase() {}
+
+ #[forbid(nonstandard_style)]
+ mod bad {
+ fn CamelCase() {} //~ ERROR should have a snake
+
+ static bad: isize = 1; //~ ERROR should have an upper
+ }
+
+ mod warn {
+ #![warn(nonstandard_style)]
+
+ fn CamelCase() {} //~ WARN should have a snake
+
+ struct snake_case; //~ WARN should have a camel
+ }
+}
+
+fn main() {}
--- /dev/null
+error: function `CamelCase` should have a snake case name such as `camel_case`
+ --> $DIR/lint-group-nonstandard-style.rs:14:1
+ |
+14 | fn CamelCase() {} //~ ERROR should have a snake
+ | ^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint-group-nonstandard-style.rs:11:9
+ |
+11 | #![deny(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)]
+
+error: function `CamelCase` should have a snake case name such as `camel_case`
+ --> $DIR/lint-group-nonstandard-style.rs:22:9
+ |
+22 | fn CamelCase() {} //~ ERROR should have a snake
+ | ^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint-group-nonstandard-style.rs:20:14
+ |
+20 | #[forbid(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)]
+
+error: static variable `bad` should have an upper case name such as `BAD`
+ --> $DIR/lint-group-nonstandard-style.rs:24:9
+ |
+24 | static bad: isize = 1; //~ ERROR should have an upper
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint-group-nonstandard-style.rs:20:14
+ |
+20 | #[forbid(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
+
+warning: function `CamelCase` should have a snake case name such as `camel_case`
+ --> $DIR/lint-group-nonstandard-style.rs:30:9
+ |
+30 | fn CamelCase() {} //~ WARN should have a snake
+ | ^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint-group-nonstandard-style.rs:28:17
+ |
+28 | #![warn(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)]
+
+warning: type `snake_case` should have a camel case name such as `SnakeCase`
+ --> $DIR/lint-group-nonstandard-style.rs:32:9
+ |
+32 | struct snake_case; //~ WARN should have a camel
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint-group-nonstandard-style.rs:28:17
+ |
+28 | #![warn(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)]
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// Copyright 2012 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.
+
+// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`.
+// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the
+// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to
+// exercise that logic in the macro parser.
+//
+// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but
+// included for consistency with `+` and `*`.
+//
+// This test focuses on error cases.
+
+#![feature(macro_at_most_once_rep)]
+
+macro_rules! foo {
+ ($(a)?) => {}
+}
+
+macro_rules! baz {
+ ($(a),?) => {} // comma separator is meaningless for `?`
+}
+
+macro_rules! barplus {
+ ($(a)?+) => {}
+}
+
+macro_rules! barstar {
+ ($(a)?*) => {}
+}
+
+pub fn main() {
+ foo!(a?a?a); //~ ERROR no rules expected the token `?`
+ foo!(a?a); //~ ERROR no rules expected the token `?`
+ foo!(a?); //~ ERROR no rules expected the token `?`
+ baz!(a?a?a); //~ ERROR no rules expected the token `?`
+ baz!(a?a); //~ ERROR no rules expected the token `?`
+ baz!(a?); //~ ERROR no rules expected the token `?`
+ baz!(a,); //~ ERROR unexpected end of macro invocation
+ baz!(a?a?a,); //~ ERROR no rules expected the token `?`
+ baz!(a?a,); //~ ERROR no rules expected the token `?`
+ baz!(a?,); //~ ERROR no rules expected the token `?`
+ barplus!(); //~ ERROR unexpected end of macro invocation
+ barplus!(a?); //~ ERROR unexpected end of macro invocation
+ barstar!(a?); //~ ERROR unexpected end of macro invocation
+}
--- /dev/null
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:40:11
+ |
+40 | foo!(a?a?a); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:41:11
+ |
+41 | foo!(a?a); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:42:11
+ |
+42 | foo!(a?); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:43:11
+ |
+43 | baz!(a?a?a); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:44:11
+ |
+44 | baz!(a?a); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:45:11
+ |
+45 | baz!(a?); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:46:11
+ |
+46 | baz!(a,); //~ ERROR unexpected end of macro invocation
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:47:11
+ |
+47 | baz!(a?a?a,); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:48:11
+ |
+48 | baz!(a?a,); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:49:11
+ |
+49 | baz!(a?,); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:50:5
+ |
+50 | barplus!(); //~ ERROR unexpected end of macro invocation
+ | ^^^^^^^^^^^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:51:15
+ |
+51 | barplus!(a?); //~ ERROR unexpected end of macro invocation
+ | ^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:52:15
+ |
+52 | barstar!(a?); //~ ERROR unexpected end of macro invocation
+ | ^
+
+error: aborting due to 13 previous errors
+
--- /dev/null
+// 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(conservative_impl_trait, universal_impl_trait)]
+
+use std::fmt::Debug;
+
+fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
+
+fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+//~^ ERROR nested `impl Trait` is not allowed
+
+fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
+//~^ ERROR nested `impl Trait` is not allowed
+//~^^ `impl Trait` not allowed
+
+fn bad_in_arg_position(_: impl Into<impl Debug>) { }
+//~^ ERROR nested `impl Trait` is not allowed
+
+struct X;
+impl X {
+ fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+ //~^ ERROR nested `impl Trait` is not allowed
+}
+
+fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
+ vec![|| println!("woot")].into_iter()
+}
+
+fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
+//~^ `impl Trait` not allowed
+ || 5
+}
+
+fn main() {}
--- /dev/null
+error[E0666]: nested `impl Trait` is not allowed
+ --> $DIR/nested_impl_trait.rs:16:56
+ |
+16 | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+ | ----------^^^^^^^^^^-
+ | | |
+ | | nested `impl Trait` here
+ | outer `impl Trait`
+
+error[E0666]: nested `impl Trait` is not allowed
+ --> $DIR/nested_impl_trait.rs:19:42
+ |
+19 | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
+ | ----------^^^^^^^^^^-
+ | | |
+ | | nested `impl Trait` here
+ | outer `impl Trait`
+
+error[E0666]: nested `impl Trait` is not allowed
+ --> $DIR/nested_impl_trait.rs:23:37
+ |
+23 | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
+ | ----------^^^^^^^^^^-
+ | | |
+ | | nested `impl Trait` here
+ | outer `impl Trait`
+
+error[E0666]: nested `impl Trait` is not allowed
+ --> $DIR/nested_impl_trait.rs:28:44
+ |
+28 | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+ | ----------^^^^^^^^^^-
+ | | |
+ | | nested `impl Trait` here
+ | outer `impl Trait`
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+ --> $DIR/nested_impl_trait.rs:19:32
+ |
+19 | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+ --> $DIR/nested_impl_trait.rs:36:42
+ |
+36 | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
= note: number of external vids: 3
= note: where <T as std::iter::Iterator>::Item: '_#2r
-note: External requirements
- --> $DIR/projection-no-regions-closure.rs:46:23
- |
-46 | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
- ]
- = note: number of external vids: 3
- = note: where <T as std::iter::Iterator>::Item: '_#2r
-
-note: External requirements
- --> $DIR/projection-no-regions-closure.rs:54:23
- |
-54 | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
- ]
- = note: number of external vids: 4
- = note: where <T as std::iter::Iterator>::Item: '_#3r
-
-note: External requirements
- --> $DIR/projection-no-regions-closure.rs:65:23
- |
-65 | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
- ]
- = note: number of external vids: 4
- = note: where <T as std::iter::Iterator>::Item: '_#3r
-
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-closure.rs:36:23
|
T
]
+note: External requirements
+ --> $DIR/projection-no-regions-closure.rs:46:23
+ |
+46 | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
+ ]
+ = note: number of external vids: 3
+ = note: where <T as std::iter::Iterator>::Item: '_#2r
+
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:42:1
|
T
]
+note: External requirements
+ --> $DIR/projection-no-regions-closure.rs:54:23
+ |
+54 | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-closure.rs:54:23
|
T
]
+note: External requirements
+ --> $DIR/projection-no-regions-closure.rs:65:23
+ |
+65 | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:60:1
|
= note: where T: '_#2r
= note: where '_#1r: '_#2r
-note: External requirements
- --> $DIR/projection-one-region-closure.rs:68:29
- |
-68 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where T: '_#3r
- = note: where '_#2r: '_#3r
-
-note: External requirements
- --> $DIR/projection-one-region-closure.rs:90:29
- |
-90 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where T: '_#3r
- = note: where '_#2r: '_#3r
-
-note: External requirements
- --> $DIR/projection-one-region-closure.rs:103:29
- |
-103 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where T: '_#3r
- = note: where '_#2r: '_#3r
-
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:56:29
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-closure.rs:68:29
+ |
+68 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+ = note: where '_#2r: '_#3r
+
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:68:29
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-closure.rs:90:29
+ |
+90 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+ = note: where '_#2r: '_#3r
+
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:90:29
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-closure.rs:103:29
+ |
+103 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+ = note: where '_#2r: '_#3r
+
note: No external requirements
--> $DIR/projection-one-region-closure.rs:97:1
|
= note: number of external vids: 3
= note: where '_#1r: '_#2r
-note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:59:29
- |
-59 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where '_#2r: '_#3r
-
-note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:80:29
- |
-80 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where '_#2r: '_#3r
-
-note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:91:29
- |
-91 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where '_#2r: '_#3r
-
-note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:103:29
- |
-103 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
- = note: number of external vids: 3
- = note: where '_#1r: '_#2r
-
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
--> $DIR/projection-one-region-trait-bound-closure.rs:48:20
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:59:29
+ |
+59 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-trait-bound-closure.rs:59:20
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:80:29
+ |
+80 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
--> $DIR/projection-one-region-trait-bound-closure.rs:80:20
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:91:29
+ |
+91 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:86:1
|
T
]
+note: External requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:103:29
+ |
+103 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+ = note: number of external vids: 3
+ = note: where '_#1r: '_#2r
+
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:95:1
|
]
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29
- |
-56 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
-
-note: No external requirements
- --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1
|
-75 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+44 | | where
+45 | | T: Anything<'b>,
+46 | | {
+47 | | with_signature(cell, t, |cell, t| require(cell, t));
+48 | | }
+ | |_^
|
- = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
'_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ T
]
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29
|
-84 | with_signature(cell, t, |cell, t| require(cell, t));
+56 | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
'_#1r,
'_#2r,
T,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
]
-note: No external requirements
- --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29
- |
-96 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
-
-note: No external requirements
- --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1
- |
-43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
-44 | | where
-45 | | T: Anything<'b>,
-46 | | {
-47 | | with_signature(cell, t, |cell, t| require(cell, t));
-48 | | }
- | |_^
- |
- = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
- '_#1r,
- T
- ]
-
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1
|
T
]
+note: No external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29
+ |
+75 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1
|
T
]
+note: No external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29
+ |
+84 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1
|
T
]
+note: No external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29
+ |
+96 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1
|
= note: number of external vids: 4
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:60:29
- |
-60 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
- ]
- = note: number of external vids: 5
- = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:81:29
- |
-81 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
- ]
- = note: number of external vids: 5
- = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:92:29
- |
-92 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
- ]
- = note: number of external vids: 5
- = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:101:29
- |
-101 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
- ]
- = note: number of external vids: 5
- = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
- |
-109 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
- = note: number of external vids: 3
- = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:120:29
- |
-120 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
-
-note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:132:29
- |
-132 | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
- = note: number of external vids: 3
- = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
-
error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:49:29
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:60:29
+ |
+60 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ '_#3r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:60:29
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:81:29
+ |
+81 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ '_#3r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:81:29
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:92:29
+ |
+92 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ '_#3r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:87:1
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:101:29
+ |
+101 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ '_#3r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:96:1
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
+ |
+109 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+ = note: number of external vids: 3
+ = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
--> $DIR/projection-two-region-trait-bound-closure.rs:109:20
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:120:29
+ |
+120 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
+
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:115:1
|
T
]
+note: External requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:132:29
+ |
+132 | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+ = note: number of external vids: 3
+ = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:124:1
|
= note: number of external vids: 2
= note: where T: '_#1r
-note: External requirements
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
- |
-43 | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^^^^^^^^
- |
- = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
- T,
- i16,
- for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
- ]
- = note: number of external vids: 2
- = note: where T: '_#1r
-
note: No external requirements
--> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1
|
T
]
+note: External requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
+ |
+43 | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
+ T,
+ i16,
+ for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
+ ]
+ = note: number of external vids: 2
+ = note: where T: '_#1r
+
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
|
= note: number of external vids: 2
= note: where T: '_#1r
-note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26
- |
-55 | with_signature(a, b, |x, y| {
- | __________________________^
-56 | | // Key point of this test:
-57 | | //
-58 | | // The *closure* is being type-checked with all of its free
-... |
-67 | | require(&x, &y)
-68 | | })
- | |_____^
- |
- = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
- = note: number of external vids: 3
- = note: where T: '_#2r
-
-note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
- |
-76 | with_signature(a, b, |x, y| {
- | __________________________^
-77 | | //~^ ERROR the parameter type `T` may not live long enough
-78 | | // See `correct_region`
-79 | | require(&x, &y)
-80 | | //~^ WARNING not reporting region error due to -Znll
-81 | | })
- | |_____^
- |
- = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
- ]
- = note: number of external vids: 3
- = note: where T: '_#2r
-
-note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26
- |
-90 | with_signature(a, b, |x, y| {
- | __________________________^
-91 | | // See `correct_region`
-92 | | require(&x, &y)
-93 | | })
- | |_____^
- |
- = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
- i32,
- extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
- ]
- = note: number of external vids: 4
- = note: where T: '_#3r
-
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26
|
T
]
+note: External requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26
+ |
+55 | with_signature(a, b, |x, y| {
+ | __________________________^
+56 | | // Key point of this test:
+57 | | //
+58 | | // The *closure* is being type-checked with all of its free
+... |
+67 | | require(&x, &y)
+68 | | })
+ | |_____^
+ |
+ = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1
|
T
]
+note: External requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
+ |
+76 | with_signature(a, b, |x, y| {
+ | __________________________^
+77 | | //~^ ERROR the parameter type `T` may not live long enough
+78 | | // See `correct_region`
+79 | | require(&x, &y)
+80 | | //~^ WARNING not reporting region error due to -Znll
+81 | | })
+ | |_____^
+ |
+ = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
T
]
+note: External requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26
+ |
+90 | with_signature(a, b, |x, y| {
+ | __________________________^
+91 | | // See `correct_region`
+92 | | require(&x, &y)
+93 | | })
+ | |_____^
+ |
+ = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
+ '_#1r,
+ '_#2r,
+ T,
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1
|
}
impl ToNbt<Self> {}
-//~^ ERROR unsupported cyclic reference
+//~^ ERROR cyclic dependency detected
fn main() {}
-error[E0391]: unsupported cyclic reference between types/traits detected
+error[E0391]: cyclic dependency detected
--> $DIR/issue-23305.rs:15:12
|
15 | impl ToNbt<Self> {}
// that won't output for the above string concatenation
let y = World::Hello + World::Goodbye;
//~^ ERROR cannot be applied to type
+
+ let x = "Hello " + "World!".to_owned();
+ //~^ ERROR cannot be applied to type
}
enum World {
|
= note: an implementation of `std::ops::Add` might be missing for `World`
-error: aborting due to 2 previous errors
+error[E0369]: binary operation `+` cannot be applied to type `&str`
+ --> $DIR/issue-39018.rs:21:13
+ |
+21 | let x = "Hello " + "World!".to_owned();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String`
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+ |
+21 | let x = "Hello ".to_owned() + "World!".to_owned();
+ | ^^^^^^^^^^^^^^^^^^^
+help: you also need to borrow the `String` on the right to get a `&str`
+ |
+21 | let x = "Hello " + &"World!".to_owned();
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
--- /dev/null
+// Copyright 2018 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.
+
+fn main() {
+ unsafe //{
+ std::mem::transmute::<f32, u32>(1.0);
+ //}
+}
+//~^^^ ERROR expected one of `extern`, `fn`, or `{`, found `std`
--- /dev/null
+error: expected one of `extern`, `fn`, or `{`, found `std`
+ --> $DIR/unsafe-block-without-braces.rs:13:9
+ |
+12 | unsafe //{
+ | - expected one of `extern`, `fn`, or `{` here
+13 | std::mem::transmute::<f32, u32>(1.0);
+ | ^^^ unexpected token
+
+error: aborting due to previous error
+
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
+ "sparc-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"sparcv9-sun-solaris",
"wasm32-unknown-emscripten",