.project
.settings/
.valgrindrc
+.vscode/
/*-*-*-*/
/*-*-*/
/Makefile
LLVM_VERSION=$($LLVM_CONFIG --version)
case $LLVM_VERSION in
- (3.[7-8]*)
+ (3.[7-9]*)
msg "found ok version of LLVM: $LLVM_VERSION"
;;
(*)
.TP
\fBRUST_TEST_THREADS\fR
The test framework Rust provides executes tests in parallel. This variable sets
-the maximum number of threads used for this purpose.
+the maximum number of threads used for this purpose. This setting is overridden
+by the --test-threads option.
.TP
\fBRUST_TEST_NOCAPTURE\fR
CFG_STATIC_LIB_NAME_i586-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_i586-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_i586-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_i586-unknown-linux-gnu := -m32 $(CFLAGS) -march=pentium
-CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=pentium
+CFG_JEMALLOC_CFLAGS_i586-unknown-linux-gnu := -m32 $(CFLAGS) -march=pentium -Wa,-mrelax-relocations=no
+CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=pentium -Wa,-mrelax-relocations=no
CFG_GCCISH_CXXFLAGS_i586-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) -march=pentium
CFG_GCCISH_LINK_FLAGS_i586-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32
CFG_GCCISH_DEF_FLAG_i586-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LIB_NAME_i686-unknown-linux-musl=lib$(1).so
CFG_STATIC_LIB_NAME_i686-unknown-linux-musl=lib$(1).a
CFG_LIB_GLOB_i686-unknown-linux-musl=lib$(1)-*.so
-CFG_JEMALLOC_CFLAGS_i686-unknown-linux-musl := -m32 -Wl,-melf_i386
-CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -g -fPIC -m32 -Wl,-melf_i386
+CFG_JEMALLOC_CFLAGS_i686-unknown-linux-musl := -m32 -Wl,-melf_i386 -Wa,-mrelax-relocations=no
+CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -g -fPIC -m32 -Wl,-melf_i386 -Wa,-mrelax-relocations=no
CFG_GCCISH_CXXFLAGS_i686-unknown-linux-musl :=
CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-musl :=
CFG_GCCISH_DEF_FLAG_i686-unknown-linux-musl :=
$$(call CFG_CC_INCLUDE_$(1),$$(S)src/rustllvm/include)
RUSTLLVM_OBJS_OBJS_$(1) := $$(RUSTLLVM_OBJS_CS_$(1):rustllvm/%.cpp=$(1)/rustllvm/%.o)
+# Flag that we are building with Rust's llvm fork
+ifeq ($(CFG_LLVM_ROOT),)
+RUSTLLVM_CXXFLAGS_$(1) := -DLLVM_RUSTLLVM
+endif
+
# Note that we appease `cl.exe` and its need for some sort of exception
# handling flag with the `EHsc` argument here as well.
ifeq ($$(findstring msvc,$(1)),msvc)
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@,) \
$$(subst /,//,$$(LLVM_CXXFLAGS_$(1))) \
$$(RUSTLLVM_COMPONENTS_$(1)) \
+ $$(RUSTLLVM_CXXFLAGS_$(1)) \
$$(EXTRA_RUSTLLVM_CXXFLAGS_$(1)) \
$$(RUSTLLVM_INCS_$(1)) \
$$<
if !build.unstable_features {
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
}
+ // Flag that rust llvm is in use
+ if build.is_rust_llvm(target) {
+ cargo.env("LLVM_RUSTLLVM", "1");
+ }
cargo.env("LLVM_CONFIG", build.llvm_config(target));
if build.config.llvm_static_stdcpp {
cargo.env("LLVM_STATIC_STDCPP",
self.out.join(target).join("llvm")
}
+ /// Returns true if no custom `llvm-config` is set for the specified target.
+ ///
+ /// If no custom `llvm-config` was specified then Rust's llvm will be used.
+ fn is_rust_llvm(&self, target: &str) -> bool {
+ match self.config.target_config.get(target) {
+ Some(ref c) => c.llvm_config.is_none(),
+ None => true
+ }
+ }
+
/// Returns the path to `llvm-config` for the specified target.
///
/// If a custom `llvm-config` was specified for target then that's returned
// This is a hack, because newer binutils broke things on some vms/distros
// (i.e., linking against unknown relocs disabled by the following flag)
// See: https://github.com/rust-lang/rust/issues/34978
- if target == "x86_64-unknown-linux-musl" {
- base.push("-Wa,-mrelax-relocations=no".into());
+ match target {
+ "i586-unknown-linux-gnu" |
+ "i686-unknown-linux-musl" |
+ "x86_64-unknown-linux-musl" => {
+ base.push("-Wa,-mrelax-relocations=no".into());
+ },
+ _ => {},
}
return base
}
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
- target.contains("msvc") {
+ target.contains("msvc") ||
+ target.contains("emscripten") {
build.config.use_jemalloc = false;
}
#[inline]
#[unstable(feature = "insert_str",
reason = "recent addition",
- issue = "0")]
+ issue = "35553")]
pub fn insert_str(&mut self, idx: usize, string: &str) {
let len = self.len();
assert!(idx <= len);
#[inline]
fn into_iter(mut self) -> IntoIter<T> {
unsafe {
- let ptr = self.as_mut_ptr();
- assume(!ptr.is_null());
- let begin = ptr as *const T;
+ let begin = self.as_mut_ptr();
+ assume(!begin.is_null());
let end = if mem::size_of::<T>() == 0 {
- arith_offset(ptr as *const i8, self.len() as isize) as *const T
+ arith_offset(begin as *const i8, self.len() as isize) as *const T
} else {
- ptr.offset(self.len() as isize) as *const T
+ begin.offset(self.len() as isize) as *const T
};
let buf = ptr::read(&self.buf);
mem::forget(self);
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
_buf: RawVec<T>,
- ptr: *const T,
+ ptr: *mut T,
end: *const T,
}
+impl<T> IntoIter<T> {
+ /// Returns the remaining items of this iterator as a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #![feature(vec_into_iter_as_slice)]
+ /// let vec = vec!['a', 'b', 'c'];
+ /// let mut into_iter = vec.into_iter();
+ /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ /// let _ = into_iter.next().unwrap();
+ /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
+ /// ```
+ #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")]
+ pub fn as_slice(&self) -> &[T] {
+ unsafe {
+ slice::from_raw_parts(self.ptr, self.len())
+ }
+ }
+
+ /// Returns the remaining items of this iterator as a mutable slice.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #![feature(vec_into_iter_as_slice)]
+ /// let vec = vec!['a', 'b', 'c'];
+ /// let mut into_iter = vec.into_iter();
+ /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ /// into_iter.as_mut_slice()[2] = 'z';
+ /// assert_eq!(into_iter.next().unwrap(), 'a');
+ /// assert_eq!(into_iter.next().unwrap(), 'b');
+ /// assert_eq!(into_iter.next().unwrap(), 'z');
+ /// ```
+ #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")]
+ pub fn as_mut_slice(&self) -> &mut [T] {
+ unsafe {
+ slice::from_raw_parts_mut(self.ptr, self.len())
+ }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send> Send for IntoIter<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
fn next(&mut self) -> Option<T> {
unsafe {
- if self.ptr == self.end {
+ if self.ptr as *const _ == self.end {
None
} else {
if mem::size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the
// same pointer.
- self.ptr = arith_offset(self.ptr as *const i8, 1) as *const T;
+ self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T;
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
} else {
if mem::size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used
- self.end = arith_offset(self.end as *const i8, -1) as *const T;
+ self.end = arith_offset(self.end as *const i8, -1) as *mut T;
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
impl<T: Clone> Clone for IntoIter<T> {
fn clone(&self) -> IntoIter<T> {
- unsafe {
- slice::from_raw_parts(self.ptr, self.len()).to_owned().into_iter()
- }
+ self.as_slice().to_owned().into_iter()
}
}
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(vec_deque_contains)]
+#![feature(vec_into_iter_as_slice)]
extern crate collections;
extern crate test;
assert_eq!(vec2, [5, 6]);
}
+#[test]
+fn test_into_iter_as_slice() {
+ let vec = vec!['a', 'b', 'c'];
+ let mut into_iter = vec.into_iter();
+ assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ let _ = into_iter.next().unwrap();
+ assert_eq!(into_iter.as_slice(), &['b', 'c']);
+ let _ = into_iter.next().unwrap();
+ let _ = into_iter.next().unwrap();
+ assert_eq!(into_iter.as_slice(), &[]);
+}
+
+#[test]
+fn test_into_iter_as_mut_slice() {
+ let vec = vec!['a', 'b', 'c'];
+ let mut into_iter = vec.into_iter();
+ assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ into_iter.as_mut_slice()[0] = 'x';
+ into_iter.as_mut_slice()[1] = 'y';
+ assert_eq!(into_iter.next().unwrap(), 'x');
+ assert_eq!(into_iter.as_slice(), &['y', 'c']);
+}
+
#[test]
fn test_into_iter_count() {
assert_eq!(vec![1, 2, 3].into_iter().count(), 3);
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use convert::From;
use default::Default;
use fmt::{self, Debug, Display};
use marker::{Copy, PhantomData, Send, Sync, Sized, Unsize};
}
}
+#[stable(feature = "cell_from", since = "1.12.0")]
+impl<T: Copy> From<T> for Cell<T> {
+ fn from(t: T) -> Cell<T> {
+ Cell::new(t)
+ }
+}
+
/// A mutable memory location with dynamically checked borrow rules
///
/// See the [module-level documentation](index.html) for more.
}
}
+#[stable(feature = "cell_from", since = "1.12.0")]
+impl<T> From<T> for RefCell<T> {
+ fn from(t: T) -> RefCell<T> {
+ RefCell::new(t)
+ }
+}
+
struct BorrowRef<'b> {
borrow: &'b Cell<BorrowFlag>,
}
UnsafeCell::new(Default::default())
}
}
+
+#[stable(feature = "cell_from", since = "1.12.0")]
+impl<T> From<T> for UnsafeCell<T> {
+ fn from(t: T) -> UnsafeCell<T> {
+ UnsafeCell::new(t)
+ }
+}
})
}
-/// Use the `format!` syntax to write data into a buffer.
+/// Write formatted data into a buffer
///
-/// This macro is typically used with a buffer of `&mut `[`Write`][write].
+/// This macro accepts any value with `write_fmt` method as a writer, a format string, and a list
+/// of arguments to format.
+///
+/// `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] or
+/// [`std::io::Write`][io_write] traits. These are sometimes called 'writers'.
+///
+/// Passed arguments will be formatted according to the specified format string and the resulting
+/// string will be passed to the writer.
///
/// See [`std::fmt`][fmt] for more information on format syntax.
///
+/// Return value is completely dependent on the 'write_fmt' method.
+///
+/// Common return values are: [`Result`][enum_result], [`io::Result`][type_result]
+///
/// [fmt]: ../std/fmt/index.html
-/// [write]: ../std/io/trait.Write.html
+/// [fmt_write]: ../std/fmt/trait.Write.html
+/// [io_write]: ../std/io/trait.Write.html
+/// [enum_result]: ../std/result/enum.Result.html
+/// [type_result]: ../std/io/type.Result.html
///
/// # Examples
///
($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
}
-/// Use the `format!` syntax to write data into a buffer, appending a newline.
-/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`)
-/// alone (no additional CARRIAGE RETURN (`\r`/`U+000D`).
+/// Write formatted data into a buffer, with appending a newline.
+///
+/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
+/// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
///
-/// This macro is typically used with a buffer of `&mut `[`Write`][write].
+/// This macro accepts any value with `write_fmt` method as a writer, a format string, and a list
+/// of arguments to format.
+///
+/// `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] or
+/// [`std::io::Write`][io_write] traits. These are sometimes called 'writers'.
+///
+/// Passed arguments will be formatted according to the specified format string and the resulting
+/// string will be passed to the writer.
///
/// See [`std::fmt`][fmt] for more information on format syntax.
///
+/// Return value is completely dependent on the 'write_fmt' method.
+///
+/// Common return values are: [`Result`][enum_result], [`io::Result`][type_result]
+///
/// [fmt]: ../std/fmt/index.html
-/// [write]: ../std/io/trait.Write.html
+/// [fmt_write]: ../std/fmt/trait.Write.html
+/// [io_write]: ../std/io/trait.Write.html
+/// [enum_result]: ../std/result/enum.Result.html
+/// [type_result]: ../std/io/type.Result.html
///
/// # Examples
///
/// ```
/// fn mutate(r: &mut Result<i32, i32>) {
/// match r.as_mut() {
- /// Ok(&mut ref mut v) => *v = 42,
- /// Err(&mut ref mut e) => *e = 0,
+ /// Ok(v) => *v = 42,
+ /// Err(e) => *e = 0,
/// }
/// }
///
//! atomically-reference-counted shared pointer).
//!
//! Most atomic types may be stored in static variables, initialized using
-//! the provided static initializers like `INIT_ATOMIC_BOOL`. Atomic statics
+//! the provided static initializers like `ATOMIC_BOOL_INIT`. Atomic statics
//! are often used for lazy global initialization.
//!
//!
```
"##,
+E0312: r##"
+A lifetime of reference outlives lifetime of borrowed content.
+
+Erroneous code example:
+
+```compile_fail,E0312
+fn make_child<'human, 'elve>(x: &mut &'human isize, y: &mut &'elve isize) {
+ *x = *y;
+ // error: lifetime of reference outlives lifetime of borrowed content
+}
+```
+
+The compiler cannot determine if the `human` lifetime will live long enough
+to keep up on the elve one. To solve this error, you have to give an
+explicit lifetime hierarchy:
+
+```
+fn make_child<'human, 'elve: 'human>(x: &mut &'human isize,
+ y: &mut &'elve isize) {
+ *x = *y; // ok!
+}
+```
+
+Or use the same lifetime for every variable:
+
+```
+fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
+ *x = *y; // ok!
+}
+```
+"##,
+
E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to change, as
described in RFC #1156 [1]. You are getting a warning because the compiler
// E0304, // expected signed integer constant
// E0305, // expected constant
E0311, // thing may not live long enough
- E0312, // lifetime of reference outlives lifetime of borrowed content
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
TyPolyTraitRef(bounds) => {
TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
}
+ TyImplTrait(bounds) => {
+ TyImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+ }
},
span: fld.new_span(span),
}
TyPolyTraitRef(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
+ TyImplTrait(ref bounds) => {
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ }
TyTypeof(ref expression) => {
visitor.visit_expr(expression)
}
hir::TyTypeof(self.lower_expr(expr))
}
PolyTraitRef(ref bounds) => {
- let bounds = bounds.iter().map(|b| self.lower_ty_param_bound(b)).collect();
- hir::TyPolyTraitRef(bounds)
+ hir::TyPolyTraitRef(self.lower_bounds(bounds))
+ }
+ ImplTrait(ref bounds) => {
+ hir::TyImplTrait(self.lower_bounds(bounds))
}
Mac(_) => panic!("TyMac should have been expanded by now."),
},
});
}
+ fn visit_ty(&mut self, ty: &'ast Ty) {
+ self.insert(ty.id, NodeTy(ty));
+
+ self.with_parent(ty.id, |this| {
+ intravisit::walk_ty(this, ty);
+ });
+ }
+
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
if let TyKind::FixedLengthVec(_, ref length) = ty.node {
self.visit_ast_const_integer(length);
}
+ if let TyKind::ImplTrait(..) = ty.node {
+ self.create_def(ty.id, DefPathData::ImplTrait);
+ }
visit::walk_ty(self, ty);
}
if let hir::TyFixedLengthVec(_, ref length) = ty.node {
self.visit_hir_const_integer(length);
}
+ if let hir::TyImplTrait(..) = ty.node {
+ self.create_def(ty.id, DefPathData::ImplTrait);
+ }
intravisit::walk_ty(self, ty);
}
Initializer,
/// Pattern binding
Binding(InternedString),
+ /// An `impl Trait` type node.
+ ImplTrait
}
impl Definitions {
Initializer => {
InternedString::new("{{initializer}}")
}
+
+ ImplTrait => {
+ InternedString::new("{{impl-Trait}}")
+ }
}
}
NodeVariant(&'ast Variant),
NodeExpr(&'ast Expr),
NodeStmt(&'ast Stmt),
+ NodeTy(&'ast Ty),
NodeLocal(&'ast Pat),
NodePat(&'ast Pat),
NodeBlock(&'ast Block),
EntryVariant(NodeId, &'ast Variant),
EntryExpr(NodeId, &'ast Expr),
EntryStmt(NodeId, &'ast Stmt),
+ EntryTy(NodeId, &'ast Ty),
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
NodeVariant(n) => EntryVariant(p, n),
NodeExpr(n) => EntryExpr(p, n),
NodeStmt(n) => EntryStmt(p, n),
+ NodeTy(n) => EntryTy(p, n),
NodeLocal(n) => EntryLocal(p, n),
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
+ EntryTy(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
EntryVariant(_, n) => NodeVariant(n),
EntryExpr(_, n) => NodeExpr(n),
EntryStmt(_, n) => NodeStmt(n),
+ EntryTy(_, n) => NodeTy(n),
EntryLocal(_, n) => NodeLocal(n),
EntryPat(_, n) => NodePat(n),
EntryBlock(_, n) => NodeBlock(n),
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
+ EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
+ EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
+ Some(NodeTy(ty)) => ty.span,
Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
NodeVariant(a) => self.print_variant(&a),
NodeExpr(a) => self.print_expr(&a),
NodeStmt(a) => self.print_stmt(&a),
+ NodeTy(a) => self.print_type(&a),
NodePat(a) => self.print_pat(&a),
NodeBlock(a) => self.print_block(&a),
NodeLifetime(a) => self.print_lifetime(&a),
Some(NodeStmt(ref stmt)) => {
format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
}
+ Some(NodeTy(ref ty)) => {
+ format!("type {}{}", pprust::ty_to_string(&ty), id_str)
+ }
Some(NodeLocal(ref pat)) => {
format!("local {}{}", pprust::pat_to_string(&pat), id_str)
}
TyObjectSum(P<Ty>, TyParamBounds),
/// A type like `for<'a> Foo<&'a Bar>`
TyPolyTraitRef(TyParamBounds),
+ /// An `impl TraitA+TraitB` type.
+ TyImplTrait(TyParamBounds),
/// Unused for now
TyTypeof(P<Expr>),
/// TyInfer means the type should be inferred instead of it having been
hir::TyPolyTraitRef(ref bounds) => {
self.print_bounds("", &bounds[..])?;
}
+ hir::TyImplTrait(ref bounds) => {
+ self.print_bounds("impl ", &bounds[..])?;
+ }
hir::TyFixedLengthVec(ref ty, ref v) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
ty::TyClosure(..) |
ty::TyTuple(..) |
ty::TyProjection(..) |
- ty::TyParam(..) => {
+ ty::TyParam(..) |
+ ty::TyAnon(..) => {
t.super_fold_with(self)
}
}
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::{self, PredicateObligations, ProjectionMode};
+use traits::{self, PredicateObligations, Reveal};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::fmt;
// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
- // documentation for `ProjectionMode`.
- projection_mode: ProjectionMode,
+ // documentation for `Reveal`.
+ projection_mode: Reveal,
// When an error occurs, we want to avoid reporting "derived"
// errors that are due to this original failure. Normally, we
arenas: ty::CtxtArenas<'tcx>,
tables: Option<RefCell<ty::Tables<'tcx>>>,
param_env: Option<ty::ParameterEnvironment<'gcx>>,
- projection_mode: ProjectionMode,
+ projection_mode: Reveal,
normalize: bool
}
pub fn infer_ctxt(self,
tables: Option<ty::Tables<'tcx>>,
param_env: Option<ty::ParameterEnvironment<'gcx>>,
- projection_mode: ProjectionMode)
+ projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
}
}
- pub fn normalizing_infer_ctxt(self, projection_mode: ProjectionMode)
+ pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: false,
- projection_mode: ProjectionMode::AnyFinal,
+ projection_mode: Reveal::NotSpecializable,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
obligations_in_snapshot: Cell::new(false),
return value;
}
- self.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
+ self.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
value.trans_normalize(&infcx)
})
}
return value;
}
- self.infer_ctxt(None, Some(env.clone()), ProjectionMode::Any).enter(|infcx| {
+ self.infer_ctxt(None, Some(env.clone()), Reveal::All).enter(|infcx| {
value.trans_normalize(&infcx)
})
}
Ok(self.tcx.erase_regions(&result))
}
- pub fn projection_mode(&self) -> ProjectionMode {
+ pub fn projection_mode(&self) -> Reveal {
self.projection_mode
}
declare_lint! {
pub PRIVATE_IN_PUBLIC,
- Warn,
+ Deny,
"detect private items in public interfaces not caught by the old implementation"
}
match self.unsafe_context.root {
SafeContext => {
// Report an error.
- span_err!(self.tcx.sess, span, E0133,
- "{} requires unsafe function or block",
- description);
+ struct_span_err!(
+ self.tcx.sess, span, E0133,
+ "{} requires unsafe function or block", description)
+ .span_label(span, &format!("unsafe call requires unsafe function or block"))
+ .emit();
}
UnsafeBlock(block_id) => {
// OK, but record this.
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.id, item.span));
} else {
- span_err!(ctxt.session, item.span, E0138,
- "multiple 'start' functions");
+ struct_span_err!(
+ ctxt.session, item.span, E0138,
+ "multiple 'start' functions")
+ .span_label(ctxt.start_fn.unwrap().1,
+ &format!("previous `start` function here"))
+ .span_label(item.span, &format!("multiple `start` functions"))
+ .emit();
}
},
EntryPointType::None => ()
use hir::def::Def;
use hir::def_id::DefId;
use infer::InferCtxt;
-use traits::ProjectionMode;
+use traits::Reveal;
use ty::{self, Ty, TyCtxt};
use ty::layout::{LayoutError, Pointer, SizeSkeleton};
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
- self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
+ self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
// const, static and N in [T; N].
fn visit_expr(&mut self, expr: &hir::Expr) {
- self.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
+ self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
span_bug!(s, "intrinsicck: closure outside of function")
}
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
- self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
+ self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
use hir::def::*;
use hir::pat_util;
use ty::{self, TyCtxt, ParameterEnvironment};
-use traits::{self, ProjectionMode};
+use traits::{self, Reveal};
use ty::subst::Subst;
use lint;
use util::nodemap::NodeMap;
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = t_ret.subst(self.ir.tcx, ¶m_env.free_substs);
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
- ProjectionMode::Any).enter(|infcx| {
+ Reveal::All).enter(|infcx| {
let cause = traits::ObligationCause::dummy();
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
});
let lifetime_j = &lifetimes[j];
if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
- span_err!(self.sess, lifetime_j.lifetime.span, E0263,
- "lifetime name `{}` declared twice in \
- the same scope",
- lifetime_j.lifetime.name);
+ struct_span_err!(self.sess, lifetime_j.lifetime.span, E0263,
+ "lifetime name `{}` declared twice in the same scope",
+ lifetime_j.lifetime.name)
+ .span_label(lifetime_j.lifetime.span,
+ &format!("declared twice"))
+ .span_label(lifetime_i.lifetime.span,
+ &format!("previous declaration here"))
+ .emit();
}
}
constrained_by_input.visit_ty(&arg.ty);
}
- let mut appears_in_output = AllCollector { regions: FnvHashSet() };
+ let mut appears_in_output = AllCollector {
+ regions: FnvHashSet(),
+ impl_trait: false
+ };
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}",
//
// Subtle point: because we disallow nested bindings, we can just
// ignore binders here and scrape up all names we see.
- let mut appears_in_where_clause = AllCollector { regions: FnvHashSet() };
+ let mut appears_in_where_clause = AllCollector {
+ regions: FnvHashSet(),
+ impl_trait: false
+ };
for ty_param in generics.ty_params.iter() {
walk_list!(&mut appears_in_where_clause,
visit_ty_param_bound,
// Late bound regions are those that:
// - appear in the inputs
// - do not appear in the where-clauses
+ // - are not implicitly captured by `impl Trait`
for lifetime in &generics.lifetimes {
let name = lifetime.lifetime.name;
// appears in the where clauses? early-bound.
if appears_in_where_clause.regions.contains(&name) { continue; }
+ // any `impl Trait` in the return type? early-bound.
+ if appears_in_output.impl_trait { continue; }
+
// does not appear in the inputs, but appears in the return
// type? eventually this will be early-bound, but for now we
// just mark it so we can issue warnings.
struct AllCollector {
regions: FnvHashSet<ast::Name>,
+ impl_trait: bool
}
impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name);
}
+
+ fn visit_ty(&mut self, ty: &hir::Ty) {
+ if let hir::TyImplTrait(_) = ty.node {
+ self.impl_trait = true;
+ }
+ intravisit::walk_ty(self, ty);
+ }
}
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum StatementKind<'tcx> {
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
+ SetDiscriminant{ lvalue: Lvalue<'tcx>, variant_index: usize },
}
impl<'tcx> Debug for Statement<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
use self::StatementKind::*;
match self.kind {
- Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv)
+ Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
+ SetDiscriminant{lvalue: ref lv, variant_index: index} => {
+ write!(fmt, "discriminant({:?}) = {:?}", lv, index)
+ }
}
}
}
}
}
-impl<'a, 'gcx, 'tcx> Mir<'tcx> {
- pub fn operand_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
- operand: &Operand<'tcx>)
- -> Ty<'tcx>
- {
- match *operand {
- Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx),
- Operand::Constant(ref c) => c.ty,
- }
- }
-
- pub fn binop_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
- op: BinOp,
- lhs_ty: Ty<'tcx>,
- rhs_ty: Ty<'tcx>)
- -> Ty<'tcx>
- {
- // FIXME: handle SIMD correctly
- match op {
- BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem |
- BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => {
- // these should be integers or floats of the same size.
- assert_eq!(lhs_ty, rhs_ty);
- lhs_ty
- }
- BinOp::Shl | BinOp::Shr => {
- lhs_ty // lhs_ty can be != rhs_ty
- }
- BinOp::Eq | BinOp::Lt | BinOp::Le |
- BinOp::Ne | BinOp::Ge | BinOp::Gt => {
- tcx.types.bool
- }
- }
- }
-
- pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
- lvalue: &Lvalue<'tcx>)
- -> LvalueTy<'tcx>
- {
- match *lvalue {
- Lvalue::Var(index) =>
- LvalueTy::Ty { ty: self.var_decls[index].ty },
- Lvalue::Temp(index) =>
- LvalueTy::Ty { ty: self.temp_decls[index].ty },
- Lvalue::Arg(index) =>
- LvalueTy::Ty { ty: self.arg_decls[index].ty },
- Lvalue::Static(def_id) =>
+impl<'tcx> Lvalue<'tcx> {
+ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
+ match self {
+ &Lvalue::Var(index) =>
+ LvalueTy::Ty { ty: mir.var_decls[index].ty },
+ &Lvalue::Temp(index) =>
+ LvalueTy::Ty { ty: mir.temp_decls[index].ty },
+ &Lvalue::Arg(index) =>
+ LvalueTy::Ty { ty: mir.arg_decls[index].ty },
+ &Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
- Lvalue::ReturnPointer =>
- LvalueTy::Ty { ty: self.return_ty.unwrap() },
- Lvalue::Projection(ref proj) =>
- self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
+ &Lvalue::ReturnPointer =>
+ LvalueTy::Ty { ty: mir.return_ty.unwrap() },
+ &Lvalue::Projection(ref proj) =>
+ proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
}
}
+}
- pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
- rvalue: &Rvalue<'tcx>)
- -> Option<Ty<'tcx>>
+impl<'tcx> Rvalue<'tcx> {
+ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
{
- match *rvalue {
- Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
- Rvalue::Repeat(ref operand, ref count) => {
- let op_ty = self.operand_ty(tcx, operand);
+ match self {
+ &Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
+ &Rvalue::Repeat(ref operand, ref count) => {
+ let op_ty = operand.ty(mir, tcx);
let count = count.value.as_u64(tcx.sess.target.uint_type);
assert_eq!(count as usize as u64, count);
Some(tcx.mk_array(op_ty, count as usize))
}
- Rvalue::Ref(reg, bk, ref lv) => {
- let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
+ &Rvalue::Ref(reg, bk, ref lv) => {
+ let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
Some(tcx.mk_ref(
tcx.mk_region(reg),
ty::TypeAndMut {
}
))
}
- Rvalue::Len(..) => Some(tcx.types.usize),
- Rvalue::Cast(_, _, ty) => Some(ty),
- Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
- let lhs_ty = self.operand_ty(tcx, lhs);
- let rhs_ty = self.operand_ty(tcx, rhs);
- Some(self.binop_ty(tcx, op, lhs_ty, rhs_ty))
+ &Rvalue::Len(..) => Some(tcx.types.usize),
+ &Rvalue::Cast(_, _, ty) => Some(ty),
+ &Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
+ let lhs_ty = lhs.ty(mir, tcx);
+ let rhs_ty = rhs.ty(mir, tcx);
+ Some(op.ty(tcx, lhs_ty, rhs_ty))
}
- Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
- let lhs_ty = self.operand_ty(tcx, lhs);
- let rhs_ty = self.operand_ty(tcx, rhs);
- let ty = self.binop_ty(tcx, op, lhs_ty, rhs_ty);
+ &Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
+ let lhs_ty = lhs.ty(mir, tcx);
+ let rhs_ty = rhs.ty(mir, tcx);
+ let ty = op.ty(tcx, lhs_ty, rhs_ty);
let ty = tcx.mk_tup(vec![ty, tcx.types.bool]);
Some(ty)
}
- Rvalue::UnaryOp(_, ref operand) => {
- Some(self.operand_ty(tcx, operand))
+ &Rvalue::UnaryOp(_, ref operand) => {
+ Some(operand.ty(mir, tcx))
}
- Rvalue::Box(t) => {
+ &Rvalue::Box(t) => {
Some(tcx.mk_box(t))
}
- Rvalue::Aggregate(ref ak, ref ops) => {
+ &Rvalue::Aggregate(ref ak, ref ops) => {
match *ak {
AggregateKind::Vec => {
if let Some(operand) = ops.get(0) {
- let ty = self.operand_ty(tcx, operand);
+ let ty = operand.ty(mir, tcx);
Some(tcx.mk_array(ty, ops.len()))
} else {
None
}
AggregateKind::Tuple => {
Some(tcx.mk_tup(
- ops.iter().map(|op| self.operand_ty(tcx, op)).collect()
+ ops.iter().map(|op| op.ty(mir, tcx)).collect()
))
}
AggregateKind::Adt(def, _, substs) => {
}
}
}
- Rvalue::InlineAsm { .. } => None
+ &Rvalue::InlineAsm { .. } => None
+ }
+ }
+}
+
+impl<'tcx> Operand<'tcx> {
+ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+ match self {
+ &Operand::Consume(ref l) => l.ty(mir, tcx).to_ty(tcx),
+ &Operand::Constant(ref c) => c.ty,
+ }
+ }
+}
+
+impl<'tcx> BinOp {
+ pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ lhs_ty: Ty<'tcx>,
+ rhs_ty: Ty<'tcx>)
+ -> Ty<'tcx> {
+ // FIXME: handle SIMD correctly
+ match self {
+ &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
+ &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
+ // these should be integers or floats of the same size.
+ assert_eq!(lhs_ty, rhs_ty);
+ lhs_ty
+ }
+ &BinOp::Shl | &BinOp::Shr => {
+ lhs_ty // lhs_ty can be != rhs_ty
+ }
+ &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
+ &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
+ tcx.types.bool
+ }
}
}
}
ref $($mutability)* rvalue) => {
self.visit_assign(block, lvalue, rvalue);
}
+ StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
+ self.visit_lvalue(lvalue, LvalueContext::Store);
+ }
}
}
CrateName,
Cfg,
TargetList,
+ TargetCPUs,
+ TargetFeatures,
+ RelocationModels,
+ CodeModels,
}
pub enum Input {
lto: bool = (false, parse_bool,
"perform LLVM link-time optimizations"),
target_cpu: Option<String> = (None, parse_opt_string,
- "select target processor (llc -mcpu=help for details)"),
+ "select target processor (rustc --print target-cpus for details)"),
target_feature: String = ("".to_string(), parse_string,
- "target specific attributes (llc -mattr=help for details)"),
+ "target specific attributes (rustc --print target-features for details)"),
passes: Vec<String> = (Vec::new(), parse_list,
"a list of extra LLVM passes to run (space separated)"),
llvm_args: Vec<String> = (Vec::new(), parse_list,
no_redzone: Option<bool> = (None, parse_opt_bool,
"disable the use of the redzone"),
relocation_model: Option<String> = (None, parse_opt_string,
- "choose the relocation model to use (llc -relocation-model for details)"),
+ "choose the relocation model to use (rustc --print relocation-models for details)"),
code_model: Option<String> = (None, parse_opt_string,
- "choose the code model to use (llc -code-model for details)"),
+ "choose the code model to use (rustc --print code-models for details)"),
metadata: Vec<String> = (Vec::new(), parse_list,
"metadata to mangle symbol names with"),
extra_filename: String = ("".to_string(), parse_string,
"[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
opt::multi_s("", "print", "Comma separated list of compiler information to \
print on stdout",
- "[crate-name|file-names|sysroot|cfg|target-list]"),
+ "[crate-name|file-names|sysroot|cfg|target-list|target-cpus|\
+ target-features|relocation-models|code-models]"),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
early_error(error_format, "Value for codegen units must be a positive nonzero integer");
}
+ let mut prints = Vec::<PrintRequest>::new();
+ if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::TargetCPUs);
+ cg.target_cpu = None;
+ };
+ if cg.target_feature == "help" {
+ prints.push(PrintRequest::TargetFeatures);
+ cg.target_feature = "".to_string();
+ }
+ if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::RelocationModels);
+ cg.relocation_model = None;
+ }
+ if cg.code_model.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::CodeModels);
+ cg.code_model = None;
+ }
+
let cg = cg;
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
- let prints = matches.opt_strs("print").into_iter().map(|s| {
+ prints.extend(matches.opt_strs("print").into_iter().map(|s| {
match &*s {
"crate-name" => PrintRequest::CrateName,
"file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot,
"cfg" => PrintRequest::Cfg,
"target-list" => PrintRequest::TargetList,
+ "target-cpus" => PrintRequest::TargetCPUs,
+ "target-features" => PrintRequest::TargetFeatures,
+ "relocation-models" => PrintRequest::RelocationModels,
+ "code-models" => PrintRequest::CodeModels,
req => {
early_error(error_format, &format!("unknown print request `{}`", req))
}
}
- }).collect::<Vec<_>>();
+ }));
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
early_warn(error_format, "-C remark will not show source locations without \
true
}
- ty::TyClosure(..) => {
+ ty::TyClosure(..) | ty::TyAnon(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
}
}
ty::TyTuple(..) => Some(12),
ty::TyProjection(..) => Some(13),
ty::TyParam(..) => Some(14),
+ ty::TyAnon(..) => Some(15),
ty::TyInfer(..) | ty::TyError => None
}
}
let mut err = struct_span_err!(self.sess, span, E0072,
"recursive type `{}` has infinite size",
self.item_path_str(type_def_id));
+ err.span_label(span, &format!("recursive type has infinite size"));
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
self.item_path_str(type_def_id)));
let mut err = match warning_node_id {
Some(_) => None,
None => {
- Some(struct_span_err!(
- self.sess, span, E0038,
- "the trait `{}` cannot be made into an object",
- self.item_path_str(trait_def_id)))
+ let trait_str = self.item_path_str(trait_def_id);
+ let mut db = struct_span_err!(
+ self.sess, span, E0038,
+ "the trait `{}` cannot be made into an object",
+ trait_str);
+ db.span_label(span,
+ &format!("the trait `{}` cannot be made \
+ into an object", trait_str));
+ Some(db)
}
};
use dep_graph::DepGraph;
use infer::{InferCtxt, InferOk};
-use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt};
+use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
+use ty::subst::{Substs, Subst};
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData;
use super::CodeAmbiguity;
use super::CodeProjectionError;
use super::CodeSelectionError;
-use super::FulfillmentError;
-use super::FulfillmentErrorCode;
-use super::ObligationCause;
-use super::PredicateObligation;
+use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
+use super::{ObligationCause, BuiltinDerivedObligation};
+use super::{PredicateObligation, TraitObligation, Obligation};
use super::project;
use super::select::SelectionContext;
use super::Unimplemented;
/// along. Once all type inference constraints have been generated, the
/// method `select_all_or_error` can be used to report any remaining
/// ambiguous cases as errors.
+
pub struct FulfillmentContext<'tcx> {
// A list of all obligations that have been registered with this
// fulfillment context.
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
+
+ // A list of obligations that need to be deferred to
+ // a later time for them to be properly fulfilled.
+ deferred_obligations: Vec<DeferredObligation<'tcx>>,
}
#[derive(Clone)]
pub stalled_on: Vec<Ty<'tcx>>,
}
+/// An obligation which cannot be fulfilled in the context
+/// it was registered in, such as auto trait obligations on
+/// `impl Trait`, which require the concrete type to be
+/// available, only guaranteed after finishing type-checking.
+#[derive(Clone, Debug)]
+pub struct DeferredObligation<'tcx> {
+ pub predicate: ty::PolyTraitPredicate<'tcx>,
+ pub cause: ObligationCause<'tcx>
+}
+
+impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
+ /// If possible, create a `DeferredObligation` from
+ /// a trait predicate which had failed selection,
+ /// but could succeed later.
+ pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ obligation: &TraitObligation<'tcx>,
+ selection_err: &SelectionError<'tcx>)
+ -> Option<DeferredObligation<'tcx>> {
+ if let Unimplemented = *selection_err {
+ if DeferredObligation::must_defer(tcx, &obligation.predicate) {
+ return Some(DeferredObligation {
+ predicate: obligation.predicate.clone(),
+ cause: obligation.cause.clone()
+ });
+ }
+ }
+
+ None
+ }
+
+ /// Returns true if the given trait predicate can be
+ /// fulfilled at a later time.
+ pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ predicate: &ty::PolyTraitPredicate<'tcx>)
+ -> bool {
+ // Auto trait obligations on `impl Trait`.
+ if tcx.trait_has_default_impl(predicate.def_id()) {
+ let substs = predicate.skip_binder().trait_ref.substs;
+ if substs.types.as_slice().len() == 1 && substs.regions.is_empty() {
+ if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+
+ /// If possible, return the nested obligations required
+ /// to fulfill this obligation.
+ pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+ -> Option<Vec<PredicateObligation<'tcx>>> {
+ if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
+ // We can resolve the `impl Trait` to its concrete type.
+ if let Some(ty_scheme) = tcx.opt_lookup_item_type(def_id) {
+ let concrete_ty = ty_scheme.ty.subst(tcx, substs);
+ let concrete_substs = Substs::new_trait(vec![], vec![], concrete_ty);
+ let predicate = ty::TraitRef {
+ def_id: self.predicate.def_id(),
+ substs: tcx.mk_substs(concrete_substs)
+ }.to_predicate();
+
+ let original_obligation = Obligation::new(self.cause.clone(),
+ self.predicate.clone());
+ let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
+ return Some(vec![Obligation::new(cause, predicate)]);
+ }
+ }
+
+ None
+ }
+
+ /// Return the `PredicateObligation` this was created from.
+ pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
+ let predicate = ty::Predicate::Trait(self.predicate.clone());
+ Obligation::new(self.cause.clone(), predicate)
+ }
+
+ /// Return an error as if this obligation had failed.
+ pub fn to_error(&self) -> FulfillmentError<'tcx> {
+ FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
+ }
+}
+
impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(),
rfc1592_obligations: Vec::new(),
region_obligations: NodeMap(),
+ deferred_obligations: vec![],
}
}
{
self.select_where_possible(infcx)?;
+ // Fail all of the deferred obligations that haven't
+ // been otherwise removed from the context.
+ let deferred_errors = self.deferred_obligations.iter()
+ .map(|d| d.to_error());
+
let errors: Vec<_> =
self.predicates.to_errors(CodeAmbiguity)
.into_iter()
.map(|e| to_fulfillment_error(e))
+ .chain(deferred_errors)
.collect();
if errors.is_empty() {
Ok(())
self.predicates.pending_obligations()
}
+ pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
+ mem::replace(&mut self.deferred_obligations, vec![])
+ }
+
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
/// only attempts to select obligations that haven't been seen before.
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
// Process pending obligations.
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
- selcx: selcx,
- region_obligations: &mut self.region_obligations,
- rfc1592_obligations: &mut self.rfc1592_obligations
+ selcx: selcx,
+ region_obligations: &mut self.region_obligations,
+ rfc1592_obligations: &mut self.rfc1592_obligations,
+ deferred_obligations: &mut self.deferred_obligations
});
debug!("select: outcome={:?}", outcome);
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
- rfc1592_obligations: &'a mut Vec<PredicateObligation<'tcx>>
+ rfc1592_obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
}
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
process_predicate(self.selcx,
obligation,
self.region_obligations,
- self.rfc1592_obligations)
+ self.rfc1592_obligations,
+ self.deferred_obligations)
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
obligation: o,
stalled_on: vec![]
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
pending_obligation: &mut PendingPredicateObligation<'tcx>,
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
- rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>)
+ rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>,
+ deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
FulfillmentErrorCode<'tcx>>
{
Err(selection_err) => {
info!("selecting trait `{:?}` at depth {} yielded Err",
data, obligation.recursion_depth);
- Err(CodeSelectionError(selection_err))
+
+ let defer = DeferredObligation::from_select_error(selcx.tcx(),
+ &trait_obligation,
+ &selection_err);
+ if let Some(deferred_obligation) = defer {
+ if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
+ Ok(Some(nested))
+ } else {
+ // Pretend that the obligation succeeded,
+ // but record it for later.
+ deferred_obligations.push(deferred_obligation);
+ Ok(Some(vec![]))
+ }
+ } else {
+ Err(CodeSelectionError(selection_err))
+ }
}
}
}
// already has the required read edges, so we don't need
// to add any more edges here.
if data.is_global() {
+ // Don't cache predicates which were fulfilled
+ // by deferring them for later fulfillment.
+ if DeferredObligation::must_defer(tcx, data) {
+ return;
+ }
+
if let Some(data) = tcx.lift_to_global(data) {
if self.set.insert(data.clone()) {
debug!("add_if_global: global predicate `{:?}` added", data);
pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr;
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
+pub use self::fulfill::DeferredObligation;
pub use self::project::MismatchedProjectionTypes;
pub use self::project::{normalize, normalize_projection_type, Normalized};
-pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, ProjectionMode};
+pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode;
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
- tcx.infer_ctxt(None, Some(elaborated_env), ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(elaborated_env), Reveal::NotSpecializable).enter(|infcx| {
let predicates = match fully_normalize(&infcx, cause,
&infcx.parameter_environment.caller_bounds) {
Ok(predicates) => predicates,
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ProjectionMode {
+pub enum Reveal {
/// FIXME (#32205)
/// At coherence-checking time, we're still constructing the
/// specialization graph, and thus we only project
///
/// The projection would succeed if `Output` had been defined
/// directly in the impl for `u8`.
- Topmost,
+ ExactMatch,
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// fn main() {
/// let <() as Assoc>::Output = true;
/// }
- AnyFinal,
+ NotSpecializable,
- /// At trans time, all projections will succeed.
- Any,
-}
-
-impl ProjectionMode {
- pub fn is_topmost(&self) -> bool {
- match *self {
- ProjectionMode::Topmost => true,
- _ => false,
- }
- }
-
- pub fn is_any_final(&self) -> bool {
- match *self {
- ProjectionMode::AnyFinal => true,
- _ => false,
- }
- }
-
- pub fn is_any(&self) -> bool {
- match *self {
- ProjectionMode::Any => true,
- _ => false,
- }
- }
+ /// At trans time, all monomorphic projections will succeed.
+ /// Also, `impl Trait` is normalized to the concrete type,
+ /// which has to be already collected by type-checking.
+ ///
+ /// NOTE: As `impl Trait`'s concrete type should *never*
+ /// be observable directly by the user, `Reveal::All`
+ /// should not be used by checks which may expose
+ /// type equality or type contents to the user.
+ /// There are some exceptions, e.g. around OIBITS and
+ /// transmute-checking, which expose some details, but
+ /// not the whole concrete type of the `impl Trait`.
+ All,
}
-
pub type PolyProjectionObligation<'tcx> =
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
let ty = ty.super_fold_with(self);
match ty.sty {
+ ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
+ // Only normalize `impl Trait` after type-checking, usually in trans.
+ if self.selcx.projection_mode() == Reveal::All {
+ let generic_ty = self.tcx().lookup_item_type(def_id).ty;
+ let concrete_ty = generic_ty.subst(self.tcx(), substs);
+ self.fold_ty(concrete_ty)
+ } else {
+ ty
+ }
+ }
+
ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*)
// (*) This is kind of hacky -- we need to be able to
debug!("assemble_candidates_from_trait_def(..)");
// Check whether the self-type is itself a projection.
- let trait_ref = match obligation_trait_ref.self_ty().sty {
- ty::TyProjection(ref data) => data.trait_ref.clone(),
+ let (def_id, substs) = match obligation_trait_ref.self_ty().sty {
+ ty::TyProjection(ref data) => {
+ (data.trait_ref.def_id, data.trait_ref.substs)
+ }
+ ty::TyAnon(def_id, substs) => (def_id, 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.
};
// If so, extract what we know from the trait and try to come up with a good answer.
- let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id);
- let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
+ let trait_predicates = selcx.tcx().lookup_predicates(def_id);
+ let bounds = trait_predicates.instantiate(selcx.tcx(), substs);
let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec());
assemble_candidates_from_predicates(selcx,
obligation,
candidate_set.vec.push(ProjectionTyCandidate::Select);
}
- super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => {
+ super::VtableImpl(ref 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
impl_data.impl_def_id,
obligation.predicate.item_name);
let new_candidate = if let Some(node_item) = opt_node_item {
- if node_item.node.is_from_trait() {
- if node_item.item.ty.is_some() {
- // The impl inherited a `type Foo =
- // Bar` given in the trait, which is
- // implicitly default. No candidate.
- None
- } else {
- // The impl did not specify `type` and neither
- // did the trait:
- //
- // ```rust
- // trait Foo { type T; }
- // impl Foo for Bar { }
- // ```
- //
- // This is an error, but it will be
- // reported in `check_impl_items_against_trait`.
- // We accept it here but will flag it as
- // an error when we confirm the candidate
- // (which will ultimately lead to `normalize_to_error`
- // being invoked).
+ let is_default = if node_item.node.is_from_trait() {
+ // If true, the impl inherited a `type Foo = Bar`
+ // given in the trait, which is implicitly default.
+ // Otherwise, the impl did not specify `type` and
+ // neither did the trait:
+ //
+ // ```rust
+ // trait Foo { type T; }
+ // impl Foo for Bar { }
+ // ```
+ //
+ // This is an error, but it will be
+ // reported in `check_impl_items_against_trait`.
+ // We accept it here but will flag it as
+ // an error when we confirm the candidate
+ // (which will ultimately lead to `normalize_to_error`
+ // being invoked).
+ node_item.item.ty.is_some()
+ } else {
+ node_item.item.defaultness.is_default()
+ };
+
+ // 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.
+ if !is_default {
+ Some(ProjectionTyCandidate::Select)
+ } else if selcx.projection_mode() == Reveal::All {
+ assert!(!poly_trait_ref.needs_infer());
+ if !poly_trait_ref.needs_subst() {
Some(ProjectionTyCandidate::Select)
+ } else {
+ None
}
- } else if node_item.item.defaultness.is_default() {
- // The impl specified `default type Foo =
- // Bar`. No candidate.
- None
} else {
- // The impl specified `type Foo = Bar`
- // with no default. Add a candidate.
- Some(ProjectionTyCandidate::Select)
+ None
}
} else {
// This is saying that neither the trait nor
};
candidate_set.vec.extend(new_candidate);
}
- super::VtableImpl(_) => {
- // In trans mode, we can just project out of impls, no prob.
- assert!(selcx.projection_mode().is_any());
- candidate_set.vec.push(ProjectionTyCandidate::Select);
- }
super::VtableParam(..) => {
// This case tell us nothing about the value of an
// associated type. Consider:
/// starting from the given impl.
///
/// Based on the "projection mode", this lookup may in fact only examine the
-/// topmost impl. See the comments for `ProjectionMode` for more details.
+/// topmost impl. See the comments for `Reveal` for more details.
fn assoc_ty_def<'cx, 'gcx, 'tcx>(
selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
impl_def_id: DefId,
{
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
- if selcx.projection_mode().is_topmost() {
+ if selcx.projection_mode() == Reveal::ExactMatch {
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(selcx.tcx()) {
if let ty::TypeTraitItem(assoc_ty) = item {
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{ObjectCastObligation, Obligation};
-use super::ProjectionMode;
+use super::Reveal;
use super::TraitNotObjectSafe;
use super::Selection;
use super::SelectionResult;
self.infcx
}
- pub fn projection_mode(&self) -> ProjectionMode {
+ pub fn projection_mode(&self) -> Reveal {
self.infcx.projection_mode()
}
// before we go into the whole skolemization thing, just
// quickly check if the self-type is a projection at all.
- let trait_def_id = match obligation.predicate.0.trait_ref.self_ty().sty {
- ty::TyProjection(ref data) => data.trait_ref.def_id,
+ match obligation.predicate.0.trait_ref.self_ty().sty {
+ ty::TyProjection(_) | ty::TyAnon(..) => {}
ty::TyInfer(ty::TyVar(_)) => {
span_bug!(obligation.cause.span,
"Self=_ should have been handled by assemble_candidates");
}
- _ => { return; }
- };
-
- debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}",
- trait_def_id);
+ _ => return
+ }
let result = self.probe(|this, snapshot| {
- this.match_projection_obligation_against_bounds_from_trait(obligation,
+ this.match_projection_obligation_against_definition_bounds(obligation,
snapshot)
});
}
}
- fn match_projection_obligation_against_bounds_from_trait(
+ fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
let (skol_trait_predicate, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot);
- debug!("match_projection_obligation_against_bounds_from_trait: \
+ debug!("match_projection_obligation_against_definition_bounds: \
skol_trait_predicate={:?} skol_map={:?}",
skol_trait_predicate,
skol_map);
- let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty {
- ty::TyProjection(ref data) => &data.trait_ref,
+ let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
+ ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs),
+ ty::TyAnon(def_id, substs) => (def_id, substs),
_ => {
span_bug!(
obligation.cause.span,
- "match_projection_obligation_against_bounds_from_trait() called \
+ "match_projection_obligation_against_definition_bounds() called \
but self-ty not a projection: {:?}",
skol_trait_predicate.trait_ref.self_ty());
}
};
- debug!("match_projection_obligation_against_bounds_from_trait: \
- projection_trait_ref={:?}",
- projection_trait_ref);
+ debug!("match_projection_obligation_against_definition_bounds: \
+ def_id={:?}, substs={:?}",
+ def_id, substs);
- let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id);
- let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
- debug!("match_projection_obligation_against_bounds_from_trait: \
+ let item_predicates = self.tcx().lookup_predicates(def_id);
+ let bounds = item_predicates.instantiate(self.tcx(), substs);
+ debug!("match_projection_obligation_against_definition_bounds: \
bounds={:?}",
bounds);
&skol_map,
snapshot)));
- debug!("match_projection_obligation_against_bounds_from_trait: \
+ debug!("match_projection_obligation_against_definition_bounds: \
matching_bound={:?}",
matching_bound);
match matching_bound {
}
}
ty::TyParam(..) |
- ty::TyProjection(..) => {
+ ty::TyProjection(..) |
+ ty::TyAnon(..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
}))
}
- ty::TyProjection(_) | ty::TyParam(_) => None,
+ ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
ty::TyInfer(ty::TyVar(_)) => Ambiguous,
ty::TyInfer(ty::FreshTy(_))
Where(ty::Binder(tys.to_vec()))
}
- ty::TyStruct(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) => {
+ ty::TyStruct(..) | ty::TyEnum(..) |
+ ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => {
// Fallback to whatever user-defined impls exist in this case.
None
}
ty::TyTrait(..) |
ty::TyParam(..) |
ty::TyProjection(..) |
+ ty::TyAnon(..) |
ty::TyInfer(ty::TyVar(_)) |
ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) |
{
self.in_snapshot(|this, snapshot| {
let result =
- this.match_projection_obligation_against_bounds_from_trait(obligation,
+ this.match_projection_obligation_against_definition_bounds(obligation,
snapshot);
assert!(result);
})
obligation)
};
- let cause = self.derived_cause(obligation, BuiltinDerivedObligation);
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
self.collect_predicates_for_types(cause,
obligation.recursion_depth+1,
trait_def,
{
debug!("vtable_default_impl: nested={:?}", nested);
- let cause = self.derived_cause(obligation, BuiltinDerivedObligation);
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
let mut obligations = self.collect_predicates_for_types(
cause,
obligation.recursion_depth+1,
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let (trait_ref, skol_map) =
this.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
- let cause = this.derived_cause(obligation, ImplDerivedObligation);
+ let cause = obligation.derived_cause(ImplDerivedObligation);
this.impl_or_trait_obligations(cause,
obligation.recursion_depth + 1,
trait_def_id,
this.rematch_impl(impl_def_id, obligation,
snapshot);
debug!("confirm_impl_candidate substs={:?}", substs);
- let cause = this.derived_cause(obligation, ImplDerivedObligation);
+ let cause = obligation.derived_cause(ImplDerivedObligation);
this.vtable_impl(impl_def_id, substs, cause,
obligation.recursion_depth + 1,
skol_map, snapshot)
}).collect();
self.infcx().plug_leaks(skol_map, snapshot, &predicates)
}
+}
+impl<'tcx> TraitObligation<'tcx> {
#[allow(unused_comparisons)]
- fn derived_cause(&self,
- obligation: &TraitObligation<'tcx>,
- variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
- -> ObligationCause<'tcx>
+ pub fn derived_cause(&self,
+ variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
+ -> ObligationCause<'tcx>
{
/*!
* Creates a cause for obligations that are derived from
* reporting.
*/
+ let obligation = self;
+
// NOTE(flaper87): As of now, it keeps track of the whole error
// chain. Ideally, we should have a way to configure this either
// by using -Z verbose or just a CLI argument.
use infer::{InferCtxt, TypeOrigin};
use middle::region;
use ty::subst::{Subst, Substs};
-use traits::{self, ProjectionMode, ObligationCause, Normalized};
+use traits::{self, Reveal, ObligationCause, Normalized};
use ty::{self, TyCtxt};
use syntax_pos::DUMMY_SP;
.unwrap()
.subst(tcx, &penv.free_substs);
- let result = tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
+ let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| {
// Normalize the trait reference, adding any obligations
// that arise into the impl1 assumptions.
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
use super::{OverlapError, specializes};
use hir::def_id::DefId;
-use traits::{self, ProjectionMode};
+use traits::{self, Reveal};
use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
use ty::fast_reject::{self, SimplifiedType};
use syntax::ast::Name;
let possible_sibling = *slot;
let tcx = tcx.global_tcx();
- let (le, ge) = tcx.infer_ctxt(None, None,
- ProjectionMode::Topmost).enter(|infcx| {
+ let (le, ge) = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
let overlap = traits::overlapping_impls(&infcx,
possible_sibling,
impl_def_id);
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use std::fmt;
+use std::rc::Rc;
// structural impls for the structs in traits
}
}
+impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
+ type Lifted = traits::ObligationCauseCode<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+ match *self {
+ super::MiscObligation => Some(super::MiscObligation),
+ super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
+ super::TupleElem => Some(super::TupleElem),
+ super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf),
+ super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)),
+ super::ReferenceOutlivesReferent(ty) => {
+ tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
+ }
+ super::ObjectCastObligation(ty) => {
+ tcx.lift(&ty).map(super::ObjectCastObligation)
+ }
+ super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
+ super::StructInitializerSized => Some(super::StructInitializerSized),
+ super::VariableType(id) => Some(super::VariableType(id)),
+ super::ReturnType => Some(super::ReturnType),
+ super::RepeatVec => Some(super::RepeatVec),
+ super::ClosureCapture(node_id, span, bound) => {
+ Some(super::ClosureCapture(node_id, span, bound))
+ }
+ super::FieldSized => Some(super::FieldSized),
+ super::ConstSized => Some(super::ConstSized),
+ super::SharedStatic => Some(super::SharedStatic),
+ super::BuiltinDerivedObligation(ref cause) => {
+ tcx.lift(cause).map(super::BuiltinDerivedObligation)
+ }
+ super::ImplDerivedObligation(ref cause) => {
+ tcx.lift(cause).map(super::ImplDerivedObligation)
+ }
+ super::CompareImplMethodObligation => {
+ Some(super::CompareImplMethodObligation)
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
+ type Lifted = traits::DerivedObligationCause<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
+ tcx.lift(&*self.parent_code).map(|code| {
+ traits::DerivedObligationCause {
+ parent_trait_ref: trait_ref,
+ parent_code: Rc::new(code)
+ }
+ })
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
+ type Lifted = traits::ObligationCause<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.code).map(|code| {
+ traits::ObligationCause {
+ span: self.span,
+ body_id: self.body_id,
+ code: code,
+ }
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
+ type Lifted = traits::DeferredObligation<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.predicate).and_then(|predicate| {
+ tcx.lift(&self.cause).map(|cause| {
+ traits::DeferredObligation {
+ predicate: predicate,
+ cause: cause
+ }
+ })
+ })
+ }
+}
+
// For trans only.
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
type Lifted = traits::Vtable<'tcx, ()>;
self.value.visit_with(visitor) || self.obligations.visit_with(visitor)
}
}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ match *self {
+ super::MiscObligation |
+ super::SliceOrArrayElem |
+ super::TupleElem |
+ super::ItemObligation(_) |
+ super::AssignmentLhsSized |
+ super::StructInitializerSized |
+ super::VariableType(_) |
+ super::ReturnType |
+ super::RepeatVec |
+ super::ClosureCapture(..) |
+ super::FieldSized |
+ super::ConstSized |
+ super::SharedStatic |
+ super::CompareImplMethodObligation => self.clone(),
+
+ super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
+ super::ReferenceOutlivesReferent(ty) => {
+ super::ReferenceOutlivesReferent(ty.fold_with(folder))
+ }
+ super::ObjectCastObligation(ty) => {
+ super::ObjectCastObligation(ty.fold_with(folder))
+ }
+ super::BuiltinDerivedObligation(ref cause) => {
+ super::BuiltinDerivedObligation(cause.fold_with(folder))
+ }
+ super::ImplDerivedObligation(ref cause) => {
+ super::ImplDerivedObligation(cause.fold_with(folder))
+ }
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ match *self {
+ super::MiscObligation |
+ super::SliceOrArrayElem |
+ super::TupleElem |
+ super::ItemObligation(_) |
+ super::AssignmentLhsSized |
+ super::StructInitializerSized |
+ super::VariableType(_) |
+ super::ReturnType |
+ super::RepeatVec |
+ super::ClosureCapture(..) |
+ super::FieldSized |
+ super::ConstSized |
+ super::SharedStatic |
+ super::CompareImplMethodObligation => false,
+
+ super::ProjectionWf(proj) => proj.visit_with(visitor),
+ super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor),
+ super::ObjectCastObligation(ty) => ty.visit_with(visitor),
+ super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor),
+ super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor)
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::DerivedObligationCause<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ traits::DerivedObligationCause {
+ parent_trait_ref: self.parent_trait_ref.fold_with(folder),
+ parent_code: self.parent_code.fold_with(folder)
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.parent_trait_ref.visit_with(visitor) || self.parent_code.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ traits::ObligationCause {
+ span: self.span,
+ body_id: self.body_id,
+ code: self.code.fold_with(folder),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.code.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ traits::DeferredObligation {
+ predicate: self.predicate.fold_with(folder),
+ cause: self.cause.fold_with(folder)
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
+ }
+}
}
ty::TyProjection(..) |
- ty::TyParam(_) => {
+ ty::TyParam(_) |
+ ty::TyAnon(..) => {
TC::All
}
sty_debug_print!(
self,
TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
- TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
+ TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
self.mk_param(def.space, def.index, def.name)
}
+ pub fn mk_anon(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyAnon(def_id, substs))
+ }
+
pub fn trait_items(self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'gcx>>> {
self.trait_items_cache.memoize(trait_did, || {
let def_ids = self.trait_item_def_ids(trait_did);
"type parameter".to_string()
}
}
+ ty::TyAnon(..) => "anonymized type".to_string(),
ty::TyError => "type error".to_string(),
}
}
TraitSimplifiedType(DefId),
StructSimplifiedType(DefId),
ClosureSimplifiedType(DefId),
+ AnonSimplifiedType(DefId),
FunctionSimplifiedType(usize),
ParameterSimplifiedType,
}
None
}
}
+ ty::TyAnon(def_id, _) => {
+ Some(AnonSimplifiedType(def_id))
+ }
ty::TyInfer(_) | ty::TyError => None,
}
}
self.add_projection_ty(data);
}
+ &ty::TyAnon(_, substs) => {
+ self.add_flags(TypeFlags::HAS_PROJECTION);
+ self.add_substs(substs);
+ }
+
&ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
let mut computation = FlagComputation::new();
computation.add_substs(principal.0.substs);
// in the normalized form
if self.just_constrained {
match t.sty {
- ty::TyProjection(..) => { return false; }
+ ty::TyProjection(..) | ty::TyAnon(..) => { return false; }
_ => { }
}
}
data @ DefPathData::Initializer |
data @ DefPathData::MacroDef(..) |
data @ DefPathData::ClosureExpr |
- data @ DefPathData::Binding(..) => {
+ data @ DefPathData::Binding(..) |
+ data @ DefPathData::ImplTrait => {
let parent_def_id = self.parent_def_id(def_id).unwrap();
self.push_item_path(buffer, parent_def_id);
buffer.push(&data.as_interned_str());
ty::TyFnPtr(_) |
ty::TyProjection(_) |
ty::TyParam(_) |
+ ty::TyAnon(..) |
ty::TyInfer(_) |
ty::TyError |
ty::TyFloat(_) => None,
(&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => {
let fields = &def.struct_variant().fields;
assert_eq!(fields.len(), 1);
- let ty = normalize_associated_type(infcx, fields[0].ty(tcx, substs));
- match *ty.layout(infcx)? {
+ match *fields[0].ty(tcx, substs).layout(infcx)? {
// FIXME(eddyb) also allow floating-point types here.
Scalar { value: Int(_), non_zero: false } |
Scalar { value: Pointer, non_zero: false } => {
(_, &ty::TyStruct(def, substs)) => {
Struct::non_zero_field_path(infcx, def.struct_variant().fields
.iter().map(|field| {
- normalize_associated_type(infcx, field.ty(tcx, substs))
+ field.ty(tcx, substs)
}))
}
Struct::non_zero_field_path(infcx, Some(ety).into_iter())
}
+ (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
+ let normalized = normalize_associated_type(infcx, ty);
+ if ty == normalized {
+ return Ok(None);
+ }
+ return Struct::non_zero_field_in_type(infcx, normalized);
+ }
+
// Anything else is not a non-zero type.
_ => Ok(None)
}
impl<'a, 'gcx, 'tcx> Layout {
pub fn compute_uncached(ty: Ty<'gcx>,
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
- -> Result<Layout, LayoutError<'gcx>> {
+ -> Result<&'gcx Layout, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
+ let success = |layout| Ok(tcx.intern_layout(layout));
let dl = &tcx.data_layout;
assert!(!ty.has_infer_types());
if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
Scalar { value: Pointer, non_zero: non_zero }
} else {
+ let pointee = normalize_associated_type(infcx, pointee);
let unsized_part = tcx.struct_tail(pointee);
let meta = match unsized_part.sty {
ty::TySlice(_) | ty::TyStr => {
let element = ty.simd_type(tcx);
match *element.layout(infcx)? {
Scalar { value, .. } => {
- return Ok(Vector {
+ return success(Vector {
element: value,
count: ty.simd_size(tcx) as u64
});
}
}
let fields = def.struct_variant().fields.iter().map(|field| {
- normalize_associated_type(infcx, field.ty(tcx, substs))
- .layout(infcx)
+ field.ty(tcx, substs).layout(infcx)
});
let packed = tcx.lookup_packed(def.did);
let mut st = Struct::new(dl, packed);
let mut st = Struct::new(dl, false);
st.extend(dl, drop_flag.iter().map(Ok), ty)?;
- return Ok(Univariant { variant: st, non_zero: false });
+ return success(Univariant { variant: st, non_zero: false });
}
if !dtor && def.variants.iter().all(|v| v.fields.is_empty()) {
}
let (discr, signed) = Integer::repr_discr(tcx, hint, min, max);
- return Ok(CEnum {
+ return success(CEnum {
discr: discr,
signed: signed,
min: min as u64,
// (Typechecking will reject discriminant-sizing attrs.)
assert_eq!(hint, attr::ReprAny);
let fields = def.variants[0].fields.iter().map(|field| {
- normalize_associated_type(infcx, field.ty(tcx, substs))
- .layout(infcx)
+ field.ty(tcx, substs).layout(infcx)
});
let mut st = Struct::new(dl, false);
st.extend(dl, fields.chain(drop_flag.iter().map(Ok)), ty)?;
- return Ok(Univariant { variant: st, non_zero: false });
+ return success(Univariant { variant: st, non_zero: false });
}
// Cache the substituted and normalized variant field types.
let variants = def.variants.iter().map(|v| {
- v.fields.iter().map(|field| {
- normalize_associated_type(infcx, field.ty(tcx, substs))
- }).collect::<Vec<_>>()
+ v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
}).collect::<Vec<_>>();
if !dtor && variants.len() == 2 && hint == attr::ReprAny {
if path == &[0] && variants[discr].len() == 1 {
match *variants[discr][0].layout(infcx)? {
Scalar { value, .. } => {
- return Ok(RawNullablePointer {
+ return success(RawNullablePointer {
nndiscr: discr as u64,
value: value
});
path.push(0); // For GEP through a pointer.
path.reverse();
let mut st = Struct::new(dl, false);
- st.extend(dl, variants[discr].iter().map(|ty| {
- ty.layout(infcx)
- }), ty)?;
- return Ok(StructWrappedNullablePointer {
+ st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
+ return success(StructWrappedNullablePointer {
nndiscr: discr as u64,
nonnull: st,
discrfield: path
}
// Types with no meaningful known layout.
- ty::TyProjection(_) | ty::TyParam(_) => {
+ ty::TyProjection(_) | ty::TyAnon(..) => {
+ let normalized = normalize_associated_type(infcx, ty);
+ if ty == normalized {
+ return Err(LayoutError::Unknown(ty));
+ }
+ return normalized.layout(infcx);
+ }
+ ty::TyParam(_) => {
return Err(LayoutError::Unknown(ty));
}
ty::TyInfer(_) | ty::TyError => {
}
};
- Ok(layout)
+ success(layout)
}
/// Returns true if the layout corresponds to an unsized type.
// Get a zero-sized variant or a pointer newtype.
let zero_or_ptr_variant = |i: usize| {
let fields = def.variants[i].fields.iter().map(|field| {
- let ty = normalize_associated_type(infcx, &field.ty(tcx, substs));
- SizeSkeleton::compute(ty, infcx)
+ SizeSkeleton::compute(field.ty(tcx, substs), infcx)
});
let mut ptr = None;
for field in fields {
}
}
+ ty::TyProjection(_) | ty::TyAnon(..) => {
+ let normalized = normalize_associated_type(infcx, ty);
+ if ty == normalized {
+ Err(err)
+ } else {
+ SizeSkeleton::compute(normalized, infcx)
+ }
+ }
+
_ => Err(err)
}
}
}
}
}
- Some(ast_map::NodeExpr(..)) => {
+ Some(ast_map::NodeExpr(expr)) => {
// This is a convenience to allow closures to work.
- ParameterEnvironment::for_item(tcx, tcx.map.get_parent(id))
+ if let hir::ExprClosure(..) = expr.node {
+ ParameterEnvironment::for_item(tcx, tcx.map.get_parent(id))
+ } else {
+ tcx.empty_parameter_environment()
+ }
}
Some(ast_map::NodeForeignItem(item)) => {
let def_id = tcx.map.local_def_id(id);
}
}
- TyProjection(..) => {
+ TyProjection(..) | TyAnon(..) => {
// must calculate explicitly.
// FIXME: consider special-casing always-Sized projections
vec![ty]
ty::TyEnum(..) | // OutlivesNominalType
ty::TyStruct(..) | // OutlivesNominalType
ty::TyBox(..) | // OutlivesNominalType (ish)
+ ty::TyAnon(..) | // OutlivesNominalType (ish)
ty::TyStr | // OutlivesScalar (ish)
ty::TyArray(..) | // ...
ty::TySlice(..) | // ...
Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name))
}
+ (&ty::TyAnon(a_def_id, a_substs), &ty::TyAnon(b_def_id, b_substs))
+ if a_def_id == b_def_id =>
+ {
+ let substs = relate_substs(relation, None, a_substs, b_substs)?;
+ Ok(tcx.mk_anon(a_def_id, substs))
+ }
+
_ =>
{
Err(TypeError::Sorts(expected_found(relation, &a, &b)))
}
}
+impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
+ type Lifted = ty::ProjectionTy<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+ -> Option<ty::ProjectionTy<'tcx>> {
+ tcx.lift(&self.trait_ref).map(|trait_ref| {
+ ty::ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: self.item_name
+ }
+ })
+ }
+}
+
impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
type Lifted = ty::ProjectionPredicate<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<ty::ProjectionPredicate<'tcx>> {
- tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+ tcx.lift(&(self.projection_ty, self.ty)).map(|(projection_ty, ty)| {
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- trait_ref: trait_ref,
- item_name: self.projection_ty.item_name
- },
+ projection_ty: projection_ty,
ty: ty
}
})
ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)),
ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)),
ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)),
+ ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
ty::TyParam(..) => self.sty.clone(),
ty::TyStruct(_did, ref substs) => substs.visit_with(visitor),
ty::TyClosure(_did, ref substs) => substs.visit_with(visitor),
ty::TyProjection(ref data) => data.visit_with(visitor),
+ ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
ty::TyParam(..) => false,
/// `<T as Trait<..>>::N`.
TyProjection(ProjectionTy<'tcx>),
+ /// Anonymized (`impl Trait`) type found in a return type.
+ /// The DefId comes from the `impl Trait` ast::Ty node, and the
+ /// substitutions are for the generics of the function in question.
+ /// After typeck, the concrete type can be found in the `tcache` map.
+ TyAnon(DefId, &'tcx Substs<'tcx>),
+
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
TyParam(ParamTy),
v
}
TyEnum(_, substs) |
- TyStruct(_, substs) => {
+ TyStruct(_, substs) |
+ TyAnon(_, substs) => {
substs.regions.as_slice().to_vec()
}
TyClosure(_, ref substs) => {
use ty::subst;
use infer::InferCtxt;
use hir::pat_util;
-use traits::{self, ProjectionMode};
+use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{Disr, ParameterEnvironment};
use ty::fold::TypeVisitor;
self_type: Ty<'tcx>, span: Span)
-> Result<(),CopyImplementationError> {
// FIXME: (@jroesch) float this code up
- tcx.infer_ctxt(None, Some(self.clone()),
- ProjectionMode::Topmost).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| {
let adt = match self_type.sty {
ty::TyStruct(struct_def, substs) => {
for field in struct_def.all_fields() {
TyRawPtr(m) |
TyRef(_, m) => self.hash(m.mutbl),
TyClosure(def_id, _) |
+ TyAnon(def_id, _) |
TyFnDef(def_id, _, _) => self.def_id(def_id),
TyFnPtr(f) => {
self.hash(f.unsafety);
param_env: &ParameterEnvironment<'tcx>,
bound: ty::BuiltinBound, span: Span) -> bool
{
- tcx.infer_ctxt(None, Some(param_env.clone()), ProjectionMode::Topmost).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch).enter(|infcx| {
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
})
}
}) => Some(true),
TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
- TyClosure(..) | TyEnum(..) | TyStruct(..) |
+ TyClosure(..) | TyEnum(..) | TyStruct(..) | TyAnon(..) |
TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
}.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span));
TyStr | TyTrait(..) | TySlice(_) => Some(false),
TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
- TyInfer(..) | TyError => None
+ TyInfer(..) | TyAnon(..) | TyError => None
}.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span));
if !self.has_param_types() && !self.has_self_ty() {
}
let layout = Layout::compute_uncached(self, infcx)?;
- let layout = tcx.intern_layout(layout);
if can_cache {
tcx.layout_cache.borrow_mut().insert(self, layout);
}
}).collect::<Vec<_>>());
}
ty::TyEnum(_, ref substs) |
- ty::TyStruct(_, ref substs) => {
+ ty::TyStruct(_, ref substs) |
+ ty::TyAnon(_, ref substs) => {
push_reversed(stack, substs.types.as_slice());
}
ty::TyClosure(_, ref substs) => {
// types appearing in the fn signature
}
+ ty::TyAnon(..) => {
+ // all of the requirements on type parameters
+ // should've been checked by the instantiation
+ // of whatever returned this exact `impl Trait`.
+ }
+
ty::TyTrait(ref data) => {
// WfObject
//
}
TyTrait(ref data) => write!(f, "{}", data),
ty::TyProjection(ref data) => write!(f, "{}", data),
+ ty::TyAnon(def_id, substs) => {
+ ty::tls::with(|tcx| {
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let item_predicates = tcx.lookup_predicates(def_id);
+ let substs = tcx.lift(&substs).unwrap_or_else(|| {
+ tcx.mk_substs(subst::Substs::empty())
+ });
+ let bounds = item_predicates.instantiate(tcx, substs);
+
+ let mut first = true;
+ let mut is_sized = false;
+ write!(f, "impl")?;
+ for predicate in bounds.predicates.into_vec() {
+ if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
+ // Don't print +Sized, but rather +?Sized if absent.
+ if Some(trait_ref.def_id()) == tcx.lang_items.sized_trait() {
+ is_sized = true;
+ continue;
+ }
+
+ write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?;
+ first = false;
+ }
+ }
+ if !is_sized {
+ write!(f, "{}?Sized", if first { " " } else { "+" })?;
+ }
+ Ok(())
+ })
+ }
TyStr => write!(f, "str"),
TyClosure(did, substs) => ty::tls::with(|tcx| {
write!(f, "[closure")?;
pub fn get_targets() -> Box<Iterator<Item=String>> {
Box::new(TARGETS.iter().filter_map(|t| -> Option<String> {
load_specific(t)
- .map(|t| t.llvm_target)
+ .and(Ok(t.to_string()))
.ok()
}))
}
}
let bits_per_block = self.bits_per_block(ctxt);
match stmt.kind {
+ repr::StatementKind::SetDiscriminant { .. } => {
+ span_bug!(stmt.source_info.span, "SetDiscriminant should not exist in borrowck");
+ }
repr::StatementKind::Assign(ref lvalue, _) => {
// assigning into this `lvalue` kills all
// MoveOuts from it, and *also* all MoveOuts
repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
(lvalue, rvalue)
}
+ repr::StatementKind::SetDiscriminant{ .. } =>
+ span_bug!(stmt.source_info.span,
+ "sanity_check should run before Deaggregator inserts SetDiscriminant"),
};
if lvalue == peek_arg_lval {
{
match self.move_data().move_paths[path].content {
MovePathContent::Lvalue(ref lvalue) => {
- let ty = self.mir.lvalue_ty(self.tcx, lvalue).to_ty(self.tcx);
+ let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty);
self.tcx.type_needs_drop_given_env(ty, self.param_env())
let mut fields = fields;
fields.retain(|&(ref lvalue, _)| {
- let ty = self.mir.lvalue_ty(self.tcx, lvalue).to_ty(self.tcx);
+ let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
self.tcx.type_needs_drop_given_env(ty, self.param_env())
});
/// This creates a "drop ladder" that drops the needed fields of the
/// ADT, both in the success case or if one of the destructors fail.
fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock {
- let ty = self.mir.lvalue_ty(self.tcx, c.lvalue).to_ty(self.tcx);
+ let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
match ty.sty {
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
self.open_drop_for_adt(c, def, substs)
// dataflow can create unneeded children in some cases
// - be sure to ignore them.
- let ty = self.mir.lvalue_ty(self.tcx, c.lvalue).to_ty(self.tcx);
+ let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
match ty.sty {
ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
Rvalue::InlineAsm { .. } => {}
}
}
+ StatementKind::SetDiscriminant{ .. } => {
+ span_bug!(stmt.source_info.span,
+ "SetDiscriminant should not exist during borrowck");
+ }
}
}
fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
lv: &repr::Lvalue<'tcx>) -> bool {
- let ty = mir.lvalue_ty(tcx, lv).to_ty(tcx);
+ let ty = lv.ty(mir, tcx).to_ty(tcx);
match ty.sty {
ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false",
// don't move out of non-Copy things
if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content {
- let ty = mir.lvalue_ty(tcx, lvalue).to_ty(tcx);
+ let ty = lvalue.ty(mir, tcx).to_ty(tcx);
if !ty.moves_by_default(tcx, param_env, DUMMY_SP) {
continue;
}
let block = &mir[loc.block];
match block.statements.get(loc.index) {
Some(stmt) => match stmt.kind {
+ repr::StatementKind::SetDiscriminant{ .. } => {
+ span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck");
+ }
repr::StatementKind::Assign(ref lvalue, _) => {
debug!("drop_flag_effects: assignment {:?}", stmt);
on_all_children_bits(tcx, mir, move_data,
lp: &LoanPath<'tcx>,
assign:
&move_data::Assignment) {
- struct_span_err!(
+ let mut err = struct_span_err!(
self.tcx.sess, span, E0384,
"re-assignment of immutable variable `{}`",
- self.loan_path_to_string(lp))
- .span_note(assign.span, "prior assignment occurs here")
- .emit();
+ self.loan_path_to_string(lp));
+ err.span_label(span, &format!("re-assignment of immutable variable"));
+ if span != assign.span {
+ err.span_label(assign.span, &format!("first assignment to `{}`",
+ self.loan_path_to_string(lp)));
+ }
+ err.emit();
}
pub fn span_err(&self, s: Span, m: &str) {
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:
-```compile_fail
+```compile_fail,E0373
fn foo() -> Box<Fn(u32) -> u32> {
let x = 0u32;
Box::new(|y| x + y)
Another situation where this might be encountered is when spawning threads:
-```compile_fail
+```compile_fail,E0373
fn foo() {
let x = 0u32;
let y = 1u32;
E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:
-```compile_fail
+```compile_fail,E0381
fn main() {
let x: i32;
let y = x; // error, use of possibly uninitialized variable
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:
-```compile_fail
+```compile_fail,E0382
struct MyStruct { s: u32 }
fn main() {
This error occurs when an attempt is made to reassign an immutable variable.
For example:
-```compile_fail
-fn main(){
+```compile_fail,E0384
+fn main() {
let x = 3;
x = 5; // error, reassignment of immutable variable
}
`mut` after the keyword `let` when declaring the variable. For example:
```
-fn main(){
+fn main() {
let mut x = 3;
x = 5;
}
For example, this can happen when storing a `&mut` inside an immutable `Box`:
-```compile_fail
+```compile_fail,E0386
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:
-```compile_fail
+```compile_fail,E0387
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }
https://doc.rust-lang.org/std/cell/
"##,
+E0388: r##"
+A mutable borrow was attempted in a static location.
+
+Erroneous code example:
+
+```compile_fail,E0388
+static X: i32 = 1;
+
+static STATIC_REF: &'static mut i32 = &mut X;
+// error: cannot borrow data mutably in a static location
+
+const CONST_REF: &'static mut i32 = &mut X;
+// error: cannot borrow data mutably in a static location
+```
+
+To fix this error, you have to use constant borrow:
+
+```
+static X: i32 = 1;
+
+static STATIC_REF: &'static i32 = &X;
+```
+"##,
+
E0389: r##"
An attempt was made to mutate data using a non-mutable reference. This
commonly occurs when attempting to assign to a non-mutable reference of a
Example of erroneous code:
-```compile_fail
+```compile_fail,E0389
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:
-```compile_fail
+```compile_fail,E0499
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
Example of erroneous code:
-```compile_fail
+```compile_fail,E0501
fn inside_closure(x: &mut i32) {
// Actions which require unique access
}
Example of erroneous code:
-```compile_fail
+```compile_fail,E0502
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
let ref y = a; // a is borrowed as immutable.
Example of erroneous code:
-```compile_fail
+```compile_fail,E0503
fn main() {
let mut value = 3;
// Create a mutable borrow of `value`. This borrow
Example of erroneous code:
-```compile_fail
+```compile_fail,E0504
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
use std::thread;
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
"##,
+E0505: r##"
+A value was moved out while it was still borrowed.
+
+Erroneous code example:
+
+```compile_fail,E0505
+struct Value {}
+
+fn eat(val: Value) {}
+
+fn main() {
+ let x = Value{};
+ {
+ let _ref_to_val: &Value = &x;
+ eat(x);
+ }
+}
+```
+
+Here, the function `eat` takes the ownership of `x`. However,
+`x` cannot be moved because it was borrowed to `_ref_to_val`.
+To fix that you can do few different things:
+
+* Try to avoid moving the variable.
+* Release borrow before move.
+* Implement the `Copy` trait on the type.
+
+Examples:
+
+```
+struct Value {}
+
+fn eat(val: &Value) {}
+
+fn main() {
+ let x = Value{};
+ {
+ let _ref_to_val: &Value = &x;
+ eat(&x); // pass by reference, if it's possible
+ }
+}
+```
+
+Or:
+
+```
+struct Value {}
+
+fn eat(val: Value) {}
+
+fn main() {
+ let x = Value{};
+ {
+ let _ref_to_val: &Value = &x;
+ }
+ eat(x); // release borrow and then move it.
+}
+```
+
+Or:
+
+```
+#[derive(Clone, Copy)] // implement Copy trait
+struct Value {}
+
+fn eat(val: Value) {}
+
+fn main() {
+ let x = Value{};
+ {
+ let _ref_to_val: &Value = &x;
+ eat(x); // it will be copied here.
+ }
+}
+```
+
+You can find more information about borrowing in the rust-book:
+http://doc.rust-lang.org/stable/book/references-and-borrowing.html
+"##,
+
E0506: r##"
This error occurs when an attempt is made to assign to a borrowed value.
Example of erroneous code:
-```compile_fail
+```compile_fail,E0506
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
struct FancyNum {
- num: u8
+ num: u8,
}
fn main() {
```
"##,
-E0505: r##"
-A value was moved out while it was still borrowed.
-Erroneous code example:
-
-```compile_fail
-struct Value {}
-
-fn eat(val: Value) {}
-
-fn main() {
- let x = Value{};
- {
- let _ref_to_val: &Value = &x;
- eat(x);
- }
-}
-```
-
-Here, the function `eat` takes the ownership of `x`. However,
-`x` cannot be moved because it was borrowed to `_ref_to_val`.
-To fix that you can do few different things:
-
-* Try to avoid moving the variable.
-* Release borrow before move.
-* Implement the `Copy` trait on the type.
-
-Examples:
-
-```
-struct Value {}
-
-fn eat(val: &Value) {}
-
-fn main() {
- let x = Value{};
- {
- let _ref_to_val: &Value = &x;
- eat(&x); // pass by reference, if it's possible
- }
-}
-```
-
-Or:
-
-```
-struct Value {}
-
-fn eat(val: Value) {}
-
-fn main() {
- let x = Value{};
- {
- let _ref_to_val: &Value = &x;
- }
- eat(x); // release borrow and then move it.
-}
-```
-
-Or:
-
-```
-#[derive(Clone, Copy)] // implement Copy trait
-struct Value {}
-
-fn eat(val: Value) {}
-
-fn main() {
- let x = Value{};
- {
- let _ref_to_val: &Value = &x;
- eat(x); // it will be copied here.
- }
-}
-```
-
-You can find more information about borrowing in the rust-book:
-http://doc.rust-lang.org/stable/book/references-and-borrowing.html
-"##,
-
E0507: r##"
You tried to move out of a value which was borrowed. Erroneous code example:
-```compile_fail
+```compile_fail,E0507
use std::cell::RefCell;
struct TheDarkKnight;
Example of erroneous code:
-```compile_fail
+```compile_fail,E0508
struct NonCopy;
fn main() {
Example of erroneous code:
-```compile_fail
+```compile_fail,E0509
struct FancyNum {
num: usize
}
register_diagnostics! {
E0385, // {} in an aliasable location
- E0388, // {} in a static location
E0524, // two closures require unique access to `..` at the same time
}
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization::{cmt};
use rustc::hir::pat_util::*;
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::ty::*;
use rustc::ty;
use std::cmp::Ordering;
.flat_map(|arm| &arm.0)
.map(|pat| vec![wrap_pat(cx, &pat)])
.collect();
- let match_span = Span {
- lo: ex.span.lo,
- hi: scrut.span.hi,
- expn_id: ex.span.expn_id
- };
- check_exhaustive(cx, match_span, &matrix, source);
+ check_exhaustive(cx, scrut.span, &matrix, source);
},
_ => ()
}
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
if sub.map_or(false, |p| pat_contains_bindings(&p)) {
- span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings");
+ struct_span_err!(cx.tcx.sess, p.span, E0007,
+ "cannot bind by-move with sub-bindings")
+ .span_label(p.span, &format!("binds an already bound by-move value by moving it"))
+ .emit();
} else if has_guard {
- span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
+ struct_span_err!(cx.tcx.sess, p.span, E0008,
+ "cannot bind by-move into a pattern guard")
+ .span_label(p.span, &format!("moves value into pattern guard"))
+ .emit();
} else if by_ref_span.is_some() {
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009,
"cannot bind by-move and by-ref in the same pattern");
let pat_ty = cx.tcx.node_id_to_type(p.id);
//FIXME: (@jroesch) this code should be floated up as well
cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
- ProjectionMode::AnyFinal).enter(|infcx| {
+ Reveal::NotSpecializable).enter(|infcx| {
if infcx.type_moves_by_default(pat_ty, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
guard: &hir::Expr) {
cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
- ProjectionMode::AnyFinal).enter(|infcx| {
+ Reveal::NotSpecializable).enter(|infcx| {
let mut checker = MutationChecker {
cx: cx,
};
use rustc::hir::pat_util::def_to_path;
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::lint;
trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
- tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
};
// NOTE: this code does not currently account for specialization, but when
- // it does so, it should hook into the ProjectionMode to determine when the
+ // it does so, it should hook into the Reveal to determine when the
// constant should resolve; this will also require plumbing through to this
- // function whether we are in "trans mode" to pick the right ProjectionMode
+ // function whether we are in "trans mode" to pick the right Reveal
// when constructing the inference context above.
match selection {
traits::VtableImpl(ref impl_data) => {
cfg,
&mut loader);
syntax_ext::register_builtins(&mut ecx.syntax_env);
- let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
- syntax_exts,
- krate);
+ let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
- *sess.available_macros.borrow_mut() = macro_names;
+ *sess.available_macros.borrow_mut() = ecx.syntax_env.names;
ret
});
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_trans::back::link;
+use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
}
}
}
+ PrintRequest::TargetCPUs => {
+ let tm = create_target_machine(sess);
+ unsafe { llvm::LLVMRustPrintTargetCPUs(tm); }
+ }
+ PrintRequest::TargetFeatures => {
+ let tm = create_target_machine(sess);
+ unsafe { llvm::LLVMRustPrintTargetFeatures(tm); }
+ }
+ PrintRequest::RelocationModels => {
+ println!("Available relocation models:");
+ for &(name, _) in RELOC_MODEL_ARGS.iter() {
+ println!(" {}", name);
+ }
+ println!("");
+ }
+ PrintRequest::CodeModels => {
+ println!("Available code models:");
+ for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){
+ println!(" {}", name);
+ }
+ println!("");
+ }
}
}
return Compilation::Stop;
use rustc::middle::stability;
use rustc::ty::subst;
use rustc::ty::subst::Subst;
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
use rustc_metadata::cstore::CStore;
index,
"test_crate",
|tcx| {
- tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::adjustment;
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::hir::map as hir_map;
use util::nodemap::{NodeSet};
use lint::{Level, LateContext, LintContext, LintArray, Lint};
let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
let param_env = Some(ty::ParameterEnvironment::for_item(tcx, node_id));
- tcx.infer_ctxt(None, param_env, ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, param_env, Reveal::NotSpecializable).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.
store.register_future_incompatible(sess, vec![
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
- reference: "the explanation for E0446 (`--explain E0446`)",
+ reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
},
FutureIncompatibleInfo {
id: LintId::of(INACCESSIBLE_EXTERN_CRATE),
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{Layout, Primitive};
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
}
ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
- ty::TyClosure(..) | ty::TyProjection(..) |
+ ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) |
ty::TyFnDef(..) => {
bug!("Unexpected type in foreign function")
}
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
let t = cx.tcx.node_id_to_type(it.id);
- let layout = cx.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
cfg.flag(&flag);
}
+ if env::var_os("LLVM_RUSTLLVM").is_some() {
+ cfg.flag("-DLLVM_RUSTLLVM");
+ }
+
cfg.file("../rustllvm/PassWrapper.cpp")
.file("../rustllvm/RustWrapper.cpp")
.file("../rustllvm/ArchiveWrapper.cpp")
pub fn LLVMRustHasFeature(T: TargetMachineRef,
s: *const c_char) -> bool;
+ pub fn LLVMRustPrintTargetCPUs(T: TargetMachineRef);
+ pub fn LLVMRustPrintTargetFeatures(T: TargetMachineRef);
+
pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
CPU: *const c_char,
Features: *const c_char,
StructCtor,
Initializer,
Binding,
+ ImplTrait,
}
pub fn simplify_def_key(key: hir_map::DefKey) -> DefKey {
hir_map::DefPathData::StructCtor => DefPathData::StructCtor,
hir_map::DefPathData::Initializer => DefPathData::Initializer,
hir_map::DefPathData::Binding(_) => DefPathData::Binding,
+ hir_map::DefPathData::ImplTrait => DefPathData::ImplTrait,
}
}
DefPathData::StructCtor => hir_map::DefPathData::StructCtor,
DefPathData::Initializer => hir_map::DefPathData::Initializer,
DefPathData::Binding => hir_map::DefPathData::Binding(name.unwrap()),
+ DefPathData::ImplTrait => hir_map::DefPathData::ImplTrait,
}
}
intravisit::walk_foreign_item(self, ni);
encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
}
+ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+ intravisit::walk_ty(self, ty);
+
+ if let hir::TyImplTrait(_) = ty.node {
+ let rbml_w = &mut *self.rbml_w_for_visit_item;
+ let def_id = self.ecx.tcx.map.local_def_id(ty.id);
+ let _task = self.index.record(def_id, rbml_w);
+ rbml_w.start_tag(tag_items_data_item);
+ encode_def_id_and_key(self.ecx, rbml_w, def_id);
+ encode_family(rbml_w, 'y');
+ encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
+ rbml_w.end_tag();
+ }
+ }
}
fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
let name = token::intern(&self.parse_str(']'));
return tcx.mk_projection(trait_ref, name);
}
+ 'A' => {
+ assert_eq!(self.next(), '[');
+ let def_id = self.parse_def();
+ let substs = self.parse_substs();
+ assert_eq!(self.next(), ']');
+ return self.tcx.mk_anon(def_id, self.tcx.mk_substs(substs));
+ }
'e' => {
return tcx.types.err;
}
enc_trait_ref(w, cx, data.trait_ref);
write!(w, "{}]", data.item_name);
}
+ ty::TyAnon(def_id, substs) => {
+ write!(w, "A[{}|", (cx.ds)(cx.tcx, def_id));
+ enc_substs(w, cx, substs);
+ write!(w, "]");
+ }
ty::TyError => {
write!(w, "e");
}
use rustc::mir::mir_map::MirMap;
use rustc::infer::InferCtxtBuilder;
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::hir;
let def_id = self.tcx.map.local_def_id(src.item_id());
CxBuilder {
src: src,
- infcx: self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal),
+ infcx: self.tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable),
def_id: def_id,
map: self.map
}
let mut curr: usize = 0;
for bb in mir.basic_blocks_mut() {
- let idx = match get_aggregate_statement(curr, &bb.statements) {
+ let idx = match get_aggregate_statement_index(curr, &bb.statements) {
Some(idx) => idx,
None => continue,
};
let src_info = bb.statements[idx].source_info;
let suffix_stmts = bb.statements.split_off(idx+1);
let orig_stmt = bb.statements.pop().unwrap();
- let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind;
+ let (lhs, rhs) = match orig_stmt.kind {
+ StatementKind::Assign(ref lhs, ref rhs) => (lhs, rhs),
+ StatementKind::SetDiscriminant{ .. } =>
+ span_bug!(src_info.span, "expected aggregate, not {:?}", orig_stmt.kind),
+ };
let (agg_kind, operands) = match rhs {
&Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
_ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
let ty = variant_def.fields[i].ty(tcx, substs);
let rhs = Rvalue::Use(op.clone());
- // since we don't handle enums, we don't need a cast
- let lhs_cast = lhs.clone();
-
- // FIXME we cannot deaggregate enums issue: #35186
+ let lhs_cast = if adt_def.variants.len() > 1 {
+ Lvalue::Projection(Box::new(LvalueProjection {
+ base: lhs.clone(),
+ elem: ProjectionElem::Downcast(adt_def, variant),
+ }))
+ } else {
+ lhs.clone()
+ };
let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection {
base: lhs_cast,
debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
bb.statements.push(new_statement);
}
+
+ // if the aggregate was an enum, we need to set the discriminant
+ if adt_def.variants.len() > 1 {
+ let set_discriminant = Statement {
+ kind: StatementKind::SetDiscriminant {
+ lvalue: lhs.clone(),
+ variant_index: variant,
+ },
+ source_info: src_info,
+ };
+ bb.statements.push(set_discriminant);
+ };
+
curr = bb.statements.len();
bb.statements.extend(suffix_stmts);
}
}
}
-fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize,
+fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
statements: &Vec<Statement<'tcx>>)
-> Option<usize> {
- for i in curr..statements.len() {
+ for i in start..statements.len() {
let ref statement = statements[i];
- let StatementKind::Assign(_, ref rhs) = statement.kind;
+ let rhs = match statement.kind {
+ StatementKind::Assign(_, ref rhs) => rhs,
+ StatementKind::SetDiscriminant{ .. } => continue,
+ };
let (kind, operands) = match rhs {
&Rvalue::Aggregate(ref kind, ref operands) => (kind, operands),
_ => continue,
&AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant),
_ => continue,
};
- if operands.len() == 0 || adt_def.variants.len() > 1 {
+ if operands.len() == 0 {
// don't deaggregate ()
- // don't deaggregate enums ... for now
continue;
}
debug!("getting variant {:?}", variant);
let (mut rvalue, mut call) = (None, None);
let source_info = if stmt_idx < no_stmts {
let statement = &mut self.source[bb].statements[stmt_idx];
- let StatementKind::Assign(_, ref mut rhs) = statement.kind;
+ let mut rhs = match statement.kind {
+ StatementKind::Assign(_, ref mut rhs) => rhs,
+ StatementKind::SetDiscriminant{ .. } =>
+ span_bug!(statement.source_info.span,
+ "cannot promote SetDiscriminant {:?}",
+ statement),
+ };
if self.keep_original {
rvalue = Some(rhs.clone());
} else {
});
let mut rvalue = match candidate {
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
- match self.source[bb].statements[stmt_idx].kind {
+ let ref mut statement = self.source[bb].statements[stmt_idx];
+ match statement.kind {
StatementKind::Assign(_, ref mut rvalue) => {
mem::replace(rvalue, Rvalue::Use(new_operand))
}
+ StatementKind::SetDiscriminant{ .. } => {
+ span_bug!(statement.source_info.span,
+ "cannot promote SetDiscriminant {:?}",
+ statement);
+ }
}
}
Candidate::ShuffleIndices(bb) => {
let (span, ty) = match candidate {
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
let statement = &mir[bb].statements[stmt_idx];
- let StatementKind::Assign(ref dest, _) = statement.kind;
+ let dest = match statement.kind {
+ StatementKind::Assign(ref dest, _) => dest,
+ StatementKind::SetDiscriminant{ .. } =>
+ panic!("cannot promote SetDiscriminant"),
+ };
if let Lvalue::Temp(index) = *dest {
if temps[index] == TempState::PromotedOut {
// Already promoted.
continue;
}
}
- (statement.source_info.span, mir.lvalue_ty(tcx, dest).to_ty(tcx))
+ (statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx))
}
Candidate::ShuffleIndices(bb) => {
let terminator = mir[bb].terminator();
let ty = match terminator.kind {
TerminatorKind::Call { ref args, .. } => {
- mir.operand_ty(tcx, &args[2])
+ args[2].ty(mir, tcx)
}
_ => {
span_bug!(terminator.source_info.span,
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
use rustc::hir::map::blocks::FnLikeNode;
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::ty::cast::CastTy;
use rustc::mir::repr::*;
this.add(Qualif::STATIC);
}
- let base_ty = this.mir.lvalue_ty(this.tcx, &proj.base)
- .to_ty(this.tcx);
+ let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
if let ty::TyRawPtr(_) = base_ty.sty {
this.add(Qualif::NOT_CONST);
if this.mode != Mode::Fn {
"cannot refer to the interior of another \
static, use a constant instead");
}
- let ty = this.mir.lvalue_ty(this.tcx, lvalue)
- .to_ty(this.tcx);
+ let ty = lvalue.ty(this.mir, this.tcx).to_ty(this.tcx);
this.qualif.restrict(ty, this.tcx, &this.param_env);
}
self.add(Qualif::STATIC_REF);
}
- let ty = self.mir.lvalue_ty(self.tcx, lvalue).to_ty(self.tcx);
+ let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
if kind == BorrowKind::Mut {
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
if !allow {
self.add(Qualif::NOT_CONST);
if self.mode != Mode::Fn {
- span_err!(self.tcx.sess, self.span, E0017,
- "references in {}s may only refer \
- to immutable values", self.mode);
+ struct_span_err!(self.tcx.sess, self.span, E0017,
+ "references in {}s may only refer \
+ to immutable values", self.mode)
+ .span_label(self.span, &format!("{}s require immutable values",
+ self.mode))
+ .emit();
}
}
} else {
}
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
- let operand_ty = self.mir.operand_ty(self.tcx, operand);
+ let operand_ty = operand.ty(self.mir, self.tcx);
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
match (cast_in, cast_out) {
}
Rvalue::BinaryOp(op, ref lhs, _) => {
- if let ty::TyRawPtr(_) = self.mir.operand_ty(self.tcx, lhs).sty {
+ if let ty::TyRawPtr(_) = lhs.ty(self.mir, self.tcx).sty {
assert!(op == BinOp::Eq || op == BinOp::Ne ||
op == BinOp::Le || op == BinOp::Lt ||
op == BinOp::Ge || op == BinOp::Gt);
}
if Some(def.did) == self.tcx.lang_items.unsafe_cell_type() {
- let ty = self.mir.rvalue_ty(self.tcx, rvalue).unwrap();
+ let ty = rvalue.ty(self.mir, self.tcx).unwrap();
self.add_type(ty);
assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
// Even if the value inside may not need dropping,
if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
self.visit_operand(func);
- let fn_ty = self.mir.operand_ty(self.tcx, func);
+ let fn_ty = func.ty(self.mir, self.tcx);
let (is_shuffle, is_const_fn) = match fn_ty.sty {
ty::TyFnDef(def_id, _, f) => {
(f.abi == Abi::PlatformIntrinsic &&
} else {
// Be conservative about the returned value of a const fn.
let tcx = self.tcx;
- let ty = self.mir.lvalue_ty(tcx, dest).to_ty(tcx);
+ let ty = dest.ty(self.mir, tcx).to_ty(tcx);
self.qualif = Qualif::empty();
self.add_type(ty);
// Statics must be Sync.
if mode == Mode::Static {
let ty = mir.return_ty.unwrap();
- tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
#![allow(unreachable_code)]
use rustc::infer::{self, InferCtxt, InferOk};
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::fold::TypeFoldable;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
use rustc::mir::repr::*;
use rustc::mir::tcx::LvalueTy;
use rustc::mir::transform::{MirPass, MirSource, Pass};
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
self.super_rvalue(rvalue);
- if let Some(ty) = self.mir.rvalue_ty(self.tcx(), rvalue) {
+ if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
self.sanitize_type(rvalue, ty);
}
}
}
ProjectionElem::Index(ref i) => {
self.visit_operand(i);
- let index_ty = self.mir.operand_ty(tcx, i);
+ let index_ty = i.ty(self.mir, tcx);
if index_ty != tcx.types.usize {
LvalueTy::Ty {
ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
let tcx = self.tcx();
match stmt.kind {
StatementKind::Assign(ref lv, ref rv) => {
- let lv_ty = mir.lvalue_ty(tcx, lv).to_ty(tcx);
- let rv_ty = mir.rvalue_ty(tcx, rv);
+ let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
+ let rv_ty = rv.ty(mir, tcx);
if let Some(rv_ty) = rv_ty {
if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
lv_ty, rv_ty, terr);
}
- }
-
// FIXME: rvalue with undeterminable type - e.g. inline
// asm.
+ }
+ }
+ StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
+ let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
+ let adt = match lvalue_type.sty {
+ TypeVariants::TyEnum(adt, _) => adt,
+ _ => {
+ span_bug!(stmt.source_info.span,
+ "bad set discriminant ({:?} = {:?}): lhs is not an enum",
+ lvalue,
+ variant_index);
+ }
+ };
+ if variant_index >= adt.variants.len() {
+ span_bug!(stmt.source_info.span,
+ "bad set discriminant ({:?} = {:?}): value of of range",
+ lvalue,
+ variant_index);
+ };
}
}
}
ref value,
..
} => {
- let lv_ty = mir.lvalue_ty(tcx, location).to_ty(tcx);
- let rv_ty = mir.operand_ty(tcx, value);
+ let lv_ty = location.ty(mir, tcx).to_ty(tcx);
+ let rv_ty = value.ty(mir, tcx);
if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
lv_ty, rv_ty, terr);
}
TerminatorKind::If { ref cond, .. } => {
- let cond_ty = mir.operand_ty(tcx, cond);
+ let cond_ty = cond.ty(mir, tcx);
match cond_ty.sty {
ty::TyBool => {}
_ => {
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
- let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
+ let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) {
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
switch_ty, discr_ty, terr);
// FIXME: check the values
}
TerminatorKind::Switch { ref discr, adt_def, ref targets } => {
- let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
+ let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
match discr_ty.sty {
ty::TyEnum(def, _)
if def == adt_def && adt_def.variants.len() == targets.len()
}
}
TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
- let func_ty = mir.operand_ty(tcx, func);
+ let func_ty = func.ty(mir, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let func_ty = match func_ty.sty {
ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty,
}
}
TerminatorKind::Assert { ref cond, ref msg, .. } => {
- let cond_ty = mir.operand_ty(tcx, cond);
+ let cond_ty = cond.ty(mir, tcx);
if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
- if mir.operand_ty(tcx, len) != tcx.types.usize {
+ if len.ty(mir, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
- if mir.operand_ty(tcx, index) != tcx.types.usize {
+ if index.ty(mir, tcx) != tcx.types.usize {
span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
}
}
span_mirbug!(self, term, "call to diverging function {:?} with dest", sig);
}
(&Some((ref dest, _)), ty::FnConverging(ty)) => {
- let dest_ty = mir.lvalue_ty(tcx, dest).to_ty(tcx);
+ let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_types(self.last_span, ty, dest_ty) {
span_mirbug!(self, term,
"call dest mismatch ({:?} <- {:?}): {:?}",
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
- let op_arg_ty = mir.operand_ty(self.tcx(), op_arg);
+ let op_arg_ty = op_arg.ty(mir, self.tcx());
if let Err(terr) = self.sub_types(self.last_span, op_arg_ty, fn_arg) {
span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
n, fn_arg, op_arg_ty, terr);
return;
}
- let arg_ty = match mir.operand_ty(self.tcx(), &args[0]).sty {
+ let arg_ty = match args[0].ty(mir, self.tcx()).sty {
ty::TyRawPtr(mt) => mt.ty,
ty::TyBox(ty) => ty,
_ => {
return;
}
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
- tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
E0130,
"patterns aren't allowed in foreign function \
declarations");
+ err.span_label(span, &format!("pattern not allowed in foreign function"));
if is_recent {
err.span_note(span,
"this is a recent error, see issue #35203 for more details");
visit::walk_foreign_item(self, fi)
}
- fn visit_variant_data(&mut self,
- vdata: &VariantData,
- _: Ident,
- _: &Generics,
- _: NodeId,
- span: Span) {
- if vdata.fields().is_empty() {
- if vdata.is_tuple() {
- self.err_handler()
- .struct_span_err(span,
- "empty tuple structs and enum variants are not allowed, use \
- unit structs and enum variants instead")
- .span_help(span,
- "remove trailing `()` to make a unit struct or unit enum variant")
- .emit();
- }
- }
-
- visit::walk_struct_def(self, vdata)
- }
-
fn visit_vis(&mut self, vis: &Visibility) {
match *vis {
Visibility::Restricted { ref path, .. } => {
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
};
self.tcx
- .infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal)
+ .infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
.enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
}
match self.cx {
Loop => {}
Closure => {
- span_err!(self.sess, span, E0267, "`{}` inside of a closure", name);
+ struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
+ .span_label(span, &format!("cannot break inside of a closure"))
+ .emit();
}
Normal => {
- span_err!(self.sess, span, E0268, "`{}` outside of loop", name);
+ struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
+ .span_label(span, &format!("cannot break outside of a loop"))
+ .emit();
}
}
}
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::ty::{self, TyCtxt, ParameterEnvironment};
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::hir;
use rustc::hir::intravisit;
// FIXME (@jroesch) change this to be an inference context
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
self.tcx.infer_ctxt(None, Some(param_env.clone()),
- ProjectionMode::AnyFinal).enter(|infcx| {
+ Reveal::NotSpecializable).enter(|infcx| {
let mut delegate = RvalueContextDelegate {
tcx: infcx.tcx,
param_env: ¶m_env
examples:
```compile_fail,E0445
-#![deny(private_in_public)]
-
trait Foo {
fn dummy(&self) { }
}
A private type was used in a public type signature. Erroneous code example:
```compile_fail,E0446
-#![deny(private_in_public)]
-
mod Foo {
struct Bar(u32);
// Return the visibility of the type alias's least visible component type when substituted
fn substituted_alias_visibility(&self, item: &hir::Item, path: &hir::Path)
-> Option<ty::Visibility> {
- // We substitute type aliases only when determining impl publicity
- // FIXME: This will probably change and all type aliases will be substituted,
- // requires an amendment to RFC 136.
- if self.required_visibility != ty::Visibility::PrivateExternal {
- return None;
- }
// Type alias is considered public if the aliased type is
// public, even if the type alias itself is private. So, something
// like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
if let hir::ItemTy(ref ty, ref generics) = item.node {
- let mut check = SearchInterfaceForPrivateItemsVisitor {
- min_visibility: ty::Visibility::Public, ..*self
- };
+ let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx,
+ self.old_error_set);
check.visit_ty(ty);
// If a private type alias with default type parameters is used in public
// interface we must ensure, that the defaults are public if they are actually used.
self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
node_id,
ty.span,
- format!("private type in public interface"));
+ format!("private type in public \
+ interface (error E0446)"));
}
}
}
struct_span_err!(resolver.session, span, E0432, "{}", msg)
}
ResolutionError::FailedToResolve(msg) => {
- struct_span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg)
+ let mut err = struct_span_err!(resolver.session, span, E0433,
+ "failed to resolve. {}", msg);
+ err.span_label(span, &msg);
+ err
}
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
struct_span_err!(resolver.session,
let def_id = self.definitions.local_def_id(type_parameter.id);
let def = Def::TyParam(space, index as u32, def_id, name);
function_type_rib.bindings.insert(ast::Ident::with_empty_ctxt(name), def);
+ self.record_def(type_parameter.id, PathResolution::new(def));
}
self.type_ribs.push(function_type_rib);
}
}
Success(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
- span_err!(self.session, directive.span, E0253, "{}", &msg);
+ struct_span_err!(self.session, directive.span, E0253, "{}", &msg)
+ .span_label(directive.span, &format!("cannot be imported directly"))
+ .emit();
// Do not import this illegal binding. Import a dummy binding and pretend
// everything is fine
self.import_dummy_binding(module, directive);
use Disr;
use value::Value;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use session::config::NoDebugInfo;
use util::common::indenter;
use util::nodemap::FnvHashMap;
field: field,
reassigned: false
};
- bcx.tcx().normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ bcx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
visitor.walk_expr(body);
});
use std::thread;
use libc::{c_uint, c_void};
+pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 4] = [
+ ("pic", llvm::RelocMode::PIC),
+ ("static", llvm::RelocMode::Static),
+ ("default", llvm::RelocMode::Default),
+ ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic),
+];
+
+pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
+ ("default", llvm::CodeModel::Default),
+ ("small", llvm::CodeModel::Small),
+ ("kernel", llvm::CodeModel::Kernel),
+ ("medium", llvm::CodeModel::Medium),
+ ("large", llvm::CodeModel::Large),
+];
+
pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! {
match llvm::last_error() {
Some(err) => panic!(handler.fatal(&format!("{}: {}", msg, err))),
None => &sess.target.target.options.code_model[..],
};
- let code_model = match code_model_arg {
- "default" => llvm::CodeModel::Default,
- "small" => llvm::CodeModel::Small,
- "kernel" => llvm::CodeModel::Kernel,
- "medium" => llvm::CodeModel::Medium,
- "large" => llvm::CodeModel::Large,
+ let code_model = match CODE_GEN_MODEL_ARGS.iter().find(
+ |&&arg| arg.0 == code_model_arg) {
+ Some(x) => x.1,
_ => {
sess.err(&format!("{:?} is not a valid code model",
sess.opts
use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor;
+use rustc_const_eval as const_eval;
+
use syntax::abi::Abi;
use errors;
use syntax_pos::DUMMY_SP;
-use syntax::ast::NodeId;
use base::custom_coerce_unsize_info;
use context::SharedCrateContext;
use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
let target_ty = monomorphize::apply_param_substs(self.scx.tcx(),
self.param_substs,
&target_ty);
- let source_ty = self.mir.operand_ty(self.scx.tcx(), operand);
+ let source_ty = operand.ty(self.mir, self.scx.tcx());
let source_ty = monomorphize::apply_param_substs(self.scx.tcx(),
self.param_substs,
&source_ty);
debug!("visiting lvalue {:?}", *lvalue);
if let mir_visit::LvalueContext::Drop = context {
- let ty = self.mir.lvalue_ty(self.scx.tcx(), lvalue)
- .to_ty(self.scx.tcx());
+ let ty = lvalue.ty(self.mir, self.scx.tcx())
+ .to_ty(self.scx.tcx());
let ty = monomorphize::apply_param_substs(self.scx.tcx(),
self.param_substs,
debug!("visiting operand {:?}", *operand);
let callee = match *operand {
- mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
- sty: ty::TyFnDef(def_id, substs, _), ..
- }, .. }) => Some((def_id, substs)),
+ mir::Operand::Constant(ref constant) => {
+ if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty {
+ // This is something that can act as a callee, proceed
+ Some((def_id, substs))
+ } else {
+ // This is not a callee, but we still have to look for
+ // references to `const` items
+ if let mir::Literal::Item { def_id, substs } = constant.literal {
+ let tcx = self.scx.tcx();
+ let substs = monomorphize::apply_param_substs(tcx,
+ self.param_substs,
+ &substs);
+
+ // If the constant referred to here is an associated
+ // item of a trait, we need to resolve it to the actual
+ // constant in the corresponding impl. Luckily
+ // const_eval::lookup_const_by_id() does that for us.
+ if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
+ def_id,
+ Some(substs)) {
+ // The hir::Expr we get here is the initializer of
+ // the constant, what we really want is the item
+ // DefId.
+ let const_node_id = tcx.map.get_parent(expr.id);
+ let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
+ tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
+ } else {
+ tcx.map.local_def_id(const_node_id)
+ };
+
+ collect_const_item_neighbours(self.scx,
+ def_id,
+ substs,
+ self.output);
+ }
+ }
+
+ None
+ }
+ }
_ => None
};
match constant.ty.sty {
ty::TyFnDef(def_id, _, bare_fn_ty)
if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => {
- let operand_ty = self.mir.operand_ty(tcx, &args[0]);
+ let operand_ty = args[0].ty(self.mir, tcx);
if let ty::TyRawPtr(mt) = operand_ty.sty {
let operand_ty = monomorphize::apply_param_substs(tcx,
self.param_substs,
ty::TyProjection(_) |
ty::TyParam(_) |
ty::TyInfer(_) |
+ ty::TyAnon(..) |
ty::TyError => {
bug!("encountered unexpected type");
}
self.output.push(TransItem::Static(item.id));
}
hir::ItemConst(..) => {
- debug!("RootCollector: ItemConst({})",
- def_id_to_string(self.scx.tcx(),
- self.scx.tcx().map.local_def_id(item.id)));
- add_roots_for_const_item(self.scx, item.id, self.output);
+ // const items only generate translation items if they are
+ // actually used somewhere. Just declaring them is insufficient.
}
hir::ItemFn(_, _, _, _, ref generics, _) => {
if !generics.is_type_parameterized() {
// There are no translation items for constants themselves but their
// initializers might still contain something that produces translation items,
// such as cast that introduce a new vtable.
-fn add_roots_for_const_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- const_item_node_id: NodeId,
- output: &mut Vec<TransItem<'tcx>>)
+fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ output: &mut Vec<TransItem<'tcx>>)
{
- let def_id = scx.tcx().map.local_def_id(const_item_node_id);
-
// Scan the MIR in order to find function calls, closures, and
// drop-glue
let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id),
|| format!("Could not find MIR for const: {:?}", def_id));
- let empty_substs = scx.empty_substs_for_def_id(def_id);
let visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: output,
- param_substs: empty_substs
+ param_substs: substs
};
visit_mir_and_promoted(visitor, &mir);
use value::Value;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::Layout;
-use rustc::traits::{self, SelectionContext, ProjectionMode};
+use rustc::traits::{self, SelectionContext, Reveal};
use rustc::ty::fold::TypeFoldable;
use rustc::hir;
use util::nodemap::NodeMap;
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
-> bool {
let tcx = ccx.tcx();
- let layout = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ let layout = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
match ty.layout(&infcx) {
Ok(layout) => layout,
Err(err) => {
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
- tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
let obligation_cause = traits::ObligationCause::misc(span,
debug!("normalize_and_test_predicates(predicates={:?})",
predicates);
- tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::dummy();
None => &sess.target.target.options.relocation_model[..],
};
- match reloc_model_arg {
- "pic" => llvm::RelocMode::PIC,
- "static" => llvm::RelocMode::Static,
- "default" => llvm::RelocMode::Default,
- "dynamic-no-pic" => llvm::RelocMode::DynamicNoPic,
+ match ::back::write::RELOC_MODEL_ARGS.iter().find(
+ |&&arg| arg.0 == reloc_model_arg) {
+ Some(x) => x.1,
_ => {
sess.err(&format!("{:?} is not a valid relocation mode",
sess.opts
.cg
- .relocation_model));
+ .code_model));
sess.abort_if_errors();
bug!();
}
ty::TyError |
ty::TyInfer(_) |
ty::TyProjection(..) |
+ ty::TyAnon(..) |
ty::TyParam(_) => {
bug!("debuginfo: Trying to create type name for \
unexpected type: {:?}", t);
match t.sty {
ty::TyBox(typ) if !type_needs_drop(tcx, typ)
&& type_is_sized(tcx, typ) => {
- tcx.normalizing_infer_ctxt(traits::ProjectionMode::Any).enter(|infcx| {
+ tcx.normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| {
let layout = t.layout(&infcx).unwrap();
if layout.size(&tcx.data_layout).bytes() == 0 {
// `Box<ZeroSizeType>` does not allocate.
use rustc::hir::def_id::DefId;
use rustc::ty::subst::{FnSpace, Subst, Substs};
use rustc::ty::subst;
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use abi::FnType;
use base::*;
use build::*;
match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
Some(node_item) => {
- let substs = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let substs = traits::translate_substs(&infcx, impl_def_id,
substs, node_item.node);
tcx.lift(&substs).unwrap_or_else(|| {
// Allow uses of projections of immediate pair fields.
if let mir::Lvalue::Projection(ref proj) = *lvalue {
if self.mir.local_index(&proj.base).is_some() {
- let ty = self.mir.lvalue_ty(self.bcx.tcx(), &proj.base);
+ let ty = proj.base.ty(self.mir, self.bcx.tcx());
+
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
if common::type_is_imm_pair(self.bcx.ccx(), ty) {
if let mir::ProjectionElem::Field(..) = proj.elem {
self.mark_as_lvalue(index);
}
LvalueContext::Drop => {
- let ty = self.mir.lvalue_ty(self.bcx.tcx(), lvalue);
+ let ty = lvalue.ty(self.mir, self.bcx.tcx());
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
// Only need the lvalue if we're actually dropping it.
}
mir::TerminatorKind::Drop { ref location, target, unwind } => {
- let ty = mir.lvalue_ty(bcx.tcx(), location).to_ty(bcx.tcx());
+ let ty = location.ty(&mir, bcx.tcx()).to_ty(bcx.tcx());
let ty = bcx.monomorphize(&ty);
// Double check for necessity to drop
let extra_args = &args[sig.inputs.len()..];
let extra_args = extra_args.iter().map(|op_arg| {
- let op_ty = self.mir.operand_ty(bcx.tcx(), op_arg);
+ let op_ty = op_arg.ty(&self.mir, bcx.tcx());
bcx.monomorphize(&op_ty)
}).collect::<Vec<_>>();
let fn_ty = callee.direct_fn_type(bcx.ccx(), &extra_args);
return ReturnDest::Nothing;
}
let dest = if let Some(index) = self.mir.local_index(dest) {
- let ret_ty = self.lvalue_ty(dest);
+ let ret_ty = self.monomorphized_lvalue_ty(dest);
match self.locals[index] {
LocalRef::Lvalue(dest) => dest,
LocalRef::Operand(None) => {
let span = statement.source_info.span;
match statement.kind {
mir::StatementKind::Assign(ref dest, ref rvalue) => {
- let ty = self.mir.lvalue_ty(tcx, dest);
+ let ty = dest.ty(self.mir, tcx);
let ty = self.monomorphize(&ty).to_ty(tcx);
match self.const_rvalue(rvalue, ty, span) {
Ok(value) => self.store(dest, value, span),
Err(err) => if failure.is_ok() { failure = Err(err); }
}
}
+ mir::StatementKind::SetDiscriminant{ .. } => {
+ span_bug!(span, "SetDiscriminant should not appear in constants?");
+ }
}
}
}
mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
- let fn_ty = self.mir.operand_ty(tcx, func);
+ let fn_ty = func.ty(self.mir, tcx);
let fn_ty = self.monomorphize(&fn_ty);
let instance = match fn_ty.sty {
ty::TyFnDef(def_id, substs, _) => {
ConstLvalue {
base: Base::Static(consts::get_static(self.ccx, def_id).val),
llextra: ptr::null_mut(),
- ty: self.mir.lvalue_ty(tcx, lvalue).to_ty(tcx)
+ ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
}
}
mir::Lvalue::Projection(ref projection) => {
let lhs = self.const_operand(lhs, span)?;
let rhs = self.const_operand(rhs, span)?;
let ty = lhs.ty;
- let binop_ty = self.mir.binop_ty(tcx, op, lhs.ty, rhs.ty);
+ let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
let (lhs, rhs) = (lhs.llval, rhs.llval);
Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
}
let lhs = self.const_operand(lhs, span)?;
let rhs = self.const_operand(rhs, span)?;
let ty = lhs.ty;
- let val_ty = self.mir.binop_ty(tcx, op, lhs.ty, rhs.ty);
+ let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
let binop_ty = tcx.mk_tup(vec![val_ty, tcx.types.bool]);
let (lhs, rhs) = (lhs.llval, rhs.llval);
assert!(!ty.is_fp());
mir::Lvalue::Arg(_) |
mir::Lvalue::ReturnPointer => bug!(), // handled above
mir::Lvalue::Static(def_id) => {
- let const_ty = self.lvalue_ty(lvalue);
+ let const_ty = self.monomorphized_lvalue_ty(lvalue);
LvalueRef::new_sized(consts::get_static(ccx, def_id).val,
LvalueTy::from_ty(const_ty))
},
ty::TyArray(..) => {
// must cast the lvalue pointer type to the new
// array type (*[%_; new_len]).
- let base_ty = self.lvalue_ty(lvalue);
+ let base_ty = self.monomorphized_lvalue_ty(lvalue);
let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
let llbase = bcx.pointercast(llbase, llbasety);
(llbase, ptr::null_mut())
match self.locals[index] {
LocalRef::Lvalue(lvalue) => f(self, lvalue),
LocalRef::Operand(None) => {
- let lvalue_ty = self.lvalue_ty(lvalue);
+ let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
let lvalue = LvalueRef::alloca(bcx,
lvalue_ty,
"lvalue_temp");
LocalRef::Operand(Some(_)) => {
// See comments in LocalRef::new_operand as to why
// we always have Some in a ZST LocalRef::Operand.
- let ty = self.lvalue_ty(lvalue);
+ let ty = self.monomorphized_lvalue_ty(lvalue);
if common::type_is_zero_size(bcx.ccx(), ty) {
// Pass an undef pointer as no stores can actually occur.
let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to());
}
}
- pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
+ pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
let tcx = self.fcx.ccx.tcx();
- let lvalue_ty = self.mir.lvalue_ty(tcx, lvalue);
+ let lvalue_ty = lvalue.ty(&self.mir, tcx);
self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
}
}
};
let operand = OperandRef {
val: OperandValue::Immediate(llresult),
- ty: self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty),
+ ty: op.ty(bcx.tcx(), lhs.ty, rhs.ty),
};
(bcx, operand)
}
let result = self.trans_scalar_checked_binop(&bcx, op,
lhs.immediate(), rhs.immediate(),
lhs.ty);
- let val_ty = self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty);
+ let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty);
let operand_ty = bcx.tcx().mk_tup(vec![val_ty, bcx.tcx().types.bool]);
let operand = OperandRef {
val: result,
use super::MirContext;
use super::LocalRef;
+use super::super::adt;
+use super::super::disr::Disr;
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_statement(&mut self,
bcx
}
LocalRef::Operand(Some(_)) => {
- let ty = self.lvalue_ty(lvalue);
+ let ty = self.monomorphized_lvalue_ty(lvalue);
if !common::type_is_zero_size(bcx.ccx(), ty) {
span_bug!(statement.source_info.span,
self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
}
}
+ mir::StatementKind::SetDiscriminant{ref lvalue, variant_index} => {
+ let ty = self.monomorphized_lvalue_ty(lvalue);
+ let repr = adt::represent_type(bcx.ccx(), ty);
+ let lvalue_transed = self.trans_lvalue(&bcx, lvalue);
+ bcx.with_block(|bcx|
+ adt::trans_set_discr(bcx,
+ &repr,
+ lvalue_transed.llval,
+ Disr::from(variant_index))
+ );
+ bcx
+ }
}
}
}
ty::TyError |
ty::TyInfer(_) |
ty::TyProjection(..) |
- ty::TyParam(_) => {
+ ty::TyParam(_) |
+ ty::TyAnon(..) => {
bug!("debuginfo: Trying to create type name for \
unexpected type: {:?}", t);
}
use adt;
use common::*;
use machine;
-use rustc::traits::ProjectionMode;
+use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TypeFoldable};
use type_::Type;
}
}
- ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | ty::TyError => {
+ ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
+ ty::TyAnon(..) | ty::TyError => {
bug!("fictitious type {:?} in sizing_type_of()", t)
}
ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => bug!()
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
// FIXME(eddyb) Temporary sanity check for ty::layout.
- let layout = cx.tcx().normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
t.layout(&infcx)
});
match layout {
}
}
- ty::TyInfer(..) => bug!("type_of with TyInfer"),
- ty::TyProjection(..) => bug!("type_of with TyProjection"),
- ty::TyParam(..) => bug!("type_of with ty_param"),
- ty::TyError => bug!("type_of with TyError"),
+ ty::TyInfer(..) |
+ ty::TyProjection(..) |
+ ty::TyParam(..) |
+ ty::TyAnon(..) |
+ ty::TyError => bug!("type_of with {:?}", t),
};
debug!("--> mapped t={:?} to llty={:?}", t, llty);
use middle::resolve_lifetime as rl;
use rustc::lint;
use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
+use rustc::ty::subst::VecPerParamSpace;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::wf::object_region_bounds;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
ElisionFailureInfo, ElidedLifetime};
+use rscope::{AnonTypeScope, MaybeWithAnonTypes};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::{NodeMap, FnvHashSet};
fn convert_ty_with_lifetime_elision(&self,
elided_lifetime: ElidedLifetime,
- ty: &hir::Ty)
+ ty: &hir::Ty,
+ anon_scope: Option<AnonTypeScope>)
-> Ty<'tcx>
{
match elided_lifetime {
Ok(implied_output_region) => {
let rb = ElidableRscope::new(implied_output_region);
- self.ast_ty_to_ty(&rb, ty)
+ self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty)
}
Err(param_lifetimes) => {
// All regions must be explicitly specified in the output
// if the lifetime elision rules do not apply. This saves
// the user from potentially-confusing errors.
let rb = UnelidableRscope::new(param_lifetimes);
- self.ast_ty_to_ty(&rb, ty)
+ self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty)
}
}
}
let region_substs =
self.create_region_substs(rscope, span, decl_generics, Vec::new());
- let binding_rscope = BindingRscope::new();
+ let anon_scope = rscope.anon_type_scope();
+ let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope);
let inputs =
data.inputs.iter()
.map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics,
let (output, output_span) = match data.output {
Some(ref output_ty) => {
- (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty),
+ (self.convert_ty_with_lifetime_elision(implied_output_region,
+ &output_ty,
+ anon_scope),
output_ty.span)
}
None => {
}
hir::TyBareFn(ref bf) => {
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
- let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl);
+ let anon_scope = rscope.anon_type_scope();
+ let (bare_fn_ty, _) =
+ self.ty_of_method_or_bare_fn(bf.unsafety,
+ bf.abi,
+ None,
+ &bf.decl,
+ anon_scope,
+ anon_scope);
// Find any late-bound regions declared in return type that do
// not appear in the arguments. These are not wellformed.
hir::TyPolyTraitRef(ref bounds) => {
self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
}
+ hir::TyImplTrait(ref bounds) => {
+ use collect::{compute_bounds, SizedByDefault};
+
+ // Create the anonymized type.
+ let def_id = tcx.map.local_def_id(ast_ty.id);
+ if let Some(anon_scope) = rscope.anon_type_scope() {
+ let substs = anon_scope.fresh_substs(tcx);
+ let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
+
+ // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+ let bounds = compute_bounds(self, ty, bounds,
+ SizedByDefault::Yes,
+ Some(anon_scope),
+ ast_ty.span);
+ let predicates = bounds.predicates(tcx, ty);
+ let predicates = tcx.lift_to_global(&predicates).unwrap();
+ tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
+ predicates: VecPerParamSpace::new(vec![], vec![], predicates)
+ });
+
+ ty
+ } else {
+ span_err!(tcx.sess, ast_ty.span, E0562,
+ "`impl Trait` not allowed outside of function \
+ and inherent method return types");
+ tcx.types.err
+ }
+ }
hir::TyPath(ref maybe_qself, ref path) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
let path_res = tcx.expect_resolution(ast_ty.id);
pub fn ty_of_method(&self,
sig: &hir::MethodSig,
- untransformed_self_ty: Ty<'tcx>)
+ untransformed_self_ty: Ty<'tcx>,
+ anon_scope: Option<AnonTypeScope>)
-> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
- let (bare_fn_ty, optional_explicit_self_category) =
- self.ty_of_method_or_bare_fn(sig.unsafety,
- sig.abi,
- Some(untransformed_self_ty),
- &sig.decl);
- (bare_fn_ty, optional_explicit_self_category)
+ self.ty_of_method_or_bare_fn(sig.unsafety,
+ sig.abi,
+ Some(untransformed_self_ty),
+ &sig.decl,
+ None,
+ anon_scope)
}
pub fn ty_of_bare_fn(&self,
unsafety: hir::Unsafety,
abi: abi::Abi,
- decl: &hir::FnDecl)
+ decl: &hir::FnDecl,
+ anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
- self.ty_of_method_or_bare_fn(unsafety, abi, None, decl).0
+ self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0
}
- fn ty_of_method_or_bare_fn<'a>(&self,
- unsafety: hir::Unsafety,
- abi: abi::Abi,
- opt_untransformed_self_ty: Option<Ty<'tcx>>,
- decl: &hir::FnDecl)
- -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory)
+ fn ty_of_method_or_bare_fn(&self,
+ unsafety: hir::Unsafety,
+ abi: abi::Abi,
+ opt_untransformed_self_ty: Option<Ty<'tcx>>,
+ decl: &hir::FnDecl,
+ arg_anon_scope: Option<AnonTypeScope>,
+ ret_anon_scope: Option<AnonTypeScope>)
+ -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory)
{
debug!("ty_of_method_or_bare_fn");
// New region names that appear inside of the arguments of the function
// declaration are bound to that function type.
- let rb = rscope::BindingRscope::new();
+ let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
let output_ty = match decl.output {
hir::Return(ref output) =>
ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region,
- &output)),
+ &output,
+ ret_anon_scope)),
hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()),
hir::NoReturn(..) => ty::FnDiverging
};
use middle::free_region::FreeRegionMap;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::ty;
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::error::ExpectedFound;
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
+use rustc::hir::map::Node;
+use rustc::hir::{ImplItemKind, TraitItem_};
use syntax::ast;
use syntax_pos::Span;
return;
}
- tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|mut infcx| {
+ tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
// Normalize the associated types in the trait_bounds.
impl_trait_ref);
let tcx = ccx.tcx;
- tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
// The below is for the most part highly similar to the procedure
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
- let origin = TypeOrigin::Misc(impl_c_span);
+ let mut origin = TypeOrigin::Misc(impl_c_span);
let err = infcx.commit_if_ok(|_| {
// There is no "body" here, so just pass dummy id.
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
impl_ty,
trait_ty);
+
+ // Locate the Span containing just the type of the offending impl
+ if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) {
+ if let Node::NodeImplItem(impl_trait_item) = impl_trait_node {
+ if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node {
+ origin = TypeOrigin::Misc(ty.span);
+ }
+ }
+ }
+
let mut diag = struct_span_err!(
tcx.sess, origin.span(), E0326,
"implemented const `{}` has an incompatible type for trait",
trait_c.name
);
+
+ // Add a label to the Span containing just the type of the item
+ if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) {
+ if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node {
+ if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node {
+ diag.span_label(ty.span, &format!("original trait requirement"));
+ }
+ }
+ }
+
infcx.note_type_err(
&mut diag, origin,
Some(infer::ValuePairs::Types(ExpectedFound {
use middle::region;
use rustc::ty::subst::{self, Subst};
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use util::nodemap::FnvHashSet;
use syntax::ast;
// check that the impl type can be made to match the trait type.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
- tcx.infer_ctxt(None, Some(impl_param_env), ProjectionMode::AnyFinal).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(impl_param_env), Reveal::NotSpecializable).enter(|infcx| {
let tcx = infcx.tcx;
let mut fulfillment_cx = traits::FulfillmentContext::new();
}
// these are always dtorck
- ty::TyTrait(..) | ty::TyProjection(_) => bug!(),
+ ty::TyTrait(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
}
}
ty::TyEnum(def, _) | ty::TyStruct(def, _) => {
def.is_dtorck(tcx)
}
- ty::TyTrait(..) | ty::TyProjection(..) => {
+ ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
true
},
(0, Vec::new(), tcx.mk_nil())
}
op => {
- span_err!(tcx.sess, it.span, E0092,
- "unrecognized atomic operation function: `{}`", op);
+ struct_span_err!(tcx.sess, it.span, E0092,
+ "unrecognized atomic operation function: `{}`", op)
+ .span_label(it.span, &format!("unrecognized atomic operation"))
+ .emit();
return;
}
};
debug!("assemble_projection_candidates: step={:?}",
step);
- let projection_trait_ref = match step.self_ty.sty {
- ty::TyProjection(ref data) => &data.trait_ref,
+ let (def_id, substs) = match step.self_ty.sty {
+ ty::TyProjection(ref data) => {
+ (data.trait_ref.def_id, data.trait_ref.substs)
+ }
+ ty::TyAnon(def_id, substs) => (def_id, substs),
_ => continue,
};
- debug!("assemble_projection_candidates: projection_trait_ref={:?}",
- projection_trait_ref);
+ debug!("assemble_projection_candidates: def_id={:?} substs={:?}",
+ def_id, substs);
- let trait_predicates = self.tcx.lookup_predicates(projection_trait_ref.def_id);
- let bounds = trait_predicates.instantiate(self.tcx, projection_trait_ref.substs);
+ let trait_predicates = self.tcx.lookup_predicates(def_id);
+ let bounds = trait_predicates.instantiate(self.tcx, substs);
let predicates = bounds.predicates.into_vec();
debug!("assemble_projection_candidates: predicates={:?}",
predicates);
{
let bound = self.erase_late_bound_regions(&poly_bound);
- debug!("assemble_projection_candidates: projection_trait_ref={:?} bound={:?}",
- projection_trait_ref,
- bound);
+ debug!("assemble_projection_candidates: def_id={:?} substs={:?} bound={:?}",
+ def_id, substs, bound);
if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
let xform_self_ty = self.xform_self_ty(&item,
use hir::pat_util;
use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::{GenericPredicates, TypeScheme};
use rustc::ty::{ParamTy, ParameterEnvironment};
use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment;
-use rustc::ty::fold::TypeFoldable;
+use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::{self, Spanned};
+use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::parse::token::{self, InternedString, keywords};
use syntax::ptr::P;
use syntax::util::lev_distance::find_best_match_for_name;
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
+
+ // Anonymized types found in explicit return types and their
+ // associated fresh inference variable. Writeback resolves these
+ // variables to get the concrete type, which can be used to
+ // deanonymize TyAnon, after typeck is done with all functions.
+ anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
+
+ // Obligations which will have to be checked at the end of
+ // type-checking, after all functions have been inferred.
+ deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
}
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
}
impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
- pub fn inherited(&'a self, param_env: Option<ty::ParameterEnvironment<'gcx>>)
+ pub fn inherited(&'a self, id: ast::NodeId)
-> InheritedBuilder<'a, 'gcx, 'tcx> {
+ let param_env = ParameterEnvironment::for_item(self.tcx, id);
InheritedBuilder {
ccx: self,
infcx: self.tcx.infer_ctxt(Some(ty::Tables::empty()),
- param_env,
- ProjectionMode::AnyFinal)
+ Some(param_env),
+ Reveal::NotSpecializable)
}
}
}
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
+ anon_types: RefCell::new(DefIdMap()),
+ deferred_obligations: RefCell::new(Vec::new()),
})
})
}
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
hir::TyFixedLengthVec(_, ref expr) => {
- check_const_in_type(self.ccx, &expr, self.ccx.tcx.types.usize);
+ check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
}
_ => {}
}
ccx.tcx.sess.track_errors(|| {
let mut visit = CheckItemBodiesVisitor { ccx: ccx };
ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit);
+
+ // Process deferred obligations, now that all functions
+ // bodies have been fully inferred.
+ for (&item_id, obligations) in ccx.deferred_obligations.borrow().iter() {
+ // Use the same DepNode as for the body of the original function/item.
+ let def_id = ccx.tcx.map.local_def_id(item_id);
+ let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeckItemBody(def_id));
+
+ let param_env = ParameterEnvironment::for_item(ccx.tcx, item_id);
+ ccx.tcx.infer_ctxt(None, Some(param_env),
+ Reveal::NotSpecializable).enter(|infcx| {
+ let mut fulfillment_cx = traits::FulfillmentContext::new();
+ for obligation in obligations.iter().map(|o| o.to_obligation()) {
+ fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+ }
+
+ if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
+ infcx.report_fulfillment_errors(&errors);
+ }
+
+ if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
+ infcx.report_fulfillment_errors_as_warnings(&errors, item_id);
+ }
+ });
+ }
})
}
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block,
- fn_id: ast::NodeId,
- fn_span: Span,
- raw_fty: Ty<'tcx>,
- param_env: ty::ParameterEnvironment<'tcx>)
-{
+ fn_id: ast::NodeId) {
+ let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
let fn_ty = match raw_fty.sty {
ty::TyFnDef(_, _, f) => f,
_ => span_bug!(body.span, "check_bare_fn: function type expected")
};
- ccx.inherited(Some(param_env)).enter(|inh| {
+ ccx.inherited(fn_id).enter(|inh| {
// Compute the fty from point of view of inside fn.
let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body.id);
let fn_sig =
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
- fcx.regionck_fn(fn_id, fn_span, decl, body);
- fcx.resolve_type_vars_in_fn(decl, body);
+ fcx.regionck_fn(fn_id, decl, body);
+ fcx.resolve_type_vars_in_fn(decl, body, fn_id);
});
}
body: &'gcx hir::Block)
-> FnCtxt<'a, 'gcx, 'tcx>
{
- let arg_tys = &fn_sig.inputs;
- let ret_ty = fn_sig.output;
+ let mut fn_sig = fn_sig.clone();
- debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
- arg_tys,
- ret_ty,
- fn_id);
+ debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
- let fcx = FnCtxt::new(inherited, ret_ty, body.id);
+ let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
- if let ty::FnConverging(ret_ty) = ret_ty {
- fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
- }
-
- debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
-
- inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
+ fn_sig.output = match fcx.ret_ty {
+ ty::FnConverging(orig_ret_ty) => {
+ fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
+ ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
+ }
+ ty::FnDiverging => ty::FnDiverging
+ };
+ fcx.ret_ty = fn_sig.output;
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
// Add formal parameters.
- for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
+ for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) {
// The type of the argument must be well-formed.
//
// NB -- this is now checked in wfcheck, but that
});
// Check the pattern.
- fcx.check_pat(&input.pat, *arg_ty);
+ fcx.check_pat(&input.pat, arg_ty);
+ fcx.write_ty(input.id, arg_ty);
}
visit.visit_block(body);
}
- fcx.check_block_with_expected(body, match ret_ty {
+ inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
+
+ fcx.check_block_with_expected(body, match fcx.ret_ty {
ty::FnConverging(result_type) => ExpectHasType(result_type),
ty::FnDiverging => NoExpectation
});
- for (input, arg) in decl.inputs.iter().zip(arg_tys) {
- fcx.write_ty(input.id, arg);
- }
-
fcx
}
match it.node {
// Consts can play a role in type-checking, so they are included here.
hir::ItemStatic(_, _, ref e) |
- hir::ItemConst(_, ref e) => check_const(ccx, it.span, &e, it.id),
+ hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
let _indenter = indenter();
match it.node {
hir::ItemFn(ref decl, _, _, _, _, ref body) => {
- let fn_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
- let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
- check_bare_fn(ccx, &decl, &body, it.id, it.span, fn_pty.ty, param_env);
+ check_bare_fn(ccx, &decl, &body, it.id);
}
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
- let impl_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
-
for impl_item in impl_items {
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
- check_const(ccx, impl_item.span, &expr, impl_item.id)
+ check_const(ccx, &expr, impl_item.id)
}
hir::ImplItemKind::Method(ref sig, ref body) => {
- check_method_body(ccx, &impl_pty.generics, sig, body,
- impl_item.id, impl_item.span);
+ check_bare_fn(ccx, &sig.decl, body, impl_item.id);
}
hir::ImplItemKind::Type(_) => {
// Nothing to do here.
}
}
hir::ItemTrait(_, _, _, ref trait_items) => {
- let trait_def = ccx.tcx.lookup_trait_def(ccx.tcx.map.local_def_id(it.id));
for trait_item in trait_items {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref expr)) => {
- check_const(ccx, trait_item.span, &expr, trait_item.id)
+ check_const(ccx, &expr, trait_item.id)
}
hir::MethodTraitItem(ref sig, Some(ref body)) => {
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
- check_method_body(ccx, &trait_def.generics, sig, body,
- trait_item.id, trait_item.span);
+ check_bare_fn(ccx, &sig.decl, body, trait_item.id);
}
hir::MethodTraitItem(ref sig, None) => {
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
}
}
-/// Type checks a method body.
-///
-/// # Parameters
-///
-/// * `item_generics`: generics defined on the impl/trait that contains
-/// the method
-/// * `self_bound`: bound for the `Self` type parameter, if any
-/// * `method`: the method definition
-fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- item_generics: &ty::Generics<'tcx>,
- sig: &'tcx hir::MethodSig,
- body: &'tcx hir::Block,
- id: ast::NodeId, span: Span) {
- debug!("check_method_body(item_generics={:?}, id={})",
- item_generics, id);
- let param_env = ParameterEnvironment::for_item(ccx.tcx, id);
-
- let fty = ccx.tcx.node_id_to_type(id);
- debug!("check_method_body: fty={:?}", fty);
-
- check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
-}
-
fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_item: &hir::ImplItem,
parent_impl: DefId)
}
}
-/// Checks a constant appearing in a type. At the moment this is just the
-/// length expression in a fixed-length vector, but someday it might be
-/// extended to type-level numeric literals.
-fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
- expr: &'tcx hir::Expr,
- expected_type: Ty<'tcx>) {
- ccx.inherited(None).enter(|inh| {
+/// Checks a constant with a given type.
+fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
+ expr: &'tcx hir::Expr,
+ expected_type: Ty<'tcx>,
+ id: ast::NodeId) {
+ ccx.inherited(id).enter(|inh| {
let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
- fcx.check_const_with_ty(expr.span, expr, expected_type);
+ fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
+
+ // Gather locals in statics (because of block expressions).
+ // This is technically unnecessary because locals in static items are forbidden,
+ // but prevents type checking from blowing up before const checking can properly
+ // emit an error.
+ GatherLocalsVisitor { fcx: &fcx }.visit_expr(expr);
+
+ fcx.check_expr_coercable_to_type(expr, expected_type);
+
+ fcx.select_all_obligations_and_apply_defaults();
+ fcx.closure_analyze_const(expr);
+ fcx.select_obligations_where_possible();
+ fcx.check_casts();
+ fcx.select_all_obligations_or_error();
+
+ fcx.regionck_expr(expr);
+ fcx.resolve_type_vars_in_expr(expr, id);
});
}
-fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- sp: Span,
- e: &'tcx hir::Expr,
- id: ast::NodeId) {
- let param_env = ParameterEnvironment::for_item(ccx.tcx, id);
- ccx.inherited(Some(param_env)).enter(|inh| {
- let rty = ccx.tcx.node_id_to_type(id);
- let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id);
- let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
- fcx.require_type_is_sized(declty, e.span, traits::ConstSized);
- fcx.check_const_with_ty(sp, e, declty);
- });
+fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ expr: &'tcx hir::Expr,
+ id: ast::NodeId) {
+ let decl_ty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
+ check_const_with_type(ccx, expr, decl_ty, id);
}
/// Checks whether a type can be represented in memory. In particular, it
"unsupported representation for zero-variant enum");
}
- ccx.inherited(None).enter(|inh| {
- let rty = ccx.tcx.node_id_to_type(id);
- let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), id);
-
- let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
- for v in vs {
- if let Some(ref e) = v.node.disr_expr {
- fcx.check_const_with_ty(e.span, e, repr_type_ty);
- }
+ let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
+ for v in vs {
+ if let Some(ref e) = v.node.disr_expr {
+ check_const_with_type(ccx, e, repr_type_ty, e.id);
}
+ }
- let def_id = ccx.tcx.map.local_def_id(id);
-
- let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
- let mut disr_vals: Vec<ty::Disr> = Vec::new();
- for (v, variant) in vs.iter().zip(variants.iter()) {
- let current_disr_val = variant.disr_val;
-
- // Check for duplicate discriminant values
- if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
- let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
- "discriminant value `{}` already exists", disr_vals[i]);
- let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
- err.span_label(ccx.tcx.map.span(variant_i_node_id),
- &format!("first use of `{}`", disr_vals[i]));
- err.span_label(v.span , &format!("enum already has `{}`", disr_vals[i]));
- err.emit();
- }
- disr_vals.push(current_disr_val);
+ let def_id = ccx.tcx.map.local_def_id(id);
+
+ let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
+ let mut disr_vals: Vec<ty::Disr> = Vec::new();
+ for (v, variant) in vs.iter().zip(variants.iter()) {
+ let current_disr_val = variant.disr_val;
+
+ // Check for duplicate discriminant values
+ if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
+ let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
+ let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
+ let i_span = match variant_i.node.disr_expr {
+ Some(ref expr) => expr.span,
+ None => ccx.tcx.map.span(variant_i_node_id)
+ };
+ let span = match v.node.disr_expr {
+ Some(ref expr) => expr.span,
+ None => v.span
+ };
+ struct_span_err!(ccx.tcx.sess, span, E0081,
+ "discriminant value `{}` already exists", disr_vals[i])
+ .span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
+ .span_label(span , &format!("enum already has `{}`", disr_vals[i]))
+ .emit();
}
- });
+ disr_vals.push(current_disr_val);
+ }
check_representable(ccx.tcx, sp, id, "enum");
}
}
}
+ /// Replace all anonymized types with fresh inference variables
+ /// and record them for writeback.
+ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
+ value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
+ if let ty::TyAnon(def_id, substs) = ty.sty {
+ // Use the same type variable if the exact same TyAnon appears more
+ // than once in the return type (e.g. if it's pased to a type alias).
+ if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
+ return ty_var;
+ }
+ let ty_var = self.next_ty_var();
+ self.anon_types.borrow_mut().insert(def_id, ty_var);
+
+ let item_predicates = self.tcx.lookup_predicates(def_id);
+ let bounds = item_predicates.instantiate(self.tcx, substs);
+
+ let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP);
+ for predicate in bounds.predicates {
+ // Change the predicate to refer to the type variable,
+ // which will be the concrete type, instead of the TyAnon.
+ // This also instantiates nested `impl Trait`.
+ let predicate = self.instantiate_anon_types(&predicate);
+
+ // Require that the predicate holds for the concrete type.
+ let cause = traits::ObligationCause::new(span, self.body_id,
+ traits::ReturnType);
+ self.register_predicate(traits::Obligation::new(cause, predicate));
+ }
+
+ ty_var
+ } else {
+ ty
+ }
+ }})
+ }
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx>
node_id: ast::NodeId)
-> Ty<'tcx> {
debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
- let type_scheme = self.tcx.lookup_item_type(did);
+ let mut type_scheme = self.tcx.lookup_item_type(did);
+ if type_scheme.ty.is_fn() {
+ // Tuple variants have fn type even in type namespace, extract true variant type from it
+ let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
+ type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
+ }
let type_predicates = self.tcx.lookup_predicates(did);
let substs = AstConv::ast_path_substs_for_ty(self, self,
path.span,
self.select_all_obligations_and_apply_defaults();
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
+
+ // Steal the deferred obligations before the fulfillment
+ // context can turn all of them into errors.
+ let obligations = fulfillment_cx.take_deferred_obligations();
+ self.deferred_obligations.borrow_mut().extend(obligations);
+
match fulfillment_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => { self.report_fulfillment_errors(&errors); }
}
_ => None
};
- if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
- // Reject tuple structs for now, braced and unit structs are allowed.
+
+ if let Some(variant) = variant {
+ if variant.kind == ty::VariantKind::Tuple &&
+ !self.tcx.sess.features.borrow().relaxed_adts {
+ emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
+ "relaxed_adts", span, GateIssue::Language,
+ "tuple structs and variants in struct patterns are unstable");
+ }
+ let ty = self.instantiate_type_path(def.def_id(), path, node_id);
+ Some((variant, ty))
+ } else {
struct_span_err!(self.tcx.sess, path.span, E0071,
"`{}` does not name a struct or a struct variant",
pprust::path_to_string(path))
.span_label(path.span, &format!("not a struct"))
.emit();
-
- return None;
+ None
}
-
- let ty = self.instantiate_type_path(def.def_id(), path, node_id);
- Some((variant.unwrap(), ty))
}
fn check_expr_struct(&self,
*self.ps.borrow_mut() = prev;
}
-
- fn check_const_with_ty(&self,
- _: Span,
- e: &'gcx hir::Expr,
- declty: Ty<'tcx>) {
- // Gather locals in statics (because of block expressions).
- // This is technically unnecessary because locals in static items are forbidden,
- // but prevents type checking from blowing up before const checking can properly
- // emit an error.
- GatherLocalsVisitor { fcx: self }.visit_expr(e);
-
- self.check_expr_coercable_to_type(e, declty);
-
- self.select_all_obligations_and_apply_defaults();
- self.closure_analyze_const(e);
- self.select_obligations_where_possible();
- self.check_casts();
- self.select_all_obligations_or_error();
-
- self.regionck_expr(e);
- self.resolve_type_vars_in_expr(e);
- }
-
// Returns the type parameter count and the type for the given definition.
fn type_scheme_and_predicates_for_def(&self,
sp: Span,
for (i, b) in tps_used.iter().enumerate() {
if !*b {
- span_err!(ccx.tcx.sess, tps[i].span, E0091,
+ struct_span_err!(ccx.tcx.sess, tps[i].span, E0091,
"type parameter `{}` is unused",
- tps[i].name);
+ tps[i].name)
+ .span_label(tps[i].span, &format!("unused type parameter"))
+ .emit();
}
}
}
pub fn regionck_fn(&self,
fn_id: ast::NodeId,
- fn_span: Span,
decl: &hir::FnDecl,
blk: &hir::Block) {
debug!("regionck_fn(id={})", fn_id);
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- rcx.visit_fn_body(fn_id, decl, blk, fn_span);
+ rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id));
}
rcx.free_region_map.relate_free_regions_from_predicates(
fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
-> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
- let param_env = ty::ParameterEnvironment::for_item(self.ccx.tcx, id);
CheckWfFcxBuilder {
- inherited: self.ccx.inherited(Some(param_env)),
+ inherited: self.ccx.inherited(id),
code: self.code.clone(),
id: id,
span: span
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable};
+use rustc::ty::subst::ParamSpace;
use rustc::infer::{InferCtxt, FixupError};
+use rustc::util::nodemap::DefIdMap;
use write_substs_to_tcx;
use write_ty_to_tcx;
// Entry point functions
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) {
+ pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr, item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
wbcx.visit_expr(e);
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
+ wbcx.visit_deferred_obligations(item_id);
}
- pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
+ pub fn resolve_type_vars_in_fn(&self,
+ decl: &hir::FnDecl,
+ blk: &hir::Block,
+ item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
wbcx.visit_block(blk);
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
+ wbcx.visit_anon_types();
+ wbcx.visit_deferred_obligations(item_id);
}
}
struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
+
+ // Mapping from free regions of the function to the
+ // early-bound versions of them, visible from the
+ // outside of the function. This is needed by, and
+ // only populated if there are any `impl Trait`.
+ free_to_bound_regions: DefIdMap<ty::Region>
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
- WritebackCx { fcx: fcx }
+ let mut wbcx = WritebackCx {
+ fcx: fcx,
+ free_to_bound_regions: DefIdMap()
+ };
+
+ // Only build the reverse mapping if `impl Trait` is used.
+ if fcx.anon_types.borrow().is_empty() {
+ return wbcx;
+ }
+
+ let free_substs = fcx.parameter_environment.free_substs;
+ for &space in &ParamSpace::all() {
+ for (i, r) in free_substs.regions.get_slice(space).iter().enumerate() {
+ match *r {
+ ty::ReFree(ty::FreeRegion {
+ bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
+ }) => {
+ let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
+ space: space,
+ index: i as u32,
+ name: name,
+ });
+ wbcx.free_to_bound_regions.insert(def_id, bound_region);
+ }
+ _ => {
+ bug!("{:?} is not a free region for an early-bound lifetime", r);
+ }
+ }
+ }
+ }
+
+ wbcx
}
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
}
}
+ fn visit_anon_types(&self) {
+ if self.fcx.writeback_errors.get() {
+ return
+ }
+
+ let gcx = self.tcx().global_tcx();
+ for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
+ let reason = ResolvingAnonTy(def_id);
+ let inside_ty = self.resolve(&concrete_ty, reason);
+
+ // Convert the type from the function into a type valid outside
+ // the function, by replacing free regions with early-bound ones.
+ let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
+ match r {
+ // 'static is valid everywhere.
+ ty::ReStatic => ty::ReStatic,
+
+ // Free regions that come from early-bound regions are valid.
+ ty::ReFree(ty::FreeRegion {
+ bound_region: ty::BoundRegion::BrNamed(def_id, _, _), ..
+ }) if self.free_to_bound_regions.contains_key(&def_id) => {
+ self.free_to_bound_regions[&def_id]
+ }
+
+ ty::ReFree(_) |
+ ty::ReEarlyBound(_) |
+ ty::ReLateBound(..) |
+ ty::ReScope(_) |
+ ty::ReSkolemized(..) => {
+ let span = reason.span(self.tcx());
+ span_err!(self.tcx().sess, span, E0564,
+ "only named lifetimes are allowed in `impl Trait`, \
+ but `{}` was found in the type `{}`", r, inside_ty);
+ ty::ReStatic
+ }
+
+ ty::ReVar(_) |
+ ty::ReEmpty |
+ ty::ReErased => {
+ let span = reason.span(self.tcx());
+ span_bug!(span, "invalid region in impl Trait: {:?}", r);
+ }
+ }
+ });
+
+ gcx.tcache.borrow_mut().insert(def_id, ty::TypeScheme {
+ ty: outside_ty,
+ generics: ty::Generics::empty()
+ });
+ }
+ }
+
fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
// Resolve any borrowings for the node with id `id`
self.visit_adjustments(reason, id);
}
}
+ fn visit_deferred_obligations(&self, item_id: ast::NodeId) {
+ let deferred_obligations = self.fcx.deferred_obligations.borrow();
+ let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
+ let reason = ResolvingDeferredObligation(obligation.cause.span);
+ self.resolve(obligation, reason)
+ }).collect();
+
+ if !obligations.is_empty() {
+ assert!(self.fcx.ccx.deferred_obligations.borrow_mut()
+ .insert(item_id, obligations).is_none());
+ }
+ }
+
fn resolve<T>(&self, x: &T, reason: ResolveReason) -> T::Lifted
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
{
///////////////////////////////////////////////////////////////////////////
// Resolution reason.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
enum ResolveReason {
ResolvingExpr(Span),
ResolvingLocal(Span),
ResolvingUpvar(ty::UpvarId),
ResolvingClosure(DefId),
ResolvingFnSig(ast::NodeId),
- ResolvingFieldTypes(ast::NodeId)
+ ResolvingFieldTypes(ast::NodeId),
+ ResolvingAnonTy(DefId),
+ ResolvingDeferredObligation(Span),
}
impl<'a, 'gcx, 'tcx> ResolveReason {
ResolvingFieldTypes(id) => {
tcx.map.span(id)
}
- ResolvingClosure(did) => {
- if let Some(node_id) = tcx.map.as_local_node_id(did) {
- tcx.expr_span(node_id)
- } else {
- DUMMY_SP
- }
+ ResolvingClosure(did) |
+ ResolvingAnonTy(did) => {
+ tcx.map.def_id_span(did, DUMMY_SP)
}
+ ResolvingDeferredObligation(span) => span
}
}
}
"cannot determine a type for this closure")
}
- ResolvingFnSig(id) | ResolvingFieldTypes(id) => {
+ ResolvingFnSig(_) |
+ ResolvingFieldTypes(_) |
+ ResolvingDeferredObligation(_) => {
// any failures here should also fail when
// resolving the patterns, closure types, or
// something else.
let span = self.reason.span(self.tcx);
self.tcx.sess.delay_span_bug(
span,
- &format!("cannot resolve some aspect of data for {:?}", id));
+ &format!("cannot resolve some aspect of data for {:?}: {}",
+ self.reason, e));
+ }
+
+ ResolvingAnonTy(_) => {
+ let span = self.reason.span(self.tcx);
+ span_err!(self.tcx.sess, span, E0563,
+ "cannot determine a type for this `impl Trait`: {}", e)
}
}
}
use middle::lang_items::UnsizeTraitLangItem;
use rustc::ty::subst::{self, Subst};
use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId};
use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
use rustc::ty::{TyRef, TyStruct, TyTrait, TyTuple};
use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
-use rustc::ty::TyProjection;
+use rustc::ty::{TyProjection, TyAnon};
use rustc::ty::util::CopyImplementationError;
use middle::free_region::FreeRegionMap;
use CrateCtxt;
None
}
- TyInfer(..) | TyClosure(..) => {
+ TyInfer(..) | TyClosure(..) | TyAnon(..) => {
// `ty` comes from a user declaration so we should only expect types
// that the user can type
span_bug!(
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
source, target);
- tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Topmost).enter(|infcx| {
+ tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
let origin = TypeOrigin::Misc(span);
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>,
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
pub fn check_coherence(ccx: &CrateCtxt) {
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
- ccx.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).enter(|infcx| {
+ ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
CoherenceChecker {
crate_context: ccx,
inference_context: infcx,
//! constructor provide a method with the same name.
use hir::def_id::DefId;
-use rustc::traits::{self, ProjectionMode};
+use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt};
use syntax::ast;
use rustc::dep_graph::DepNode;
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i+1)..] {
- self.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).enter(|infcx| {
+ self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
}
let ty_generic_predicates =
ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates);
- let (fty, explicit_self_category) =
+ let (fty, explicit_self_category) = {
+ let anon_scope = match container {
+ ImplContainer(_) => Some(AnonTypeScope::new(&ty_generics)),
+ TraitContainer(_) => None
+ };
AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
- sig,
- untransformed_rcvr_ty);
+ sig, untransformed_rcvr_ty, anon_scope)
+ };
let def_id = ccx.tcx.map.local_def_id(id);
- let substs = mk_item_substs(ccx, &ty_generics);
+ let substs = mk_item_substs(ccx.tcx, &ty_generics);
let ty_method = ty::Method::new(name,
ty_generics,
.map(|field| field.unsubst_ty())
.collect();
let def_id = tcx.map.local_def_id(ctor_id);
- let substs = mk_item_substs(ccx, &scheme.generics);
+ let substs = mk_item_substs(tcx, &scheme.generics);
tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: abi::Abi::Rust,
// Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
let self_param_ty = tcx.mk_self_type();
let superbounds1 = compute_bounds(&ccx.icx(scope),
- self_param_ty,
- bounds,
- SizedByDefault::No,
- item.span);
+ self_param_ty,
+ bounds,
+ SizedByDefault::No,
+ None,
+ item.span);
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
assoc_ty,
bounds,
SizedByDefault::Yes,
+ None,
trait_item.span);
bounds.predicates(ccx.tcx, assoc_ty).into_iter()
}
hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
- let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl);
+ let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
+ Some(AnonTypeScope::new(&ty_generics)));
let def_id = ccx.tcx.map.local_def_id(it.id);
- let substs = mk_item_substs(ccx, &ty_generics);
+ let substs = mk_item_substs(tcx, &ty_generics);
let ty = tcx.mk_fn_def(def_id, substs, tofd);
ty::TypeScheme { ty: ty, generics: ty_generics }
}
hir::ItemEnum(ref ei, ref generics) => {
let def = convert_enum_def(ccx, it, ei);
let ty_generics = ty_generics_for_type(ccx, generics);
- let substs = mk_item_substs(ccx, &ty_generics);
+ let substs = mk_item_substs(tcx, &ty_generics);
let t = tcx.mk_enum(def, substs);
ty::TypeScheme { ty: t, generics: ty_generics }
}
hir::ItemStruct(ref si, ref generics) => {
let def = convert_struct_def(ccx, it, si);
let ty_generics = ty_generics_for_type(ccx, generics);
- let substs = mk_item_substs(ccx, &ty_generics);
+ let substs = mk_item_substs(tcx, &ty_generics);
let t = tcx.mk_struct(def, substs);
ty::TypeScheme { ty: t, generics: ty_generics }
}
}
// Add the Sized bound, unless the type parameter is marked as `?Sized`.
-fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
- bounds: &mut ty::BuiltinBounds,
- ast_bounds: &[hir::TyParamBound],
- span: Span)
+fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+ bounds: &mut ty::BuiltinBounds,
+ ast_bounds: &[hir::TyParamBound],
+ span: Span)
{
let tcx = astconv.tcx();
param_ty,
¶m.bounds,
SizedByDefault::Yes,
+ None,
param.span);
let predicates = bounds.predicates(ccx.tcx, param_ty);
result.predicates.extend(space, predicates.into_iter());
for leaf_ty in ty.walk() {
if let ty::TyParam(p) = leaf_ty.sty {
if p.space == space && p.idx >= index {
- span_err!(ccx.tcx.sess, path.span, E0128,
- "type parameters with a default cannot use \
- forward declared identifiers");
+ struct_span_err!(ccx.tcx.sess, path.span, E0128,
+ "type parameters with a default cannot use \
+ forward declared identifiers")
+ .span_label(path.span, &format!("defaulted type parameters \
+ cannot be forward declared"))
+ .emit();
return ccx.tcx.types.err
}
}
}
-enum SizedByDefault { Yes, No, }
+pub enum SizedByDefault { Yes, No, }
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
/// built-in trait (formerly known as kind): Send.
-fn compute_bounds<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
- param_ty: ty::Ty<'tcx>,
- ast_bounds: &[hir::TyParamBound],
- sized_by_default: SizedByDefault,
- span: Span)
- -> Bounds<'tcx>
+pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+ param_ty: ty::Ty<'tcx>,
+ ast_bounds: &[hir::TyParamBound],
+ sized_by_default: SizedByDefault,
+ anon_scope: Option<AnonTypeScope>,
+ span: Span)
+ -> Bounds<'tcx>
{
- let mut bounds =
- conv_param_bounds(astconv,
- span,
- param_ty,
- ast_bounds);
+ let tcx = astconv.tcx();
+ let PartitionedBounds {
+ mut builtin_bounds,
+ trait_bounds,
+ region_bounds
+ } = partition_bounds(tcx, span, &ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
- add_unsized_bound(astconv,
- &mut bounds.builtin_bounds,
- ast_bounds,
- span);
+ add_unsized_bound(astconv, &mut builtin_bounds, ast_bounds, span);
}
- bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
+ let mut projection_bounds = vec![];
+
+ let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope);
+ let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
+ astconv.instantiate_poly_trait_ref(&rscope,
+ bound,
+ Some(param_ty),
+ &mut projection_bounds)
+ }).collect();
- bounds
+ let region_bounds = region_bounds.into_iter().map(|r| {
+ ast_region_to_region(tcx, r)
+ }).collect();
+
+ trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
+
+ Bounds {
+ region_bounds: region_bounds,
+ builtin_bounds: builtin_bounds,
+ trait_bounds: trait_bounds,
+ projection_bounds: projection_bounds,
+ }
}
/// Converts a specific TyParamBound from the AST into a set of
}
}
-fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
- param_ty: Ty<'tcx>,
- trait_ref: &hir::PolyTraitRef,
- projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
- -> ty::PolyTraitRef<'tcx>
+fn conv_poly_trait_ref<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+ param_ty: Ty<'tcx>,
+ trait_ref: &hir::PolyTraitRef,
+ projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> ty::PolyTraitRef<'tcx>
{
AstConv::instantiate_poly_trait_ref(astconv,
&ExplicitRscope,
projections)
}
-fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx, 'tcx>,
- span: Span,
- param_ty: ty::Ty<'tcx>,
- ast_bounds: &[hir::TyParamBound])
- -> Bounds<'tcx>
-{
- let tcx = astconv.tcx();
- let PartitionedBounds {
- builtin_bounds,
- trait_bounds,
- region_bounds
- } = partition_bounds(tcx, span, &ast_bounds);
-
- let mut projection_bounds = Vec::new();
-
- let trait_bounds: Vec<ty::PolyTraitRef> =
- trait_bounds.iter()
- .map(|bound| conv_poly_trait_ref(astconv,
- param_ty,
- *bound,
- &mut projection_bounds))
- .collect();
-
- let region_bounds: Vec<ty::Region> =
- region_bounds.into_iter()
- .map(|r| ast_region_to_region(tcx, r))
- .collect();
-
- Bounds {
- region_bounds: region_bounds,
- builtin_bounds: builtin_bounds,
- trait_bounds: trait_bounds,
- projection_bounds: projection_bounds,
- }
-}
-
fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
ccx: &CrateCtxt<'a, 'tcx>,
id: DefId,
}
}
- let substs = mk_item_substs(ccx, &ty_generics);
+ let substs = mk_item_substs(ccx.tcx, &ty_generics);
let t_fn = ccx.tcx.mk_fn_def(id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
abi: abi,
unsafety: hir::Unsafety::Unsafe,
}
}
-fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- ty_generics: &ty::Generics<'tcx>)
- -> &'tcx Substs<'tcx>
+pub fn mk_item_substs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ ty_generics: &ty::Generics)
+ -> &'tcx Substs<'tcx>
{
let types =
ty_generics.types.map(
- |def| ccx.tcx.mk_param_from_def(def));
+ |def| tcx.mk_param_from_def(def));
let regions =
ty_generics.regions.map(
|def| def.to_early_bound_region());
- ccx.tcx.mk_substs(Substs::new(types, regions))
+ tcx.mk_substs(Substs::new(types, regions))
}
/// Checks that all the type parameters on an impl
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
match t.sty {
- ty::TyProjection(..) if !self.include_nonconstraining => {
+ ty::TyProjection(..) | ty::TyAnon(..) if !self.include_nonconstraining => {
// projections are not injective
return false;
}
Matching with the wrong number of fields has no sensible interpretation:
-```compile_fail
+```compile_fail,E0023
enum Fruit {
Apple(String, String),
Pear(u32),
Each field of a struct can only be bound once in a pattern. Erroneous code
example:
-```compile_fail
+```compile_fail,E0025
struct Foo {
a: u8,
b: u8,
Change this:
-```compile_fail
+```compile_fail,E0026
struct Thing {
x: u32,
y: u32
For example:
-```compile_fail
+```compile_fail,E0027
struct Dog {
name: String,
age: u32,
want to capture values of an orderable type between two end-points, you can use
a guard.
-```compile_fail
+```compile_fail,E0029
+let string = "salutations !";
+
// The ordering relation for strings can't be evaluated at compile time,
// so this doesn't work:
match string {
The compiler doesn't know what method to call because more than one method
has the same prototype. Erroneous code example:
-```compile_fail
+```compile_fail,E0034
struct Test;
trait Trait1 {
You tried to give a type parameter where it wasn't needed. Erroneous code
example:
-```compile_fail
+```compile_fail,E0035
struct Test;
impl Test {
This error occurrs when you pass too many or not enough type parameters to
a method. Erroneous code example:
-```compile_fail
+```compile_fail,E0036
struct Test;
impl Test {
Here's an example of this error:
-```compile_fail
+```compile_fail,E0040
struct Foo {
x: i32,
}
E0044: r##"
You can't use type parameters on foreign items. Example of erroneous code:
-```compile_fail
+```compile_fail,E0044
extern { fn some_func<T>(x: T); }
```
FFI. As such, variadic parameters can only be used with functions which are
using the C ABI. Examples of erroneous code:
-```compile_fail
+```compile_fail,E0045
+#![feature(unboxed_closures)]
+
extern "rust-call" { fn foo(x: u8, ...); }
// or
To fix such code, put them in an extern "C" block:
-```ignore
-extern "C" fn foo(x: u8, ...);
-```
-
-Or:
-
```
extern "C" {
fn foo (x: u8, ...);
E0046: r##"
Items are missing in a trait implementation. Erroneous code example:
-```compile_fail
+```compile_fail,E0046
trait Foo {
fn foo();
}
For example, the trait below has a method `foo` with a type parameter `T`,
but the implementation of `foo` for the type `Bar` is missing this parameter:
-```compile_fail
+```compile_fail,E0049
trait Foo {
fn foo<T: Default>(x: T) -> Self;
}
(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits
the `u8` parameter:
-```compile_fail
+```compile_fail,E0050
trait Foo {
fn foo(&self, x: u8) -> bool;
}
Here are a couple examples of this error:
-```compile_fail
+```compile_fail,E0053
trait Foo {
fn foo(x: u16);
fn bar(&self);
It is not allowed to cast to a bool. If you are trying to cast a numeric type
to a bool, you can compare it with zero instead:
-```compile_fail
+```compile_fail,E0054
let x = 5;
// Not allowed, won't compile
For a somewhat artificial example:
-```compile_fail,ignore
+```compile_fail,E0055
#![recursion_limit="2"]
struct Foo;
An example using a closure:
-```compile_fail
+```compile_fail,E0057
let f = |x| x * 3;
let a = f(); // invalid, too few parameters
let b = f(4); // this works!
The most likely source of this error is using angle-bracket notation without
wrapping the function argument type into a tuple, for example:
-```compile_fail
+```compile_fail,E0059
+#![feature(unboxed_closures)]
+
fn foo<F: Fn<i32>>(f: F) -> F::Output { f(3) }
```
It can be fixed by adjusting the trait bound like this:
-```ignore
+```
+#![feature(unboxed_closures)]
+
fn foo<F: Fn<(i32,)>>(f: F) -> F::Output { f(3) }
```
enum variant, one of the fields was specified more than once. Erroneous code
example:
-```compile_fail
+```compile_fail,E0062
struct Foo {
- x: i32
+ x: i32,
}
fn main() {
```
struct Foo {
- x: i32
+ x: i32,
}
fn main() {
This error indicates that during an attempt to build a struct or struct-like
enum variant, one of the fields was not provided. Erroneous code example:
-```compile_fail
+```compile_fail,E0063
struct Foo {
x: i32,
- y: i32
+ y: i32,
}
fn main() {
```
struct Foo {
x: i32,
- y: i32
+ y: i32,
}
fn main() {
Let's start with some erroneous code examples:
-```compile_fail
+```compile_fail,E0067
use std::collections::LinkedList;
// Bad: assignment to non-lvalue expression
The compiler found a function whose body contains a `return;` statement but
whose return type is not `()`. An example of this is:
-```compile_fail
+```compile_fail,E0069
// error
fn foo() -> u8 {
return;
Now, we can go further. Here are some erroneous code examples:
-```compile_fail
+```compile_fail,E0070
struct SomeStruct {
x: i32,
y: i32
Example of erroneous code:
-```compile_fail
+```compile_fail,E0071
enum Foo { FirstValue(i32) };
let u = Foo::FirstValue { value: 0 }; // error: Foo::FirstValue
This will cause an error:
-```compile_fail
+```compile_fail,E0075
#![feature(repr_simd)]
#[repr(simd)]
This will cause an error:
-```compile_fail
+```compile_fail,E0076
#![feature(repr_simd)]
#[repr(simd)]
This will cause an error:
-```compile_fail
+```compile_fail,E0077
#![feature(repr_simd)]
#[repr(simd)]
For example, in the following code:
-```compile_fail
+```compile_fail,E0079
enum Foo {
- Q = "32"
+ Q = "32",
}
```
```
enum Foo {
- Q = 32
+ Q = 32,
}
```
This error indicates that the same value was used for two or more variants,
making them impossible to tell apart.
-```compile_fail
+```compile_fail,E0081
// Bad.
enum Enum {
P = 3,
X = 3,
- Y = 5
+ Y = 5,
}
```
enum Enum {
P,
X = 3,
- Y = 5
+ Y = 5,
}
```
top to bottom starting from 0, so clashes can occur with seemingly unrelated
variants.
-```compile_fail
+```compile_fail,E0081
enum Bad {
X,
Y = 0
#[repr(u8)]
enum Thing {
A = 1024,
- B = 5
+ B = 5,
}
```
```ignore
enum DependsOnPointerSize {
- A = 1 << 32
+ A = 1 << 32,
}
```
Erroneous code example:
-```compile_fail
+```compile_fail,E0084
#[repr(i32)]
enum NightsWatch {} // error: unsupported representation for zero-variant enum
```
E0087: r##"
Too many type parameters were supplied for a function. For example:
-```compile_fail
+```compile_fail,E0087
fn foo<T>() {}
fn main() {
E0088: r##"
You gave too many lifetime parameters. Erroneous code example:
-```compile_fail
+```compile_fail,E0088
fn f() {}
fn main() {
E0089: r##"
Not enough type parameters were supplied for a function. For example:
-```compile_fail
+```compile_fail,E0089
fn foo<T, U>() {}
fn main() {
Note that if a function takes multiple type parameters but you want the compiler
to infer some of them, you can use type placeholders:
-```compile_fail
+```compile_fail,E0089
fn foo<T, U>(x: T) {}
fn main() {
You gave an unnecessary type parameter in a type alias. Erroneous code
example:
-```compile_fail
+```compile_fail,E0091
type Foo<T> = u32; // error: type parameter `T` is unused
// or:
type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
You tried to declare an undefined atomic operation function.
Erroneous code example:
-```compile_fail
+```compile_fail,E0092
#![feature(intrinsics)]
extern "rust-intrinsic" {
E0093: r##"
You declared an unknown intrinsic function. Erroneous code example:
-```compile_fail
+```compile_fail,E0093
#![feature(intrinsics)]
extern "rust-intrinsic" {
You gave an invalid number of type parameters to an intrinsic function.
Erroneous code example:
-```compile_fail
+```compile_fail,E0094
#![feature(intrinsics)]
extern "rust-intrinsic" {
You hit this error because the compiler lacks the information to
determine a type for this expression. Erroneous code example:
-```compile_fail
-fn main() {
- let x = |_| {}; // error: cannot determine a type for this expression
-}
+```compile_fail,E0101
+let x = |_| {}; // error: cannot determine a type for this expression
```
You have two possibilities to solve this situation:
Examples:
```
-fn main() {
- let x = |_ : u32| {}; // ok!
- // or:
- let x = |_| {};
- x(0u32);
-}
+let x = |_ : u32| {}; // ok!
+// or:
+let x = |_| {};
+x(0u32);
```
"##,
You hit this error because the compiler lacks the information to
determine the type of this variable. Erroneous code example:
-```compile_fail
-fn main() {
- // could be an array of anything
- let x = []; // error: cannot determine a type for this local variable
-}
+```compile_fail,E0102
+// could be an array of anything
+let x = []; // error: cannot determine a type for this local variable
```
To solve this situation, constrain the type of the variable.
Here are some simple examples of where you'll run into this error:
-```compile_fail
+```compile_fail,E0106
struct Foo { x: &bool } // error
struct Foo<'a> { x: &'a bool } // correct
Here are some examples of elision errors:
-```compile_fail
+```compile_fail,E0106
// error, no input lifetimes
fn foo() -> &str { }
Some basic examples include:
-```compile_fail
+```compile_fail,E0107
struct Foo<'a>(&'a str);
enum Bar { A, B, C }
Here's an example that is currently an error, but may work in a future version
of Rust:
-```compile_fail
+```compile_fail,E0107
struct Foo<'a>(&'a str);
trait Quux { }
where the type was defined. For example, an `impl` block as below is not allowed
since `Vec` is defined in the standard library:
-```compile_fail
+```compile_fail,E0116
impl Vec<u8> { } // error
```
Note that using the `type` keyword does not work here because `type` only
introduces a type alias:
-```compile_fail
+```compile_fail,E0116
type Bytes = Vec<u8>;
impl Bytes { } // error, same as above
Here's one example of this error:
-```compile_fail
+```compile_fail,E0117
impl Drop for u32 {}
```
You're trying to write an inherent implementation for something which isn't a
struct nor an enum. Erroneous code example:
-```compile_fail
+```compile_fail,E0118
impl (u8, u8) { // error: no base type found for inherent implementation
fn get_state(&self) -> String {
// ...
There are conflicting trait implementations for the same type.
Example of erroneous code:
-```compile_fail
+```compile_fail,E0119
trait MyTrait {
fn get(&self) -> usize;
}
An attempt was made to implement Drop on a trait, which is not allowed: only
structs and enums can implement Drop. An example causing this error:
-```compile_fail
+```compile_fail,E0120
trait MyTrait {}
impl Drop for MyTrait {
Examples of this error include:
-```compile_fail
+```compile_fail,E0121
fn foo() -> _ { 5 } // error, explicitly write out the return type instead
static BAR: _ = "test"; // error, explicitly write out the type instead
You declared two fields of a struct with the same name. Erroneous code
example:
-```compile_fail
+```compile_fail,E0124
struct Foo {
field1: i32,
field1: i32, // error: field is already declared
Type parameter defaults can only use parameters that occur before them.
Erroneous code example:
-```compile_fail
+```compile_fail,E0128
struct Foo<T=U, U=()> {
field1: T,
filed2: U,
parameters. When `main` is present, it must take no arguments and return `()`.
Erroneous code example:
-```compile_fail
+```compile_fail,E0131
fn main<T>() { // error: main function is not allowed to have type parameters
}
```
Erroneous code example:
-```compile_fail
+```compile_fail,E0132
#![feature(start)]
#[start]
This error means that an attempt was made to match a struct type enum
variant as a non-struct type:
-```compile_fail
+```compile_fail,E0164
enum Foo { B { i: u32 } }
fn bar(foo: Foo) -> u32 {
marked as diverging. A function diverges if it has `!` in the place of the
return type in its signature. For example:
-```compile_fail
+```compile_fail,E0166
fn foo() -> ! { return; } // error
```
This error means that an attempt was made to specify the type of a variable with
a combination of a concrete type and a trait. Consider the following example:
-```compile_fail
+```compile_fail,E0172
fn foo(bar: i32+std::fmt::Display) {}
```
For example:
-```compile_fail
+```compile_fail,E0178
trait Foo {}
struct Bar<'a> {
Here's an example of this error:
-```compile_fail
+```compile_fail,E0185
trait Foo {
fn foo();
}
Here's an example of this error:
-```compile_fail
+```compile_fail,E0186
trait Foo {
fn foo(&self);
}
Trait objects need to have all associated types specified. Erroneous code
example:
-```compile_fail
+```compile_fail,E0191
trait Trait {
type Bar;
}
A type parameter was declared which shadows an existing one. An example of this
error:
-```compile_fail
+```compile_fail,E0194
trait Foo<T> {
fn do_something(&self) -> T;
fn do_something_else<T: Clone>(&self, bar: T);
Your method's lifetime parameters do not match the trait declaration.
Erroneous code example:
-```compile_fail
+```compile_fail,E0195
trait Trait {
fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
}
implementing an unsafe trait. Removing the `unsafe` keyword from the inherent
implementation will resolve this error.
-```compile_fail
+```compile_fail,E0197
struct Foo;
// this will cause this error
implementation for a safe trait unsafe will cause a compiler error. Removing
the unsafe marker on the trait noted in the error will resolve this problem.
-```compile_fail
+```compile_fail,E0199
struct Foo;
trait Bar { }
implementation for an unsafe trait isn't marked as unsafe. This may be resolved
by marking the unsafe implementation as unsafe.
-```compile_fail
+```compile_fail,E0200
struct Foo;
unsafe trait Bar { }
For example:
-```compile_fail
+```compile_fail,E0201
struct Foo(u8);
impl Foo {
fields does not implement `Copy`. To fix this, you must implement `Copy` for the
mentioned field. Note that this may not be possible, as in the example of
-```compile_fail
+```compile_fail,E0204
struct Foo {
foo : Vec<u32>,
}
Here's another example that will fail:
-```compile_fail
+```compile_fail,E0204
#[derive(Copy)]
struct Foo<'a> {
ty: &'a mut bool,
variants does not implement `Copy`. To fix this, you must implement `Copy` for
the mentioned variant. Note that this may not be possible, as in the example of
-```compile_fail
+```compile_fail,E0205
enum Foo {
Bar(Vec<u32>),
Baz,
Here's another example that will fail:
-```compile_fail
+```compile_fail,E0205
#[derive(Copy)]
enum Foo<'a> {
Bar(&'a mut bool),
- Baz
+ Baz,
}
```
examples will fail, because neither `i32` (primitive type) nor `&'static Bar`
(reference to `Bar`) is a struct or enum:
-```compile_fail
+```compile_fail,E0206
type Foo = i32;
impl Copy for Foo { } // error
Suppose we have a struct `Foo` and we would like to define some methods for it.
The following definition leads to a compiler error:
-```compile_fail
+```compile_fail,E0207
struct Foo;
impl<T: Default> Foo {
As another example, suppose we have a `Maker` trait and want to establish a
type `FooMaker` that makes `Foo`s:
-```compile_fail
+```compile_fail,E0207
trait Maker {
type Item;
fn make(&mut self) -> Self::Item;
If `ForeignTrait` is a trait defined in some external crate `foo`, then the
following trait `impl` is an error:
-```compile_fail
-extern crate foo;
-use foo::ForeignTrait;
+```compile_fail,E0210
+extern crate collections;
+use collections::range::RangeArgument;
+
+impl<T> RangeArgument<T> for T { } // error
-impl<T> ForeignTrait for T { } // error
+fn main() {}
```
To work around this, it can be covered with a local type, `MyType`:
A generic type was described using parentheses rather than angle brackets. For
example:
-```compile_fail
+```compile_fail,E0214
fn main() {
let v: Vec(&str) = vec!["foo"];
}
You used an associated type which isn't defined in the trait.
Erroneous code example:
-```compile_fail
+```compile_fail,E0220
trait T1 {
type Bar;
}
An attempt was made to retrieve an associated type, but the type was ambiguous.
For example:
-```compile_fail
+```compile_fail,E0221
trait T1 {}
trait T2 {}
An attempt was made to retrieve an associated type, but the type was ambiguous.
For example:
-```compile_fail
+```compile_fail,E0223
trait MyTrait {type X; }
fn main() {
You attempted to use multiple types as bounds for a closure or trait object.
Rust does not currently support this. A simple example that causes this error:
-```compile_fail
+```compile_fail,E0225
fn main() {
let _: Box<std::io::Read + std::io::Write>;
}
E0232: r##"
The attribute must have a value. Erroneous code example:
-```compile_fail
+```compile_fail,E0232
#![feature(on_unimplemented)]
#[rustc_on_unimplemented] // error: this attribute must have a value
For example, the `Foo` struct below is defined to be generic in `T`, but the
type parameter is missing in the definition of `Bar`:
-```compile_fail
+```compile_fail,E0243
struct Foo<T> { x: T }
struct Bar { x: Foo }
For example, the `Foo` struct below has no type parameters, but is supplied
with two in the definition of `Bar`:
-```compile_fail
+```compile_fail,E0244
struct Foo { x: bool }
struct Bar<S, T> { x: Foo<S, T> }
This error indicates an attempt to use a value where a type is expected. For
example:
-```compile_fail
+```compile_fail,E0248
enum Foo {
Bar(u32)
}
A cross-crate opt-out trait was implemented on something which wasn't a struct
or enum type. Erroneous code example:
-```compile_fail
+```compile_fail,E0321
#![feature(optin_builtin_traits)]
struct Foo;
impl !Sync for Foo {}
-unsafe impl Send for &'static Foo {
+unsafe impl Send for &'static Foo {}
// error: cross-crate traits with a default impl, like `core::marker::Send`,
// can only be implemented for a struct/enum type, not
// `&'static Foo`
An associated const was implemented when another trait item was expected.
Erroneous code example:
-```compile_fail
+```compile_fail,E0323
#![feature(associated_consts)]
trait Foo {
A method was implemented when another trait item was expected. Erroneous
code example:
-```compile_fail
+```compile_fail,E0324
+#![feature(associated_consts)]
+
struct Bar;
trait Foo {
An associated type was implemented when another trait item was expected.
Erroneous code example:
-```compile_fail
+```compile_fail,E0325
+#![feature(associated_consts)]
+
struct Bar;
trait Foo {
Here's an example of this error:
-```compile_fail
+```compile_fail,E0326
+#![feature(associated_consts)]
+
trait Foo {
const BAR: bool;
}
An attempt was made to implement `Drop` on a concrete specialization of a
generic type. An example is shown below:
-```compile_fail
+```compile_fail,E0366
struct Foo<T> {
t: T
}
An attempt was made to implement `Drop` on a specialization of a generic type.
An example is shown below:
-```compile_fail
+```compile_fail,E0367
trait Foo{}
struct MyStruct<T> {
This error indicates that a binary assignment operator like `+=` or `^=` was
applied to a type that doesn't support it. For example:
-```compile_fail
+```compile_fail,E0368
let mut x = 12f32; // error: binary operation `<<` cannot be applied to
// type `f32`
operator for some type `Foo` by implementing the `std::ops::Add` trait for
`Foo`, but you find that using `+=` does not work, as in this example:
-```compile_fail
+```compile_fail,E0368
use std::ops::Add;
struct Foo(u32);
A binary operation was attempted on a type which doesn't support it.
Erroneous code example:
-```compile_fail
+```compile_fail,E0369
let x = 12f32; // error: binary operation `<<` cannot be applied to
// type `f32`
Example:
-```compile_fail
+```compile_fail,E0371
trait Foo { fn foo(&self) { } }
trait Bar: Foo { }
trait Baz: Bar { }
Example of erroneous code:
-```compile_fail
+```compile_fail,E0374
#![feature(coerce_unsized)]
use std::ops::CoerceUnsized;
Example of erroneous code:
-```compile_fail
+```compile_fail,E0375
#![feature(coerce_unsized)]
use std::ops::CoerceUnsized;
Example of erroneous code:
-```compile_fail
+```compile_fail,E0376
#![feature(coerce_unsized)]
use std::ops::CoerceUnsized;
E0390: r##"
You tried to implement methods for a primitive type. Erroneous code example:
-```compile_fail
+```compile_fail,E0390
struct Foo {
x: i32
}
The following example contains a circular dependency between two traits:
-```compile_fail
+```compile_fail,E0391
trait FirstTrait : SecondTrait {
}
This error indicates that a type or lifetime parameter has been declared
but not actually used. Here is an example that demonstrates the error:
-```compile_fail
+```compile_fail,E0392
enum Foo<T> {
- Bar
+ Bar,
}
```
```
enum Foo {
- Bar
+ Bar,
}
```
```
enum Foo<T> {
- Bar(T)
+ Bar(T),
}
```
which the pointed-at data is valid. An initial attempt (below) causes this
error:
-```compile_fail
+```compile_fail,E0392
struct Foo<'a, T> {
- x: *const T
+ x: *const T,
}
```
A type parameter which references `Self` in its default value was not specified.
Example of erroneous code:
-```compile_fail
+```compile_fail,E0393
trait A<T=Self> {}
fn together_we_will_rule_the_galaxy(son: &A) {}
The length of the platform-intrinsic function `simd_shuffle`
wasn't specified. Erroneous code example:
-```compile_fail
+```compile_fail,E0439
#![feature(platform_intrinsics)]
extern "platform-intrinsic" {
A platform-specific intrinsic function has the wrong number of type
parameters. Erroneous code example:
-```compile_fail
+```compile_fail,E0440
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
An unknown platform-specific intrinsic function was used. Erroneous
code example:
-```compile_fail
+```compile_fail,E0441
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
Intrinsic argument(s) and/or return value have the wrong type.
Erroneous code example:
-```compile_fail
+```compile_fail,E0442
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
Intrinsic argument(s) and/or return value have the wrong type.
Erroneous code example:
-```compile_fail
+```compile_fail,E0443
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
A platform-specific intrinsic function has wrong number of arguments.
Erroneous code example:
-```compile_fail
+```compile_fail,E0444
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
The `typeof` keyword is currently reserved but unimplemented.
Erroneous code example:
-```compile_fail
+```compile_fail,E0516
fn main() {
let x: typeof(92) = 92;
}
A non-default implementation was already made on this type so it cannot be
specialized further. Erroneous code example:
-```compile_fail
+```compile_fail,E0520
#![feature(specialization)]
trait SpaceLlama {
E0513, // no type for local variable ..
E0521, // redundant default implementations of trait
E0533, // `{}` does not name a unit variant, unit struct or a constant
+ E0562, // `impl Trait` not allowed outside of function
+ // and inherent method return types
+ E0563, // cannot determine a type for this `impl Trait`: {}
+ E0564, // only named lifetimes are allowed in `impl Trait`,
+ // but `{}` was found in the type `{}`
}
use rustc::infer::TypeOrigin;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::traits::ProjectionMode;
+use rustc::traits::{self, Reveal};
use session::{config, CompileResult};
use util::common::time;
pub stack: RefCell<Vec<collect::AstConvRequest>>,
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+
+ /// Obligations which will have to be checked at the end of
+ /// type-checking, after all functions have been inferred.
+ /// The key is the NodeId of the item the obligations were from.
+ pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
}
// Functions that write types into the node type table
abi: Abi,
span: Span) {
if decl.variadic && abi != Abi::C {
- span_err!(tcx.sess, span, E0045,
+ let mut err = struct_span_err!(tcx.sess, span, E0045,
"variadic function must have C calling convention");
+ err.span_label(span, &("variadics require C calling conventions").to_string())
+ .emit();
}
}
t1: Ty<'tcx>,
t2: Ty<'tcx>)
-> bool {
- ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
+ ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
infcx.report_mismatched_types(origin, t1, t2, err);
false
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
all_traits: RefCell::new(None),
stack: RefCell::new(Vec::new()),
- tcx: tcx
+ tcx: tcx,
+ deferred_obligations: RefCell::new(NodeMap()),
};
// this ensures that later parts of type checking can assume that items
// except according to those terms.
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::subst::Substs;
use std::cell::Cell;
use syntax_pos::Span;
/// computing `object_lifetime_default` (in particular, in legacy
/// modes, it may not be relevant).
fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
+
+ /// If this scope allows anonymized types, return the generics in
+ /// scope, that anonymized types will close over. For example,
+ /// if you have a function like:
+ ///
+ /// fn foo<'a, T>() -> impl Trait { ... }
+ ///
+ /// then, for the rscope that is used when handling the return type,
+ /// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`,
+ /// on which `.fresh_substs(...)` can be used to obtain identity
+ /// Substs for `'a` and `T`, to track them in `TyAnon`. This property
+ /// is controlled by the region scope because it's fine-grained enough
+ /// to allow restriction of anonymized types to the syntactical extent
+ /// of a function's return type.
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ None
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct AnonTypeScope<'a> {
+ generics: &'a ty::Generics<'a>
+}
+
+impl<'a, 'b, 'gcx, 'tcx> AnonTypeScope<'a> {
+ pub fn new(generics: &'a ty::Generics<'a>) -> AnonTypeScope<'a> {
+ AnonTypeScope {
+ generics: generics
+ }
+ }
+
+ pub fn fresh_substs(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
+ use collect::mk_item_substs;
+
+ mk_item_substs(tcx, self.generics)
+ }
+}
+
+/// A scope wrapper which optionally allows anonymized types.
+#[derive(Copy, Clone)]
+pub struct MaybeWithAnonTypes<'a, R> {
+ base_scope: R,
+ anon_scope: Option<AnonTypeScope<'a>>
+}
+
+impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R> {
+ pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope<'a>>) -> Self {
+ MaybeWithAnonTypes {
+ base_scope: base_scope,
+ anon_scope: anon_scope
+ }
+ }
+}
+
+impl<'a, R: RegionScope> RegionScope for MaybeWithAnonTypes<'a, R> {
+ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+ self.base_scope.object_lifetime_default(span)
+ }
+
+ fn anon_regions(&self,
+ span: Span,
+ count: usize)
+ -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
+ self.base_scope.anon_regions(span, count)
+ }
+
+ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
+ self.base_scope.base_object_lifetime_default(span)
+ }
+
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ self.anon_scope
+ }
}
// A scope in which all regions must be explicitly named. This is used
{
self.base_scope.anon_regions(span, count)
}
+
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ self.base_scope.anon_type_scope()
+ }
}
/// A scope which simply shifts the Debruijn index of other scopes
}
}
}
+
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ self.base_scope.anon_type_scope()
+ }
}
/* leaf type -- noop */
}
- ty::TyClosure(..) => {
+ ty::TyClosure(..) | ty::TyAnon(..) => {
bug!("Unexpected closure type in variance computation");
}
use rustc_trans::back::link;
use rustc::middle::cstore;
use rustc::middle::privacy::AccessLevels;
+use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::hir::def::Def;
use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc::hir::fold::Folder;
use rustc::hir::print as pprust;
use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::ty;
// for<'a> Foo(&'a)
PolyTraitRef(Vec<TyParamBound>),
+
+ // impl TraitA+TraitB
+ ImplTrait(Vec<TyParamBound>),
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
}
}
+
+// Poor man's type parameter substitution at HIR level.
+// Used to replace private type aliases in public signatures with their aliased types.
+struct SubstAlias<'a, 'tcx: 'a> {
+ tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>,
+ // Table type parameter definition -> substituted type
+ ty_substs: HashMap<Def, hir::Ty>,
+ // Table node id of lifetime parameter definition -> substituted lifetime
+ lt_substs: HashMap<ast::NodeId, hir::Lifetime>,
+}
+
+impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> {
+ fn fold_ty(&mut self, ty: P<hir::Ty>) -> P<hir::Ty> {
+ if let hir::TyPath(..) = ty.node {
+ let def = self.tcx.expect_def(ty.id);
+ if let Some(new_ty) = self.ty_substs.get(&def).cloned() {
+ return P(new_ty);
+ }
+ }
+ hir::fold::noop_fold_ty(ty, self)
+ }
+ fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime {
+ let def = self.tcx.named_region_map.defs.get(<.id).cloned();
+ match def {
+ Some(DefEarlyBoundRegion(_, _, node_id)) |
+ Some(DefLateBoundRegion(_, node_id)) |
+ Some(DefFreeRegion(_, node_id)) => {
+ if let Some(lt) = self.lt_substs.get(&node_id).cloned() {
+ return lt;
+ }
+ }
+ _ => {}
+ }
+ hir::fold::noop_fold_lifetime(lt, self)
+ }
+}
+
impl Clean<Type> for hir::Ty {
fn clean(&self, cx: &DocContext) -> Type {
use rustc::hir::*;
FixedVector(box ty.clean(cx), n)
},
TyTup(ref tys) => Tuple(tys.clean(cx)),
- TyPath(None, ref p) => {
- resolve_type(cx, p.clean(cx), self.id)
+ TyPath(None, ref path) => {
+ if let Some(tcx) = cx.tcx_opt() {
+ // Substitute private type aliases
+ let def = tcx.expect_def(self.id);
+ if let Def::TyAlias(def_id) = def {
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ if !cx.access_levels.borrow().is_exported(def_id) {
+ let item = tcx.map.expect_item(node_id);
+ if let hir::ItemTy(ref ty, ref generics) = item.node {
+ let provided_params = &path.segments.last().unwrap().parameters;
+ let mut ty_substs = HashMap::new();
+ let mut lt_substs = HashMap::new();
+ for (i, ty_param) in generics.ty_params.iter().enumerate() {
+ let ty_param_def = tcx.expect_def(ty_param.id);
+ if let Some(ty) = provided_params.types().get(i).cloned()
+ .cloned() {
+ ty_substs.insert(ty_param_def, ty.unwrap());
+ } else if let Some(default) = ty_param.default.clone() {
+ ty_substs.insert(ty_param_def, default.unwrap());
+ }
+ }
+ for (i, lt_param) in generics.lifetimes.iter().enumerate() {
+ if let Some(lt) = provided_params.lifetimes().get(i)
+ .cloned()
+ .cloned() {
+ lt_substs.insert(lt_param.lifetime.id, lt);
+ }
+ }
+ let mut subst_alias = SubstAlias {
+ tcx: &tcx,
+ ty_substs: ty_substs,
+ lt_substs: lt_substs
+ };
+ return subst_alias.fold_ty(ty.clone()).clean(cx);
+ }
+ }
+ }
+ }
+ }
+ resolve_type(cx, path.clean(cx), self.id)
}
TyPath(Some(ref qself), ref p) => {
let mut segments: Vec<_> = p.segments.clone().into();
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyPolyTraitRef(ref bounds) => PolyTraitRef(bounds.clean(cx)),
+ TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
TyInfer => Infer,
TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
}
ty::TyParam(ref p) => Generic(p.name.to_string()),
+ ty::TyAnon(def_id, substs) => {
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let item_predicates = cx.tcx().lookup_predicates(def_id);
+ let substs = cx.tcx().lift(&substs).unwrap();
+ let bounds = item_predicates.instantiate(cx.tcx(), substs);
+ let predicates = bounds.predicates.into_vec();
+ ImplTrait(predicates.into_iter().filter_map(|predicate| {
+ predicate.to_opt_poly_trait_ref().clean(cx)
+ }).collect())
+ }
+
ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton)
ty::TyInfer(..) => panic!("TyInfer"),
}
Ok(())
}
+ clean::ImplTrait(ref bounds) => {
+ write!(f, "impl ")?;
+ for (i, bound) in bounds.iter().enumerate() {
+ if i != 0 {
+ write!(f, " + ")?;
+ }
+ write!(f, "{}", *bound)?;
+ }
+ Ok(())
+ }
// It's pretty unsightly to look at `<A as B>::C` in output, and
// we've got hyperlinking on our side, so try to avoid longer
// notation as much as possible by making `C` a hyperlink to trait
/// Ok("/home/alex/bar")
/// ```
///
-/// This sort of behavior has been known to [lead to privledge escalation] when
+/// This sort of behavior has been known to [lead to privilege escalation] when
/// used incorrectly, for example.
///
-/// [lead to privledge escalation]: http://securityvulns.com/Wdocument183.html
+/// [lead to privilege escalation]: http://securityvulns.com/Wdocument183.html
///
/// # Examples
///
///
/// extern { fn my_string() -> *const c_char; }
///
-/// fn main() {
-/// unsafe {
-/// let slice = CStr::from_ptr(my_string());
-/// println!("string length: {}", slice.to_bytes().len());
-/// }
+/// unsafe {
+/// let slice = CStr::from_ptr(my_string());
+/// println!("string length: {}", slice.to_bytes().len());
/// }
/// ```
///
/// unsafe { work_with(data.as_ptr()) }
/// }
///
-/// fn main() {
-/// let s = CString::new("data data data data").unwrap();
-/// work(&s);
-/// }
+/// let s = CString::new("data data data data").unwrap();
+/// work(&s);
/// ```
///
/// Converting a foreign C string into a Rust `String`
/// }
/// }
///
-/// fn main() {
-/// println!("string: {}", my_string_safe());
-/// }
+/// println!("string: {}", my_string_safe());
/// ```
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// extern { fn puts(s: *const c_char); }
///
- /// fn main() {
- /// let to_print = CString::new("Hello!").unwrap();
- /// unsafe {
- /// puts(to_print.as_ptr());
- /// }
+ /// let to_print = CString::new("Hello!").unwrap();
+ /// unsafe {
+ /// puts(to_print.as_ptr());
/// }
/// ```
///
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
+#![cfg_attr(test, feature(update_panic_count))]
// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
// might be unavailable or disabled
/// ```
#[stable(feature = "resume_unwind", since = "1.9.0")]
pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
- panicking::rust_panic(payload)
+ panicking::update_count_then_panic(payload)
}
use io::prelude::*;
use any::Any;
-use cell::Cell;
use cell::RefCell;
use fmt;
use intrinsics;
use mem;
+use ptr;
use raw;
-use sys_common::rwlock::RWLock;
use sys::stdio::Stderr;
+use sys_common::rwlock::RWLock;
use sys_common::thread_info;
use sys_common::util;
use thread;
}
}
-thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
-
// Binary interface to the panic runtime that the standard library depends on.
//
// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
// for this panic. Otherwise only print it if logging is enabled.
#[cfg(any(not(cargobuild), feature = "backtrace"))]
let log_backtrace = {
- let panics = PANIC_COUNT.with(|c| c.get());
+ let panics = update_panic_count(0);
panics >= 2 || backtrace::log_enabled()
};
}
}
+
+#[cfg(not(test))]
+#[doc(hidden)]
+#[unstable(feature = "update_panic_count", issue = "0")]
+pub fn update_panic_count(amt: isize) -> usize {
+ use cell::Cell;
+ thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+ PANIC_COUNT.with(|c| {
+ let next = (c.get() as isize + amt) as usize;
+ c.set(next);
+ return next
+ })
+}
+
+#[cfg(test)]
+pub use realstd::rt::update_panic_count;
+
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
- let mut slot = None;
- let mut f = Some(f);
- let ret = PANIC_COUNT.with(|s| {
- let prev = s.get();
- s.set(0);
-
- let mut to_run = || {
- slot = Some(f.take().unwrap()());
- };
- let fnptr = get_call(&mut to_run);
- let dataptr = &mut to_run as *mut _ as *mut u8;
- let mut any_data = 0;
- let mut any_vtable = 0;
- let fnptr = mem::transmute::<fn(&mut _), fn(*mut u8)>(fnptr);
- let r = __rust_maybe_catch_panic(fnptr,
- dataptr,
- &mut any_data,
- &mut any_vtable);
- s.set(prev);
-
- if r == 0 {
- Ok(())
- } else {
- Err(mem::transmute(raw::TraitObject {
- data: any_data as *mut _,
- vtable: any_vtable as *mut _,
- }))
- }
- });
+ struct Data<F, R> {
+ f: F,
+ r: R,
+ }
- return ret.map(|()| {
- slot.take().unwrap()
- });
+ // We do some sketchy operations with ownership here for the sake of
+ // performance. The `Data` structure is never actually fully valid, but
+ // instead it always contains at least one uninitialized field. We can only
+ // pass pointers down to `__rust_maybe_catch_panic` (can't pass objects by
+ // value), so we do all the ownership tracking here manully.
+ //
+ // Note that this is all invalid if any of these functions unwind, but the
+ // whole point of this function is to prevent that! As a result we go
+ // through a transition where:
+ //
+ // * First, only the closure we're going to call is initialized. The return
+ // value is uninitialized.
+ // * When we make the function call, the `do_call` function below, we take
+ // ownership of the function pointer, replacing it with uninitialized
+ // data. At this point the `Data` structure is entirely uninitialized, but
+ // it won't drop due to an unwind because it's owned on the other side of
+ // the catch panic.
+ // * If the closure successfully returns, we write the return value into the
+ // data's return slot. Note that `ptr::write` is used as it's overwriting
+ // uninitialized data.
+ // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
+ // in one of two states:
+ //
+ // 1. The closure didn't panic, in which case the return value was
+ // filled in. We have to be careful to `forget` the closure,
+ // however, as ownership was passed to the `do_call` function.
+ // 2. The closure panicked, in which case the return value wasn't
+ // filled in. In this case the entire `data` structure is invalid,
+ // so we forget the entire thing.
+ //
+ // Once we stack all that together we should have the "most efficient'
+ // method of calling a catch panic whilst juggling ownership.
+ let mut any_data = 0;
+ let mut any_vtable = 0;
+ let mut data = Data {
+ f: f,
+ r: mem::uninitialized(),
+ };
- fn get_call<F: FnMut()>(_: &mut F) -> fn(&mut F) {
- call
- }
+ let r = __rust_maybe_catch_panic(do_call::<F, R>,
+ &mut data as *mut _ as *mut u8,
+ &mut any_data,
+ &mut any_vtable);
+
+ return if r == 0 {
+ let Data { f, r } = data;
+ mem::forget(f);
+ debug_assert!(update_panic_count(0) == 0);
+ Ok(r)
+ } else {
+ mem::forget(data);
+ update_panic_count(-1);
+ debug_assert!(update_panic_count(0) == 0);
+ Err(mem::transmute(raw::TraitObject {
+ data: any_data as *mut _,
+ vtable: any_vtable as *mut _,
+ }))
+ };
- fn call<F: FnMut()>(f: &mut F) {
- f()
+ fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+ unsafe {
+ let data = data as *mut Data<F, R>;
+ let f = ptr::read(&mut (*data).f);
+ ptr::write(&mut (*data).r, f());
+ }
}
}
/// Determines whether the current thread is unwinding because of panic.
pub fn panicking() -> bool {
- PANIC_COUNT.with(|c| c.get() != 0)
+ update_panic_count(0) != 0
}
/// Entry point of panic from the libcore crate.
file_line: &(&'static str, u32)) -> ! {
let (file, line) = *file_line;
- let panics = PANIC_COUNT.with(|c| {
- let prev = c.get();
- c.set(prev + 1);
- prev
- });
+ let panics = update_panic_count(1);
// If this is the third nested call (e.g. panics == 2, this is 0-indexed),
// the panic hook probably triggered the last panic, otherwise the
// double-panic check would have aborted the process. In this case abort the
// process real quickly as we don't want to try calling it again as it'll
// probably just panic again.
- if panics > 1 {
+ if panics > 2 {
util::dumb_print(format_args!("thread panicked while processing \
panic. aborting.\n"));
unsafe { intrinsics::abort() }
HOOK_LOCK.read_unlock();
}
- if panics > 0 {
+ if panics > 1 {
// If a thread panics while it's already unwinding then we
// have limited options. Currently our preference is to
// just abort. In the future we may consider resuming
rust_panic(msg)
}
+/// Shim around rust_panic. Called by resume_unwind.
+pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
+ update_panic_count(1);
+ rust_panic(msg)
+}
+
/// A private no-mangle function on which to slap yer breakpoints.
#[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
// Reexport some of our utilities which are expected by other crates.
-pub use panicking::{begin_panic, begin_panic_fmt};
+pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
#[cfg(not(test))]
#[lang = "start"]
})
}
- /// Returns true iff the address is unnamed.
+ /// Returns true if and only if the address is unnamed.
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn is_unnamed(&self) -> bool {
if let AddressKind::Unnamed = self.address() {
}
}
- #[cfg(not(target_os = "nacl"))]
+ #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
unsafe fn reset_sigpipe() {
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
}
- #[cfg(target_os = "nacl")]
+ #[cfg(any(target_os = "nacl", target_os = "emscripten"))]
unsafe fn reset_sigpipe() {}
}
#[cfg(any(target_os = "android",
target_os = "ios",
- target_os = "nacl"))]
+ target_os = "nacl",
+ target_os = "emscripten"))]
unsafe fn fallback() -> Option<OsString> { None }
#[cfg(not(any(target_os = "android",
target_os = "ios",
- target_os = "nacl")))]
+ target_os = "nacl",
+ target_os = "emscripten")))]
unsafe fn fallback() -> Option<OsString> {
#[cfg(not(target_os = "solaris"))]
unsafe fn getpwduid_r(me: libc::uid_t, passwd: &mut libc::passwd,
}
#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "emscripten"))]
+ target_os = "android"))]
pub fn set_name(name: &CStr) {
const PR_SET_NAME: libc::c_int = 15;
// pthread wrapper only appeared in glibc 2.12, so we use syscall
name.as_ptr() as *mut libc::c_void);
}
}
- #[cfg(any(target_env = "newlib", target_os = "solaris"))]
+ #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
pub fn set_name(_name: &CStr) {
- // Newlib and Illumos has no way to set a thread name.
+ // Newlib, Illumos and Emscripten have no way to set a thread name.
}
pub fn sleep(dur: Duration) {
ObjectSum(P<Ty>, TyParamBounds),
/// A type like `for<'a> Foo<&'a Bar>`
PolyTraitRef(TyParamBounds),
+ /// An `impl TraitA+TraitB` type.
+ ImplTrait(TyParamBounds),
/// No-op; kept solely so that we can pretty-print faithfully
Paren(P<Ty>),
/// Unused for now
/// Returns a `Folder` for deeply expanding all macros in an AST node.
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
- expand::MacroExpander::new(self)
+ expand::MacroExpander::new(self, false, false)
}
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{Block, Crate, Ident, Mac_, Name, PatKind};
+use ast::{Block, Crate, Ident, Mac_, PatKind};
use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
use ast;
use ext::hygiene::Mark;
use visit::Visitor;
use std_inject;
-use std::collections::HashSet;
-
// A trait for AST nodes and AST node lists into which macro invocations may expand.
trait MacroGenerable: Sized {
// Expand the given MacResult using its appropriate `make_*` method.
}
});
- // DON'T mark before expansion.
- fld.cx.insert_macro(ast::MacroDef {
+ let def = ast::MacroDef {
ident: ident,
id: ast::DUMMY_NODE_ID,
span: call_site,
export: attr::contains_name(&attrs, "macro_export"),
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
attrs: attrs,
- });
+ };
- // macro_rules! has a side effect but expands to nothing.
- Some(Box::new(MacroScopePlaceholder))
+ fld.cx.insert_macro(def.clone());
+
+ // macro_rules! has a side effect, but expands to nothing.
+ // If keep_macs is true, expands to a MacEager::items instead.
+ if fld.keep_macs {
+ Some(MacEager::items(SmallVector::one(P(ast::Item {
+ ident: def.ident,
+ attrs: def.attrs.clone(),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Mac(ast::Mac {
+ span: def.span,
+ node: ast::Mac_ {
+ path: path.clone(),
+ tts: def.body.clone(),
+ }
+ }),
+ vis: ast::Visibility::Inherited,
+ span: def.span,
+ }))))
+ } else {
+ Some(Box::new(MacroScopePlaceholder))
+ }
}
MultiDecorator(..) | MultiModifier(..) => {
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
let configured = marked.fold_with(&mut fld.strip_unconfigured());
fld.load_macros(&configured);
- let fully_expanded = configured.fold_with(fld);
+
+ let fully_expanded = if fld.single_step {
+ configured
+ } else {
+ configured.fold_with(fld)
+ };
+
fld.cx.bt_pop();
fully_expanded
}
/// A tree-folder that performs macro expansion
pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>,
+ pub single_step: bool,
+ pub keep_macs: bool,
}
impl<'a, 'b> MacroExpander<'a, 'b> {
- pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
- MacroExpander { cx: cx }
+ pub fn new(cx: &'a mut ExtCtxt<'b>,
+ single_step: bool,
+ keep_macs: bool) -> MacroExpander<'a, 'b> {
+ MacroExpander {
+ cx: cx,
+ single_step: single_step,
+ keep_macs: keep_macs
+ }
}
fn strip_unconfigured(&mut self) -> StripUnconfigured {
}
}
-pub fn expand_crate(mut cx: ExtCtxt,
+pub fn expand_crate(cx: &mut ExtCtxt,
user_exts: Vec<NamedSyntaxExtension>,
- mut c: Crate) -> (Crate, HashSet<Name>) {
+ c: Crate) -> Crate {
+ let mut expander = MacroExpander::new(cx, false, false);
+ expand_crate_with_expander(&mut expander, user_exts, c)
+}
+
+// Expands crate using supplied MacroExpander - allows for
+// non-standard expansion behaviour (e.g. step-wise).
+pub fn expand_crate_with_expander(expander: &mut MacroExpander,
+ user_exts: Vec<NamedSyntaxExtension>,
+ mut c: Crate) -> Crate {
if std_inject::no_core(&c) {
- cx.crate_root = None;
+ expander.cx.crate_root = None;
} else if std_inject::no_std(&c) {
- cx.crate_root = Some("core");
+ expander.cx.crate_root = Some("core");
} else {
- cx.crate_root = Some("std");
+ expander.cx.crate_root = Some("std");
}
- let ret = {
- let mut expander = MacroExpander::new(&mut cx);
- for (name, extension) in user_exts {
- expander.cx.syntax_env.insert(name, extension);
- }
+ // User extensions must be added before expander.load_macros is called,
+ // so that macros from external crates shadow user defined extensions.
+ for (name, extension) in user_exts {
+ expander.cx.syntax_env.insert(name, extension);
+ }
- let items = SmallVector::many(c.module.items);
- expander.load_macros(&items);
- c.module.items = items.into();
+ let items = SmallVector::many(c.module.items);
+ expander.load_macros(&items);
+ c.module.items = items.into();
- let err_count = cx.parse_sess.span_diagnostic.err_count();
- let mut ret = expander.fold_crate(c);
- ret.exported_macros = expander.cx.exported_macros.clone();
+ let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
+ let mut ret = expander.fold_crate(c);
+ ret.exported_macros = expander.cx.exported_macros.clone();
- if cx.parse_sess.span_diagnostic.err_count() > err_count {
- cx.parse_sess.span_diagnostic.abort_if_errors();
- }
+ if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
+ expander.cx.parse_sess.span_diagnostic.abort_if_errors();
+ }
- ret
- };
- return (ret, cx.syntax_env.names);
+ ret
}
// A Marker adds the given mark to the syntax context and
Vec::new(), &sess).unwrap();
// should fail:
let mut loader = DummyMacroLoader;
- let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
- expand_crate(ecx, vec![], crate_ast);
+ let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+ expand_crate(&mut ecx, vec![], crate_ast);
}
// make sure that macros can't escape modules
src,
Vec::new(), &sess).unwrap();
let mut loader = DummyMacroLoader;
- let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
- expand_crate(ecx, vec![], crate_ast);
+ let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+ expand_crate(&mut ecx, vec![], crate_ast);
}
// macro_use modules should allow macros to escape
src,
Vec::new(), &sess).unwrap();
let mut loader = DummyMacroLoader;
- let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
- expand_crate(ecx, vec![], crate_ast);
+ let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+ expand_crate(&mut ecx, vec![], crate_ast);
}
fn expand_crate_str(crate_str: String) -> ast::Crate {
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
// the cfg argument actually does matter, here...
let mut loader = DummyMacroLoader;
- let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
- expand_crate(ecx, vec![], crate_ast).0
+ let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
+ expand_crate(&mut ecx, vec![], crate_ast)
}
#[test] fn macro_tokens_should_match(){
use self::TokenTreeOrTokenTreeVec::*;
use ast;
-use ast::{Name, Ident};
+use ast::Ident;
use syntax_pos::{self, BytePos, mk_sp, Span};
use codemap::Spanned;
use errors::FatalError;
}
pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
- -> ParseResult<HashMap<Name, Rc<NamedMatch>>> {
+ -> ParseResult<HashMap<Ident, Rc<NamedMatch>>> {
fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc<NamedMatch>],
- ret_val: &mut HashMap<Name, Rc<NamedMatch>>, idx: &mut usize)
+ ret_val: &mut HashMap<Ident, Rc<NamedMatch>>, idx: &mut usize)
-> Result<(), (syntax_pos::Span, String)> {
match *m {
TokenTree::Sequence(_, ref seq) => {
}
}
TokenTree::Token(sp, MatchNt(bind_name, _)) => {
- match ret_val.entry(bind_name.name) {
+ match ret_val.entry(bind_name) {
Vacant(spot) => {
spot.insert(res[*idx].clone());
*idx += 1;
Error(syntax_pos::Span, String)
}
-pub type NamedParseResult = ParseResult<HashMap<Name, Rc<NamedMatch>>>;
+pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
pub type PositionalParseResult = ParseResult<Vec<Rc<NamedMatch>>>;
/// Perform a token equality check, ignoring syntax context (that is, an
let mut valid = true;
// Extract the arguments:
- let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
+ let lhses = match **argument_map.get(&lhs_nm).unwrap() {
MatchedSeq(ref s, _) => {
s.iter().map(|m| match **m {
MatchedNonterminal(NtTT(ref tt)) => {
_ => cx.span_bug(def.span, "wrong-structured lhs")
};
- let rhses = match **argument_map.get(&rhs_nm.name).unwrap() {
+ let rhses = match **argument_map.get(&rhs_nm).unwrap() {
MatchedSeq(ref s, _) => {
s.iter().map(|m| match **m {
MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(),
// except according to those terms.
use self::LockstepIterSize::*;
-use ast::{Ident, Name};
+use ast::Ident;
use syntax_pos::{Span, DUMMY_SP};
use errors::{Handler, DiagnosticBuilder};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
/// the unzipped tree:
stack: Vec<TtFrame>,
/* for MBE-style macro transcription */
- interpolations: HashMap<Name, Rc<NamedMatch>>,
+ interpolations: HashMap<Ident, Rc<NamedMatch>>,
imported_from: Option<Ident>,
// Some => return imported_from as the next token
/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
/// (and should) be None.
pub fn new_tt_reader(sp_diag: &Handler,
- interp: Option<HashMap<Name, Rc<NamedMatch>>>,
+ interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
imported_from: Option<Ident>,
src: Vec<tokenstream::TokenTree>)
-> TtReader {
/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
/// (and should) be None.
pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
- interp: Option<HashMap<Name, Rc<NamedMatch>>>,
+ interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
imported_from: Option<Ident>,
src: Vec<tokenstream::TokenTree>,
desugar_doc_comments: bool)
}
fn lookup_cur_matched(r: &TtReader, name: Ident) -> Option<Rc<NamedMatch>> {
- let matched_opt = r.interpolations.get(&name.name).cloned();
+ let matched_opt = r.interpolations.get(&name).cloned();
matched_opt.map(|s| lookup_cur_matched_by_matched(r, s))
}
(active, cfg_target_has_atomic, "1.9.0", Some(32976)),
// Allows `..` in tuple (struct) patterns
- (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627))
+ (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
+
+ // Allows `impl Trait` in function return types.
+ (active, conservative_impl_trait, "1.12.0", Some(34511)),
+
+ // Allows tuple structs and variants in more contexts,
+ // Permits numeric fields in struct expressions and patterns.
+ (active, relaxed_adts, "1.12.0", Some(35626))
);
declare_features! (
ast::TyKind::BareFn(ref bare_fn_ty) => {
self.check_abi(bare_fn_ty.abi, ty.span);
}
+ ast::TyKind::ImplTrait(..) => {
+ gate_feature_post!(&self, conservative_impl_trait, ty.span,
+ "`impl Trait` is experimental");
+ }
_ => {}
}
visit::walk_ty(self, ty)
}
PatKind::TupleStruct(_, ref fields, ddpos)
if ddpos.is_none() && fields.is_empty() => {
- self.context.span_handler.struct_span_err(pattern.span,
- "nullary enum variants are written with \
- no trailing `( )`").emit();
+ gate_feature_post!(&self, relaxed_adts, pattern.span,
+ "empty tuple structs patterns are unstable");
}
_ => {}
}
visit::walk_impl_item(self, ii);
}
+ fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
+ _: &ast::Generics, _: NodeId, span: Span) {
+ if vdata.fields().is_empty() {
+ if vdata.is_tuple() {
+ gate_feature_post!(&self, relaxed_adts, span,
+ "empty tuple structs and enum variants are unstable, \
+ use unit structs and enum variants instead");
+ }
+ }
+
+ visit::walk_struct_def(self, vdata)
+ }
+
fn visit_vis(&mut self, vis: &ast::Visibility) {
let span = match *vis {
ast::Visibility::Crate(span) => span,
TyKind::PolyTraitRef(bounds) => {
TyKind::PolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
}
+ TyKind::ImplTrait(bounds) => {
+ TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+ }
TyKind::Mac(mac) => {
TyKind::Mac(fld.fold_mac(mac))
}
pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> {
/*
Parses whatever can come after a `for` keyword in a type.
- The `for` has already been consumed.
+ The `for` hasn't been consumed.
Deprecated:
}
}
+ pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> {
+ /*
+ Parses whatever can come after a `impl` keyword in a type.
+ The `impl` has already been consumed.
+ */
+
+ let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?;
+
+ if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
+ let last_span = self.last_span;
+ self.span_err(last_span, "at least one trait must be specified");
+ }
+
+ Ok(ast::TyKind::ImplTrait(bounds))
+ }
+
+
pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?))
}
self.parse_borrowed_pointee()?
} else if self.check_keyword(keywords::For) {
self.parse_for_in_type()?
+ } else if self.eat_keyword(keywords::Impl) {
+ self.parse_impl_trait_type()?
} else if self.token_is_bare_fn_keyword() {
// BARE FUNCTION
self.parse_ty_bare_fn(Vec::new())?
}
}
+ pub fn parse_field_name(&mut self) -> PResult<'a, Ident> {
+ if let token::Literal(token::Integer(name), None) = self.token {
+ self.bump();
+ Ok(Ident::with_empty_ctxt(name))
+ } else {
+ self.parse_ident()
+ }
+ }
+
/// Parse ident COLON expr
pub fn parse_field(&mut self) -> PResult<'a, Field> {
let lo = self.span.lo;
- let i = self.parse_ident()?;
+ let i = self.parse_field_name()?;
let hi = self.last_span.hi;
self.expect(&token::Colon)?;
let e = self.parse_expr()?;
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
// Parsing a pattern of the form "fieldname: pat"
- let fieldname = self.parse_ident()?;
+ let fieldname = self.parse_field_name()?;
self.bump();
let pat = self.parse_pat()?;
hi = pat.span.hi;
}
/// Parse a structure field
- fn parse_name_and_ty(&mut self, pr: Visibility,
- attrs: Vec<Attribute> ) -> PResult<'a, StructField> {
- let lo = match pr {
- Visibility::Inherited => self.span.lo,
- _ => self.last_span.lo,
- };
+ fn parse_name_and_ty(&mut self,
+ lo: BytePos,
+ vis: Visibility,
+ attrs: Vec<Attribute>)
+ -> PResult<'a, StructField> {
let name = self.parse_ident()?;
self.expect(&token::Colon)?;
let ty = self.parse_ty_sum()?;
Ok(StructField {
span: mk_sp(lo, self.last_span.hi),
ident: Some(name),
- vis: pr,
+ vis: vis,
id: ast::DUMMY_NODE_ID,
ty: ty,
attrs: attrs,
/// Parse a structure field declaration
pub fn parse_single_struct_field(&mut self,
+ lo: BytePos,
vis: Visibility,
attrs: Vec<Attribute> )
-> PResult<'a, StructField> {
- let a_var = self.parse_name_and_ty(vis, attrs)?;
+ let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
match self.token {
token::Comma => {
self.bump();
/// Parse an element of a struct definition
fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
let attrs = self.parse_outer_attributes()?;
+ let lo = self.span.lo;
let vis = self.parse_visibility(true)?;
- self.parse_single_struct_field(vis, attrs)
+ self.parse_single_struct_field(lo, vis, attrs)
}
// If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`)
ast::TyKind::PolyTraitRef(ref bounds) => {
try!(self.print_bounds("", &bounds[..]));
}
+ ast::TyKind::ImplTrait(ref bounds) => {
+ try!(self.print_bounds("impl ", &bounds[..]));
+ }
ast::TyKind::FixedLengthVec(ref ty, ref v) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&ty));
ts: InternalTS,
}
+// This indicates the maximum size for a leaf in the concatenation algorithm.
+// If two leafs will be collectively smaller than this, they will be merged.
+// If a leaf is larger than this, it will be concatenated at the top.
+const LEAF_SIZE : usize = 32;
+
// NB If Leaf access proves to be slow, inroducing a secondary Leaf without the bounds
// for unsliced Leafs may lead to some performance improvemenet.
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
}
}
}
+
+ fn to_vec(&self) -> Vec<&TokenTree> {
+ let mut res = Vec::with_capacity(self.len());
+ fn traverse_and_append<'a>(res: &mut Vec<&'a TokenTree>, ts: &'a InternalTS) {
+ match *ts {
+ InternalTS::Empty(..) => {},
+ InternalTS::Leaf { ref tts, offset, len, .. } => {
+ let mut to_app = tts[offset..offset + len].iter().collect();
+ res.append(&mut to_app);
+ }
+ InternalTS::Node { ref left, ref right, .. } => {
+ traverse_and_append(res, left);
+ traverse_and_append(res, right);
+ }
+ }
+ }
+ traverse_and_append(&mut res, self);
+ res
+ }
+
+ fn to_tts(&self) -> Vec<TokenTree> {
+ self.to_vec().into_iter().cloned().collect::<Vec<TokenTree>>()
+ }
+
+ // Returns an internal node's children.
+ fn children(&self) -> Option<(Rc<InternalTS>, Rc<InternalTS>)> {
+ match *self {
+ InternalTS::Node { ref left, ref right, .. } => Some((left.clone(), right.clone())),
+ _ => None,
+ }
+ }
}
/// TokenStream operators include basic destructuring, boolean operations, `maybe_...`
///
/// `maybe_path_prefix("a::b::c(a,b,c).foo()") -> (a::b::c, "(a,b,c).foo()")`
impl TokenStream {
+ // Construct an empty node with a dummy span.
pub fn mk_empty() -> TokenStream {
TokenStream { ts: InternalTS::Empty(DUMMY_SP) }
}
+ // Construct an empty node with the provided span.
fn mk_spanned_empty(sp: Span) -> TokenStream {
TokenStream { ts: InternalTS::Empty(sp) }
}
+ // Construct a leaf node with a 0 offset and length equivalent to the input.
fn mk_leaf(tts: Rc<Vec<TokenTree>>, sp: Span) -> TokenStream {
let len = tts.len();
TokenStream {
}
}
+ // Construct a leaf node with the provided values.
fn mk_sub_leaf(tts: Rc<Vec<TokenTree>>, offset: usize, len: usize, sp: Span) -> TokenStream {
TokenStream {
ts: InternalTS::Leaf {
}
}
+ // Construct an internal node with the provided values.
fn mk_int_node(left: Rc<InternalTS>,
right: Rc<InternalTS>,
len: usize,
}
}
- /// Concatenates two TokenStreams into a new TokenStream
+ /// Concatenates two TokenStreams into a new TokenStream.
pub fn concat(left: TokenStream, right: TokenStream) -> TokenStream {
- let new_len = left.len() + right.len();
- let new_span = combine_spans(left.span(), right.span());
- TokenStream::mk_int_node(Rc::new(left.ts), Rc::new(right.ts), new_len, new_span)
+ // This internal procedure performs 'aggressive compacting' during concatenation as
+ // follows:
+ // - If the nodes' combined total total length is less than 32, we copy both of
+ // them into a new vector and build a new leaf node.
+ // - If one node is an internal node and the other is a 'small' leaf (length<32),
+ // we recur down the internal node on the appropriate side.
+ // - Otherwise, we construct a new internal node that points to them as left and
+ // right.
+ fn concat_internal(left: Rc<InternalTS>, right: Rc<InternalTS>) -> TokenStream {
+ let llen = left.len();
+ let rlen = right.len();
+ let len = llen + rlen;
+ let span = combine_spans(left.span(), right.span());
+ if len <= LEAF_SIZE {
+ let mut new_vec = left.to_tts();
+ let mut rvec = right.to_tts();
+ new_vec.append(&mut rvec);
+ return TokenStream::mk_leaf(Rc::new(new_vec), span);
+ }
+
+ match (left.children(), right.children()) {
+ (Some((lleft, lright)), None) => {
+ if rlen <= LEAF_SIZE {
+ let new_right = concat_internal(lright, right);
+ TokenStream::mk_int_node(lleft, Rc::new(new_right.ts), len, span)
+ } else {
+ TokenStream::mk_int_node(left, right, len, span)
+ }
+ }
+ (None, Some((rleft, rright))) => {
+ if rlen <= LEAF_SIZE {
+ let new_left = concat_internal(left, rleft);
+ TokenStream::mk_int_node(Rc::new(new_left.ts), rright, len, span)
+ } else {
+ TokenStream::mk_int_node(left, right, len, span)
+ }
+ }
+ (_, _) => TokenStream::mk_int_node(left, right, len, span),
+ }
+ }
+
+ if left.is_empty() {
+ right
+ } else if right.is_empty() {
+ left
+ } else {
+ concat_internal(Rc::new(left.ts), Rc::new(right.ts))
+ }
}
/// Indicate if the TokenStream is empty.
/// Convert a TokenStream into a vector of borrowed TokenTrees.
pub fn to_vec(&self) -> Vec<&TokenTree> {
- fn internal_to_vec(ts: &InternalTS) -> Vec<&TokenTree> {
- match *ts {
- InternalTS::Empty(..) => Vec::new(),
- InternalTS::Leaf { ref tts, offset, len, .. } => {
- tts[offset..offset + len].iter().collect()
- }
- InternalTS::Node { ref left, ref right, .. } => {
- let mut v1 = internal_to_vec(left);
- let mut v2 = internal_to_vec(right);
- v1.append(&mut v2);
- v1
- }
- }
- }
- internal_to_vec(&self.ts)
+ self.ts.to_vec()
}
/// Convert a TokenStream into a vector of TokenTrees (by cloning the TokenTrees).
/// (This operation is an O(n) deep copy of the underlying structure.)
pub fn to_tts(&self) -> Vec<TokenTree> {
- self.to_vec().into_iter().cloned().collect::<Vec<TokenTree>>()
+ self.ts.to_tts()
}
/// Return the TokenStream's span.
TyKind::PolyTraitRef(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
+ TyKind::ImplTrait(ref bounds) => {
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ }
TyKind::Typeof(ref expression) => {
visitor.visit_expr(expression)
}
pub nocapture: bool,
pub color: ColorConfig,
pub quiet: bool,
+ pub test_threads: Option<usize>,
}
impl TestOpts {
nocapture: false,
color: AutoColor,
quiet: false,
+ test_threads: None,
}
}
}
of stdout", "PATH"),
getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \
task, allow printing directly"),
+ getopts::optopt("", "test-threads", "Number of threads used for running tests \
+ in parallel", "n_threads"),
getopts::optflag("q", "quiet", "Display one character per test instead of one line"),
getopts::optopt("", "color", "Configure coloring of output:
auto = colorize if stdout is a tty and tests are run on serially (default);
tests whose names contain the filter are run.
By default, all tests are run in parallel. This can be altered with the
-RUST_TEST_THREADS environment variable when running tests (set it to 1).
+--test-threads flag or the RUST_TEST_THREADS environment variable when running
+tests (set it to 1).
All tests have their standard output and standard error captured by default.
This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
};
}
+ let test_threads = match matches.opt_str("test-threads") {
+ Some(n_str) =>
+ match n_str.parse::<usize>() {
+ Ok(n) => Some(n),
+ Err(e) =>
+ return Some(Err(format!("argument for --test-threads must be a number > 0 \
+ (error: {})", e)))
+ },
+ None =>
+ None,
+ };
+
let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
Some("auto") | None => AutoColor,
Some("always") => AlwaysColor,
nocapture: nocapture,
color: color,
quiet: quiet,
+ test_threads: test_threads,
};
Some(Ok(test_opts))
}
});
- // It's tempting to just spawn all the tests at once, but since we have
- // many tests that run in other processes we would be making a big mess.
- let concurrency = get_concurrency();
+ let concurrency = match opts.test_threads {
+ Some(n) => n,
+ None => get_concurrency(),
+ };
let mut remaining = filtered_tests;
remaining.reverse();
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "asmjs")]
-// FIXME: Copied from arm. Need to confirm.
pub const unwinder_private_data_size: usize = 20;
#[repr(C)]
-Subproject commit d1cc48989b13780f21c408fef17dceb104a09c9d
+Subproject commit 786aad117be48547f4ca50fae84c4879fa992d4d
}
}
+#if LLVM_RUSTLLVM
+/// getLongestEntryLength - Return the length of the longest entry in the table.
+///
+static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) {
+ size_t MaxLen = 0;
+ for (auto &I : Table)
+ MaxLen = std::max(MaxLen, std::strlen(I.Key));
+ return MaxLen;
+}
+
+extern "C" void
+LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
+ const TargetMachine *Target = unwrap(TM);
+ const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
+ const ArrayRef<SubtargetFeatureKV> CPUTable = MCInfo->getCPUTable();
+ unsigned MaxCPULen = getLongestEntryLength(CPUTable);
+
+ printf("Available CPUs for this target:\n");
+ for (auto &CPU : CPUTable)
+ printf(" %-*s - %s.\n", MaxCPULen, CPU.Key, CPU.Desc);
+ printf("\n");
+}
+
+extern "C" void
+LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) {
+ const TargetMachine *Target = unwrap(TM);
+ const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
+ const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
+ unsigned MaxFeatLen = getLongestEntryLength(FeatTable);
+
+ printf("Available features for this target:\n");
+ for (auto &Feature : FeatTable)
+ printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
+ printf("\n");
+
+ printf("Use +feature to enable a feature, or -feature to disable it.\n"
+ "For example, rustc -C -target-cpu=mycpu -C target-feature=+feature1,-feature2\n\n");
+}
+
+#else
+
+extern "C" void
+LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
+ printf("Target CPU help is not supported by this LLVM version.\n\n");
+}
+
+extern "C" void
+LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) {
+ printf("Target features help is not supported by this LLVM version.\n\n");
+}
+#endif
+
extern "C" LLVMTargetMachineRef
LLVMRustCreateTargetMachine(const char *triple,
const char *cpu,
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2016-07-25b
+2016-08-07
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// We specify -Z incremental here because we want to test the partitioning for
+// incremental compilation
+// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const
+
+// This test case makes sure, that references made through constants are
+// recorded properly in the InliningMap.
+
+mod mod1 {
+ pub trait Trait1 {
+ fn do_something(&self) {}
+ fn do_something_else(&self) {}
+ }
+
+ impl Trait1 for u32 {}
+
+ pub trait Trait1Gen<T> {
+ fn do_something(&self, x: T) -> T;
+ fn do_something_else(&self, x: T) -> T;
+ }
+
+ impl<T> Trait1Gen<T> for u32 {
+ fn do_something(&self, x: T) -> T { x }
+ fn do_something_else(&self, x: T) -> T { x }
+ }
+
+ fn id<T>(x: T) -> T { x }
+
+ // These are referenced, so they produce trans-items (see main())
+ pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1;
+ pub const TRAIT1_GEN_REF: &'static Trait1Gen<u8> = &0u32 as &Trait1Gen<u8>;
+ pub const ID_CHAR: fn(char) -> char = id::<char>;
+
+
+
+ pub trait Trait2 {
+ fn do_something(&self) {}
+ fn do_something_else(&self) {}
+ }
+
+ impl Trait2 for u32 {}
+
+ pub trait Trait2Gen<T> {
+ fn do_something(&self, x: T) -> T;
+ fn do_something_else(&self, x: T) -> T;
+ }
+
+ impl<T> Trait2Gen<T> for u32 {
+ fn do_something(&self, x: T) -> T { x }
+ fn do_something_else(&self, x: T) -> T { x }
+ }
+
+ // These are not referenced, so they do not produce trans-items
+ pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2;
+ pub const TRAIT2_GEN_REF: &'static Trait2Gen<u8> = &0u32 as &Trait2Gen<u8>;
+ pub const ID_I64: fn(i64) -> i64 = id::<i64>;
+}
+
+//~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[External]
+fn main() {
+
+ // Since Trait1::do_something() is instantiated via its default implementation,
+ // it is considered a generic and is instantiated here only because it is
+ // referenced in this module.
+ //~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0]<u32> @@ vtable_through_const[Internal]
+
+ // Although it is never used, Trait1::do_something_else() has to be
+ // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable
+ // could not be fully constructed.
+ //~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0]<u32> @@ vtable_through_const[Internal]
+ mod1::TRAIT1_REF.do_something();
+
+ // Same as above
+ //~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0]<u8> @@ vtable_through_const[Internal]
+ //~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0]<u8> @@ vtable_through_const[Internal]
+ mod1::TRAIT1_GEN_REF.do_something(0u8);
+
+ //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0]<char> @@ vtable_through_const[Internal]
+ mod1::ID_CHAR('x');
+}
+
+//~ TRANS_ITEM drop-glue i8
fn main() {
let x = Some("s".to_string());
match x {
- op_string @ Some(s) => {}, //~ ERROR E0007
- //~| ERROR E0303
+ op_string @ Some(s) => {},
+ //~^ ERROR E0007
+ //~| NOTE binds an already bound by-move value by moving it
+ //~| ERROR E0303
None => {},
}
}
fn main() {
match Some("hi".to_string()) {
- Some(s) if s.len() == 0 => {}, //~ ERROR E0008
+ Some(s) if s.len() == 0 => {},
+ //~^ ERROR E0008
+ //~| NOTE moves value into pattern guard
_ => {},
}
}
const C: i32 = 2;
const CR: &'static mut i32 = &mut C; //~ ERROR E0017
+ //~| NOTE constants require immutable values
//~| ERROR E0017
+ //~| NOTE constants require immutable values
static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+ //~| NOTE statics require immutable values
//~| ERROR E0017
+ //~| NOTE statics require immutable values
//~| ERROR E0388
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
+ //~| NOTE statics require immutable values
//~| ERROR E0017
-
+ //~| NOTE statics require immutable values
fn main() {}
fn foo(&self) -> Self;
}
-fn call_foo(x: Box<Trait>) { //~ ERROR E0038
+fn call_foo(x: Box<Trait>) {
+ //~^ ERROR E0038
+ //~| NOTE the trait `Trait` cannot be made into an object
+ //~| NOTE method `foo` references the `Self` type in its arguments or return type
let y = x.foo();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045
+extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045
+ //~| NOTE variadics require C calling conventions
fn main() {
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-enum Foo { FirstValue(i32) }
+enum Foo {}
fn main() {
- let u = Foo::FirstValue { value: 0 };
- //~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071]
+ let u = Foo { value: 0 };
+ //~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
//~| NOTE not a struct
let t = u32 { value: 4 };
// except according to those terms.
struct ListNode { //~ ERROR E0072
+ //~| NOTE recursive type has infinite size
head: u8,
tail: Option<ListNode>,
}
// except according to those terms.
enum Enum {
- P = 3,
- X = 3, //~ ERROR E0081
+ P = 3, //~ NOTE first use of `3isize`
+ X = 3,
+ //~^ ERROR discriminant value `3isize` already exists
+ //~| NOTE enum already has `3isize`
Y = 5
}
// except according to those terms.
type Foo<T> = u32; //~ ERROR E0091
+ //~| NOTE unused type parameter
type Foo2<A, B> = Box<A>; //~ ERROR E0091
+ //~| NOTE unused type parameter
fn main() {
}
#![feature(intrinsics)]
extern "rust-intrinsic" {
fn atomic_foo(); //~ ERROR E0092
-}
+} //~| NOTE unrecognized atomic operation
fn main() {
}
// except according to those terms.
struct Foo<T=U, U=()> { //~ ERROR E0128
+ //~| NOTE defaulted type parameters cannot be forward declared
field1: T,
field2: U,
}
// except according to those terms.
extern {
- fn foo((a, b): (u32, u32)); //~ ERROR E0130
+ fn foo((a, b): (u32, u32));
+ //~^ ERROR E0130
+ //~| NOTE pattern not allowed in foreign function
}
fn main() {
unsafe fn f() { return; }
fn main() {
- f(); //~ ERROR E0133
+ f();
+ //~^ ERROR E0133
+ //~| NOTE unsafe call requires unsafe function or block
}
#[start]
fn foo(argc: isize, argv: *const *const u8) -> isize {}
+//~^ NOTE previous `start` function here
#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {} //~ ERROR E0138
+fn f(argc: isize, argv: *const *const u8) -> isize {}
+//~^ ERROR E0138
+//~| NOTE multiple `start` functions
}
}
-use foo::MyTrait::do_something; //~ ERROR E0253
+use foo::MyTrait::do_something;
+ //~^ ERROR E0253
+ //~|NOTE cannot be imported directly
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) { } //~ ERROR E0263
+fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) {
+ //~^ ERROR E0263
+ //~| NOTE declared twice
+ //~| NOTE previous declaration here
+}
fn main() {}
fn main() {
let w = || { break; }; //~ ERROR E0267
+ //~| NOTE cannot break inside of a closure
}
fn main() {
break; //~ ERROR E0268
+ //~| NOTE cannot break outside of a loop
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod foo {
+ pub const X: u32 = 1;
+}
+
+pub use foo as foo2; //~ ERROR E0365
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+#[deny(overflowing_literals)]
+#[repr(i64)]
+enum Foo {
+ X = 0x7fffffffffffffff,
+ Y, //~ ERROR E0370
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized> {
+ a: i32,
+}
+
+impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> //~ ERROR E0374
+ where T: CoerceUnsized<U> {}
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized, U: ?Sized> {
+ a: i32,
+ b: T,
+ c: U,
+}
+
+impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {} //~ ERROR E0375
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized> {
+ a: T,
+}
+
+impl<T, U> CoerceUnsized<U> for Foo<T> {} //~ ERROR E0376
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+static X: i32 = 1;
+const C: i32 = 2;
+
+const CR: &'static mut i32 = &mut C; //~ ERROR E0017
+ //~| ERROR E0017
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+ //~| ERROR E0017
+ //~| ERROR E0388
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
+ //~| ERROR E0017
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct FancyNum {
+ num: u8,
+}
+
+fn main() {
+ let mut fancy = FancyNum{ num: 5 };
+ let fancy_ref = &(&mut fancy);
+ fancy_ref.num = 6; //~ ERROR E0389
+ println!("{}", fancy_ref.num);
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+ x: i32
+}
+
+impl *mut Foo {} //~ ERROR E0390
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Foo<T> { Bar } //~ ERROR E0392
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait A<T=Self> {}
+
+fn together_we_will_rule_the_galaxy(son: &A) {} //~ ERROR E0393
+
+fn main() {
+}
target_arch = "aarch64"))]
pub fn main() {
let x: isize;
- x = 1; //~ NOTE prior assignment occurs here
+ x = 1; //~ NOTE first assignment
foo(x);
unsafe {
asm!("mov $1, $0" : "=r"(x) : "r"(5));
//~^ ERROR re-assignment of immutable variable `x`
+ //~| NOTE re-assignment of immutable
//~| NOTE in this expansion of asm!
}
foo(x);
fn test() {
let v: isize;
- v = 1; //~ NOTE prior assignment occurs here
+ v = 1; //~ NOTE first assignment
println!("v={}", v);
v = 2; //~ ERROR re-assignment of immutable variable
+ //~| NOTE re-assignment of immutable
println!("v={}", v);
}
#![feature(associated_consts)]
trait Foo {
- const BAR: u32;
+ const BAR: u32; //~ NOTE original trait requirement
}
struct SignedBar;
impl Foo for SignedBar {
const BAR: i32 = -1;
//~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326]
- //~| expected u32, found i32
+ //~| NOTE expected u32, found i32
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(relaxed_adts)]
+
pub struct XEmpty1 {}
pub struct XEmpty2;
+pub struct XEmpty6();
pub enum XE {
XEmpty3 {},
XEmpty4,
+ XEmpty5(),
}
let mut map = HashMap::new();
//~^ ERROR E0433
+ //~| NOTE Use of undeclared type or module `HashMap`
for line in input.lines() {
let line = line.unwrap();
// aux-build:empty-struct.rs
+#![feature(relaxed_adts)]
+
extern crate empty_struct;
use empty_struct::*;
let e1 = Empty1 {};
let xe1 = XEmpty1 {};
- // Rejected by parser as yet
- // match e1 {
- // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
- // }
- // match xe1 {
- // XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1`
- // }
+ match e1 {
+ Empty1() => () //~ ERROR unresolved variant or struct `Empty1`
+ }
+ match xe1 {
+ XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
+ }
match e1 {
Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
}
// aux-build:empty-struct.rs
+#![feature(relaxed_adts)]
+
extern crate empty_struct;
use empty_struct::*;
let e3 = E::Empty3 {};
let xe3 = XE::XEmpty3 {};
- // Rejected by parser as yet
- // match e3 {
- // E::Empty3() => () // ERROR `E::Empty3` does not name a tuple variant or a tuple struct
- // }
- // match xe3 {
- // E::Empty3() => () // ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
- // }
+ match e3 {
+ E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
+ }
+ match xe3 {
+ XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
+ }
match e3 {
E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
}
--- /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.
+
+// Can't use unit struct as enum pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2();
+
+enum E {
+ Empty4()
+}
+
+// remove attribute after warning cycle and promoting warnings to errors
+fn main() {
+ let e2 = Empty2();
+ let e4 = E::Empty4();
+ let xe6 = XEmpty6();
+ let xe5 = XE::XEmpty5();
+
+ match e2 {
+ Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
+ }
+ match xe6 {
+ XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
+ }
+
+ match e4 {
+ E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
+ }
+ match xe5 {
+ XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
+ _ => {},
+ }
+}
--- /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.
+
+// Can't use unit struct as enum pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
+
+enum E {
+ Empty4
+}
+
+// remove attribute after warning cycle and promoting warnings to errors
+fn main() {
+ let e2 = Empty2;
+ let e4 = E::Empty4;
+ let xe2 = XEmpty2;
+ let xe4 = XE::XEmpty4;
+
+ match e2 {
+ Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
+ //~^ WARNING hard error
+ }
+ match xe2 {
+ XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
+ //~^ WARNING hard error
+ }
+
+ match e4 {
+ E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
+ //~^ WARNING hard error
+ }
+ match xe4 {
+ XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
+ //~^ WARNING hard 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.
+
+// Can't use unit struct as enum pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
+
+enum E {
+ Empty4
+}
+
+// remove attribute after warning cycle and promoting warnings to errors
+fn main() {
+ let e2 = Empty2;
+ let e4 = E::Empty4;
+ let xe2 = XEmpty2;
+ let xe4 = XE::XEmpty4;
+
+ match e2 {
+ Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
+ }
+ match xe2 {
+ XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
+ }
+
+ match e4 {
+ E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
+ }
+ match xe4 {
+ XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
+ _ => {},
+ }
+}
+++ /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.
-
-// Can't use unit struct as enum pattern
-
-// aux-build:empty-struct.rs
-
-extern crate empty_struct;
-use empty_struct::*;
-
-struct Empty2;
-
-enum E {
- Empty4
-}
-
-// remove attribute after warning cycle and promoting warnings to errors
-fn main() {
- let e2 = Empty2;
- let e4 = E::Empty4;
- let xe2 = XEmpty2;
- let xe4 = XE::XEmpty4;
-
- // Rejected by parser as yet
- // match e2 {
- // Empty2() => () // ERROR `Empty2` does not name a tuple variant or a tuple struct
- // }
- // match xe2 {
- // XEmpty2() => () // ERROR `XEmpty2` does not name a tuple variant or a tuple struct
- // }
- match e2 {
- Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
- //~^ WARNING hard error
- }
- match xe2 {
- XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
- //~^ WARNING hard error
- }
- // Rejected by parser as yet
- // match e4 {
- // E::Empty4() => () // ERROR `E::Empty4` does not name a tuple variant or a tuple struct
- // }
- // match xe4 {
- // XE::XEmpty4() => (), // ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
- // _ => {},
- // }
- match e4 {
- E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
- //~^ WARNING hard error
- }
- match xe4 {
- XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
- //~^ WARNING hard error
- _ => {},
- }
-}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Z(u8, u8);
+
+enum E {
+ U(u8, u8),
+}
+
+fn main() {
+ match Z(0, 1) {
+ Z{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
+ }
+ match E::U(0, 1) {
+ E::U{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
+ }
+
+ let z1 = Z(0, 1);
+ let z2 = Z { ..z1 }; //~ ERROR tuple structs and variants in struct patterns are unstable
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S(); //~ ERROR empty tuple structs and enum variants are unstable
+struct Z(u8, u8);
+
+enum E {
+ V(), //~ ERROR empty tuple structs and enum variants are unstable
+ U(u8, u8),
+}
+
+fn main() {
+ match S() {
+ S() => {} //~ ERROR empty tuple structs patterns are unstable
+ }
+ match E::V() {
+ E::V() => {} //~ ERROR empty tuple structs patterns are unstable
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![feature(conservative_impl_trait)]
+
+use std::cell::Cell;
+use std::rc::Rc;
+
+// Fast path, main can see the concrete type returned.
+fn before() -> impl Fn(i32) {
+ let p = Rc::new(Cell::new(0));
+ move |x| p.set(x)
+}
+
+fn send<T: Send>(_: T) {}
+
+fn main() {
+ send(before());
+ //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+ //~| NOTE required because it appears within the type `[closure
+ //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
+ //~| NOTE required by `send`
+
+ send(after());
+ //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+ //~| NOTE required because it appears within the type `[closure
+ //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
+ //~| NOTE required by `send`
+}
+
+// Deferred path, main has to wait until typeck finishes,
+// to check if the return type of after is Send.
+fn after() -> impl Fn(i32) {
+ let p = Rc::new(Cell::new(0));
+ move |x| p.set(x)
+}
+
+// Cycles should work as the deferred obligations are
+// independently resolved and only require the concrete
+// return type, which can't depend on the obligation.
+fn cycle1() -> impl Clone {
+ send(cycle2().clone());
+ //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
+ //~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
+ //~| NOTE required because it appears within the type `impl std::clone::Clone`
+ //~| NOTE required by `send`
+
+ Rc::new(Cell::new(5))
+}
+
+fn cycle2() -> impl Clone {
+ send(cycle1().clone());
+ //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+ //~| NOTE required because it appears within the type `impl std::clone::Clone`
+ //~| NOTE required by `send`
+
+ Rc::new(String::from("foo"))
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+fn main() {
+ let _: impl Fn() = || {};
+ //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+ let _ = || -> impl Fn() { || {} };
+ //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+fn arguments(_: impl Fn(),
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+ _: Vec<impl Clone>) {}
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+type Factory<R> = impl Fn() -> R;
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+type GlobalFactory<R> = fn() -> impl FnOnce() -> R;
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+trait LazyToString {
+ fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String;
+ //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Note that the following impl doesn't error, because the trait is invalid.
+impl LazyToString for String {
+ fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String {
+ || self.clone()
+ }
+}
+
+#[derive(Copy, Clone)]
+struct Lazy<T>(T);
+
+impl std::ops::Add<Lazy<i32>> for Lazy<i32> {
+ type Output = impl Fn() -> Lazy<i32>;
+ //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+ fn add(self, other: Lazy<i32>) -> Self::Output {
+ move || Lazy(self.0 + other.0)
+ }
+}
+
+impl<F> std::ops::Add<F>
+for impl Fn() -> Lazy<i32>
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+where F: Fn() -> impl FnOnce() -> i32
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+ type Output = Self;
+
+ fn add(self, other: F) -> Self::Output {
+ move || Lazy(self().0 + other()())
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, specialization)]
+
+trait Foo: Copy + ToString {}
+
+impl<T: Copy + ToString> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+ x
+}
+
+fn two(x: bool) -> impl Foo {
+ if x {
+ return 1_i32;
+ }
+ 0_u32
+ //~^ ERROR mismatched types
+ //~| expected i32, found u32
+}
+
+fn sum_to(n: u32) -> impl Foo {
+ if n == 0 {
+ 0
+ } else {
+ n + sum_to(n - 1)
+ //~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+ }
+}
+
+trait Leak: Sized {
+ type T;
+ fn leak(self) -> Self::T;
+}
+impl<T> Leak for T {
+ default type T = ();
+ default fn leak(self) -> Self::T { panic!() }
+}
+impl Leak for i32 {
+ type T = i32;
+ fn leak(self) -> i32 { self }
+}
+
+trait CheckIfSend: Sized {
+ type T: Default;
+ fn check(self) -> Self::T { Default::default() }
+}
+impl<T> CheckIfSend for T {
+ default type T = ();
+}
+impl<T: Send> CheckIfSend for T {
+ type T = bool;
+}
+
+fn main() {
+ let _: u32 = hide(0_u32);
+ //~^ ERROR mismatched types
+ //~| expected type `u32`
+ //~| found type `impl Foo`
+ //~| expected u32, found anonymized type
+
+ let _: i32 = Leak::leak(hide(0_i32));
+ //~^ ERROR mismatched types
+ //~| expected type `i32`
+ //~| found type `<impl Foo as Leak>::T`
+ //~| expected i32, found associated type
+
+ let _: bool = CheckIfSend::check(hide(0_i32));
+ //~^ ERROR mismatched types
+ //~| expected type `bool`
+ //~| found type `<impl Foo as CheckIfSend>::T`
+ //~| expected bool, found associated type
+
+ let mut x = (hide(0_u32), hide(0_i32));
+ x = (x.1,
+ //~^ ERROR mismatched types
+ //~| expected u32, found i32
+ x.0);
+ //~^ ERROR mismatched types
+ //~| expected i32, found u32
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo() -> impl Fn() { || {} }
+//~^ ERROR `impl Trait` is experimental
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+// Helper creating a fake borrow, captured by the impl Trait.
+fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
+
+fn stack() -> impl Copy {
+ //~^ ERROR only named lifetimes are allowed in `impl Trait`
+ let x = 0;
+ &x
+}
+
+fn late_bound(x: &i32) -> impl Copy {
+ //~^ ERROR only named lifetimes are allowed in `impl Trait`
+ x
+}
+
+// FIXME(#34511) Should work but doesn't at the moment,
+// region-checking needs an overhault to support this.
+fn early_bound<'a>(x: &'a i32) -> impl Copy {
+ //~^ ERROR only named lifetimes are allowed in `impl Trait`
+ x
+}
+
+fn ambiguous<'a, 'b>(x: &'a [u32], y: &'b [u32]) -> impl Iterator<Item=u32> {
+ //~^ ERROR only named lifetimes are allowed in `impl Trait`
+ if x.len() < y.len() {
+ x.iter().cloned()
+ } else {
+ y.iter().cloned()
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+// Helper creating a fake borrow, captured by the impl Trait.
+fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
+
+fn main() {
+ //~^ NOTE reference must be valid for the block
+ let long;
+ let mut short = 0;
+ //~^ NOTE but borrowed value is only valid for the block suffix following statement 1
+ long = borrow(&mut short);
+ //~^ ERROR `short` does not live long enough
+}
+++ /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.
-
-// For style and consistency reasons, non-parametrized enum variants must
-// be used simply as `ident` instead of `ident ()`.
-// This test-case covers enum declaration.
-
-enum Foo {
- Bar(), //~ ERROR empty tuple structs and enum variants are not allowed
- //~^ HELP remove trailing `()` to make a unit struct or unit enum variant
- Baz(), //~ ERROR empty tuple structs and enum variants are not allowed
- //~^ HELP remove trailing `()` to make a unit struct or unit enum variant
- Bazar
-}
-
-fn main() {
- println!("{}", match Bar { Bar => 1, Baz => 2, Bazar => 3 }) //~ ERROR unresolved name `Bar`
-}
+++ /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.
-
-// compile-flags: -Z continue-parse-after-error
-
-// For style and consistency reasons, non-parametrized enum variants must
-// be used simply as `ident` instead of `ident ()`.
-// This test-case covers enum matching.
-
-enum Foo {
- Bar,
- Baz,
- Bazar
-}
-
-fn main() {
- println!("{}", match Bar {
- Bar() => 1, //~ ERROR nullary enum variants are written with no trailing `( )`
- Baz() => 2, //~ ERROR nullary enum variants are written with no trailing `( )`
- Bazar => 3
- })
-}
enum Foo {
A = 1,
- //~^ NOTE first use
- //~| NOTE first use
- //~| NOTE first use
- B = 1, //~ ERROR discriminant value
- //~^ NOTE enum already
+ //~^ NOTE first use of `1isize`
+ //~| NOTE first use of `1isize`
+ //~| NOTE first use of `1isize`
+ B = 1,
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
C = 0,
- D, //~ ERROR discriminant value
- //~^ NOTE enum already
+ D,
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
- E = N, //~ ERROR discriminant value
- //~^ NOTE enum already
+ E = N,
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed
+struct TS ( //~ ERROR empty tuple structs and enum variants are unstable
#[cfg(untrue)]
i32,
);
enum E {
- TV ( //~ ERROR empty tuple structs and enum variants are not allowed
+ TV ( //~ ERROR empty tuple structs and enum variants are unstable
#[cfg(untrue)]
i32,
)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(relaxed_adts)]
+
enum MyOption<T> {
MySome(T),
MyNone,
fn main() {
match MyOption::MySome(42) {
MyOption::MySome { x: 42 } => (),
- //~^ ERROR `MyOption::MySome` does not name a struct or a struct variant
+ //~^ ERROR struct `MyOption::MySome` does not have a field named `x`
+ //~| ERROR pattern does not mention field `0`
_ => (),
}
}
// except according to those terms.
pub struct Foo<Bar=Bar>; //~ ERROR E0128
+ //~| NOTE defaulted type parameters cannot be forward declared
pub struct Baz(Foo);
fn main() {}
//~^ ERROR `Array` cannot be made into an object
//~| NOTE the trait cannot require that `Self : Sized`
//~| NOTE requirements on the impl of `std::ops::CoerceUnsized<&Array>`
+ //~| NOTE the trait `Array` cannot be made into an object
as
&Array;
//~^ ERROR `Array` cannot be made into an object
//~| NOTE the trait cannot require that `Self : Sized`
+ //~| NOTE the trait `Array` cannot be made into an object
}
fn main() {}
fn main() {
let _ = &()
as &Map<Key=u32,MapValue=u32>;
- //~^ ERROR the trait `Map` cannot be made into an object
+ //~^ ERROR E0038
//~| NOTE the trait cannot use `Self` as a type parameter
+ //~| NOTE the trait `Map` cannot be made into an object
}
+++ /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.
-
-struct Foo(u32);
-struct Bar;
-
-enum Enum {
- Foo(u32),
- Bar
-}
-
-fn main() {
- let x = Foo(1);
- Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant
- let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
-
- let x = Bar;
- Bar { ..x };
- let Bar { .. } = x;
-
- match Enum::Bar {
- Enum::Bar { .. }
- => {}
- Enum::Foo { .. } //~ ERROR `Enum::Foo` does not name a struct
- => {}
- }
-}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use inner::C;
+
+mod inner {
+ trait A {
+ fn a(&self) { }
+ }
+
+ pub trait B {
+ fn b(&self) { }
+ }
+
+ pub trait C: A + B { //~ ERROR private trait in public interface
+ //~^ WARN will become a hard error
+ fn c(&self) { }
+ }
+
+ impl A for i32 {}
+ impl B for i32 {}
+ impl C for i32 {}
+
+}
+
+fn main() {
+ // A is private
+ // B is pub, not reexported
+ // C : A + B is pub, reexported
+
+ // 0.a(); // can't call
+ // 0.b(); // can't call
+ 0.c(); // ok
+
+ C::a(&0); // can call
+ C::b(&0); // can call
+ C::c(&0); // ok
+}
use std::ptr;
fn main() {
- (&ptr::write)(1 as *mut _, 42); //~ ERROR E0133
+ (&ptr::write)(1 as *mut _, 42);
+ //~^ ERROR E0133
+ //~| NOTE unsafe call requires unsafe function or block
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(rustc_attrs)]
#![allow(unused)]
struct SemiPriv;
mod m1 {
struct Priv;
impl ::SemiPriv {
- pub fn f(_: Priv) {} //~ WARN private type in public interface
+ pub fn f(_: Priv) {} //~ ERROR private type in public interface
//~^ WARNING hard error
}
mod m2 {
struct Priv;
impl ::std::ops::Deref for ::SemiPriv {
- type Target = Priv; //~ WARN private type in public interface
+ type Target = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
fn deref(&self) -> &Self::Target { unimplemented!() }
}
mod m3 {
struct Priv;
impl ::SemiPrivTrait for () {
- type Assoc = Priv; //~ WARN private type in public interface
+ type Assoc = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
}
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() {}
enum foo { foo_(bar) }
struct bar { x: bar }
//~^ ERROR E0072
+//~| NOTE recursive type has infinite size
fn main() {
}
// too big.
enum Expr { //~ ERROR E0072
+ //~| NOTE recursive type has infinite size
Plus(Expr, Expr),
Literal(i64),
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! m { ($t:tt) => { $t } }
+
+fn main() {
+ m!($t); //~ ERROR unknown macro variable
+ //~| ERROR expected expression
+}
// except according to those terms.
struct S { //~ ERROR E0072
+ //~| NOTE recursive type has infinite size
element: Option<S>
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(relaxed_adts)]
+
struct NonCopyable(());
fn main() {
- let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant
+ let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p`
}
let v: isize;
loop {
v = 1; //~ ERROR re-assignment of immutable variable
- //~^ NOTE prior assignment occurs here
+ //~^ NOTE re-assignment of immutable variable
v.clone(); // just to prevent liveness warnings
}
}
fn test() {
let v: isize;
- v = 2; //~ NOTE prior assignment occurs here
+ v = 2; //~ NOTE first assignment
v += 1; //~ ERROR re-assignment of immutable variable
+ //~| NOTE re-assignment of immutable
v.clone();
}
// except according to those terms.
fn test() {
- let v: isize = 1; //~ NOTE prior assignment occurs here
+ let v: isize = 1; //~ NOTE first assignment
v.clone();
v = 2; //~ ERROR re-assignment of immutable variable
+ //~| NOTE re-assignment of immutable
v.clone();
}
foo!(Box);
+macro_rules! bar {
+ ($x:tt) => {
+ macro_rules! baz {
+ ($x:tt, $y:tt) => { ($x, $y) }
+ }
+ }
+}
+
#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() { //~ ERROR compilation successful
+ bar!($y);
+ let _: (i8, i16) = baz!(0i8, 0i16);
+}
extern {
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
- //~^ NOTE this is a recent error
+ //~^ NOTE pattern not allowed in foreign function
+ //~| NOTE this is a recent error
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
+ //~^ NOTE pattern not allowed in foreign function
fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations
- //~^ NOTE this is a recent error
+ //~^ NOTE pattern not allowed in foreign function
+ //~| NOTE this is a recent error
fn g1(arg: u8); // OK
fn g2(_: u8); // OK
// fn g3(u8); // Not yet
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(relaxed_adts)]
+
+struct S(u8, u16);
+
+fn main() {
+ let s = S{0b1: 10, 0: 11}; //~ ERROR structure `S` has no field named `0b1`
+ match s {
+ S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1`
+ }
+}
fn make_bar<T:Bar>(t: &T) -> &Bar {
//~^ ERROR E0038
//~| NOTE method `bar` has generic type parameters
+ //~| NOTE the trait `Bar` cannot be made into an object
t
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
//~^ ERROR E0038
- //~^^ NOTE method `bar` has generic type parameters
+ //~| NOTE method `bar` has generic type parameters
+ //~| NOTE the trait `Bar` cannot be made into an object
t as &Bar
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
//~^ ERROR E0038
//~| NOTE method `bar` references the `Self` type in its arguments or return type
+ //~| NOTE the trait `Bar` cannot be made into an object
loop { }
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
//~^ ERROR E0038
//~| NOTE method `bar` references the `Self` type in its arguments or return type
+ //~| NOTE the trait `Baz` cannot be made into an object
t
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
//~^ ERROR E0038
//~| NOTE the trait cannot require that `Self : Sized`
+ //~| NOTE the trait `Bar` cannot be made into an object
t
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
//~^ ERROR E0038
//~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
+ //~| NOTE the trait `Baz` cannot be made into an object
t
}
// except according to those terms.
mod m1 {
- #![deny(private_in_public)]
-
pub struct Pub;
struct Priv;
// Private types and traits are not allowed in public interfaces.
// This test also ensures that the checks are performed even inside private modules.
-#![feature(rustc_attrs)]
#![feature(associated_consts)]
#![feature(associated_type_defaults)]
#![allow(dead_code)]
type Alias;
}
- pub type Alias = Priv; //~ WARN private type in public interface
+ pub type Alias = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
pub enum E {
- V1(Priv), //~ WARN private type in public interface
+ V1(Priv), //~ ERROR private type in public interface
//~^ WARNING hard error
- V2 { field: Priv }, //~ WARN private type in public interface
+ V2 { field: Priv }, //~ ERROR private type in public interface
//~^ WARNING hard error
}
pub trait Tr {
- const C: Priv = Priv; //~ WARN private type in public interface
+ const C: Priv = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
- type Alias = Priv; //~ WARN private type in public interface
+ type Alias = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
- fn f1(arg: Priv) {} //~ WARN private type in public interface
+ fn f1(arg: Priv) {} //~ ERROR private type in public interface
//~^ WARNING hard error
- fn f2() -> Priv { panic!() } //~ WARN private type in public interface
+ fn f2() -> Priv { panic!() } //~ ERROR private type in public interface
//~^ WARNING hard error
}
extern {
- pub static ES: Priv; //~ WARN private type in public interface
+ pub static ES: Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
- pub fn ef1(arg: Priv); //~ WARN private type in public interface
+ pub fn ef1(arg: Priv); //~ ERROR private type in public interface
//~^ WARNING hard error
- pub fn ef2() -> Priv; //~ WARN private type in public interface
+ pub fn ef2() -> Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
impl PubTr for Pub {
- type Alias = Priv; //~ WARN private type in public interface
+ type Alias = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
}
pub struct Pub<T>(T);
pub trait PubTr {}
- pub type Alias<T: PrivTr> = T; //~ WARN private trait in public interface
+ pub type Alias<T: PrivTr> = T; //~ ERROR private trait in public interface
//~^ WARN trait bounds are not (yet) enforced in type definitions
//~| WARNING hard error
- pub trait Tr1: PrivTr {} //~ WARN private trait in public interface
+ pub trait Tr1: PrivTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
- pub trait Tr2<T: PrivTr> {} //~ WARN private trait in public interface
+ pub trait Tr2<T: PrivTr> {} //~ ERROR private trait in public interface
//~^ WARNING hard error
pub trait Tr3 {
- type Alias: PrivTr; //~ WARN private trait in public interface
+ type Alias: PrivTr; //~ ERROR private trait in public interface
//~^ WARNING hard error
- fn f<T: PrivTr>(arg: T) {} //~ WARN private trait in public interface
+ fn f<T: PrivTr>(arg: T) {} //~ ERROR private trait in public interface
//~^ WARNING hard error
}
- impl<T: PrivTr> Pub<T> {} //~ WARN private trait in public interface
+ impl<T: PrivTr> Pub<T> {} //~ ERROR private trait in public interface
//~^ WARNING hard error
- impl<T: PrivTr> PubTr for Pub<T> {} //~ WARN private trait in public interface
+ impl<T: PrivTr> PubTr for Pub<T> {} //~ ERROR private trait in public interface
//~^ WARNING hard error
}
pub struct Pub<T>(T);
pub trait PubTr {}
- pub type Alias<T> where T: PrivTr = T; //~ WARN private trait in public interface
+ pub type Alias<T> where T: PrivTr = T; //~ ERROR private trait in public interface
//~^ WARNING hard error
- pub trait Tr2<T> where T: PrivTr {} //~ WARN private trait in public interface
+ pub trait Tr2<T> where T: PrivTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
pub trait Tr3 {
- fn f<T>(arg: T) where T: PrivTr {} //~ WARN private trait in public interface
+ fn f<T>(arg: T) where T: PrivTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
}
- impl<T> Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
+ impl<T> Pub<T> where T: PrivTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
- impl<T> PubTr for Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
+ impl<T> PubTr for Pub<T> where T: PrivTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
}
trait PrivTr<T> {}
pub trait PubTr<T> {}
- pub trait Tr1: PrivTr<Pub> {} //~ WARN private trait in public interface
+ pub trait Tr1: PrivTr<Pub> {} //~ ERROR private trait in public interface
//~^ WARNING hard error
- pub trait Tr2: PubTr<Priv> {} //~ WARN private type in public interface
+ pub trait Tr2: PubTr<Priv> {} //~ ERROR private type in public interface
//~^ WARNING hard error
- pub trait Tr3: PubTr<[Priv; 1]> {} //~ WARN private type in public interface
+ pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR private type in public interface
//~^ WARNING hard error
- pub trait Tr4: PubTr<Pub<Priv>> {} //~ WARN private type in public interface
+ pub trait Tr4: PubTr<Pub<Priv>> {} //~ ERROR private type in public interface
//~^ WARNING hard error
}
type Alias = Priv; // OK
}
impl PubTr for Pub {
- type Alias = Priv; //~ WARN private type in public interface
+ type Alias = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
}
}
pub fn f1(arg: PrivUseAlias) {} // OK
+ pub fn f2(arg: PrivAlias) {} // OK
pub trait Tr1: PrivUseAliasTr {} // OK
- // This should be OK, if type aliases are substituted
- pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ WARN private type in public interface
- //~^ WARNING hard error
+ pub trait Tr2: PrivUseAliasTr<PrivAlias> {} // OK
impl PrivAlias {
- pub fn f(arg: Priv) {} //~ WARN private type in public interface
+ pub fn f(arg: Priv) {} //~ ERROR private type in public interface
//~^ WARNING hard error
}
// This doesn't even parse
// impl <Priv as PrivTr>::AssocAlias {
- // pub fn f(arg: Priv) {} // WARN private type in public interface
+ // pub fn f(arg: Priv) {} // ERROR private type in public interface
// }
impl PrivUseAliasTr for PrivUseAlias {
- type Check = Priv; //~ WARN private type in public interface
+ type Check = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
impl PrivUseAliasTr for PrivAlias {
- type Check = Priv; //~ WARN private type in public interface
+ type Check = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
impl PrivUseAliasTr for <Priv as PrivTr>::AssocAlias {
- type Check = Priv; //~ WARN private type in public interface
+ type Check = Priv; //~ ERROR private type in public interface
//~^ WARNING hard error
}
}
type AssocAlias = Priv3;
}
- pub trait Tr1: PrivUseAliasTr {} //~ WARN private trait in public interface
+ pub trait Tr1: PrivUseAliasTr {} //~ ERROR private trait in public interface
//~^ WARNING hard error
- pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ WARN private trait in public interface
- //~^ WARN private type in public interface
+ pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ ERROR private trait in public interface
+ //~^ ERROR private type in public interface
//~| WARNING hard error
//~| WARNING hard error
struct Priv;
type PrivAliasGeneric<T = Priv> = T;
type Result<T> = ::std::result::Result<T, Priv>;
+
+ pub fn f1(arg: PrivAliasGeneric<u8>) {} // OK, not an error
}
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() {}
}
impl PrivTr for Priv {}
- // This should be OK, if type aliases are substituted
- pub fn f2(arg: PrivAlias) {} //~ ERROR private type in public interface
// This should be OK, but associated type aliases are not substituted yet
pub fn f3(arg: <Priv as PrivTr>::AssocAlias) {} //~ ERROR private type in public interface
type PrivAliasGeneric<T = Priv> = T;
type Result<T> = ::std::result::Result<T, Priv>;
- // This should be OK, if type aliases are substituted
- pub fn f1(arg: PrivAliasGeneric<u8>) {} //~ ERROR private type in public interface
pub fn f2(arg: PrivAliasGeneric) {} //~ ERROR private type in public interface
pub fn f3(arg: Result<u8>) {} //~ ERROR private type in public interface
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(rustc_attrs)]
#![allow(dead_code)]
extern crate core;
-pub use core as reexported_core; //~ WARN extern crate `core` is private, and cannot be reexported
+pub use core as reexported_core; //~ ERROR extern crate `core` is private, and cannot be reexported
//~^ WARNING hard error
mod m1 {
- pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
+ pub use ::E::V; //~ ERROR variant `V` is private, and cannot be reexported
//~^ WARNING hard error
}
mod m2 {
- pub use ::E::{V}; //~ WARN variant `V` is private, and cannot be reexported
+ pub use ::E::{V}; //~ ERROR variant `V` is private, and cannot be reexported
//~^ WARNING hard error
}
mod m3 {
- pub use ::E::V::{self}; //~ WARN variant `V` is private, and cannot be reexported
+ pub use ::E::V::{self}; //~ ERROR variant `V` is private, and cannot be reexported
//~^ WARNING hard error
}
mod m4 {
- pub use ::E::*; //~ WARN variant `V` is private, and cannot be reexported
+ pub use ::E::*; //~ ERROR variant `V` is private, and cannot be reexported
//~^ WARNING hard error
}
enum E { V }
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() {}
+++ /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.
-
-// Regression test for issue #26083
-// Test that span for public struct fields start at `pub` instead of the identifier
-
-struct Foo {
- pub bar: u8,
-
- pub
- //~^ error: field `bar` is already declared [E0124]
- bar: u8,
-
- pub bar:
- //~^ error: field `bar` is already declared [E0124]
- u8,
-
- bar:
- //~^ error: field `bar` is already declared [E0124]
- u8,
-}
-
-fn main() { }
+++ /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.
-
-struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed
-
-fn main() {}
unsafe impl UnsafeTrait for *mut isize {
fn foo(self) {
// Unsafe actions are not made legal by taking place in an unsafe trait:
- *self += 1; //~ ERROR E0133
+ *self += 1;
+ //~^ ERROR E0133
+ //~| NOTE unsafe call requires unsafe function or block
}
}
// Tests that `transmute` cannot be called on types of different size.
#![allow(warnings)]
+#![feature(specialization)]
use std::mem::transmute;
//~^ ERROR transmute called with differently sized types
}
+trait Specializable { type Output; }
+
+impl<T> Specializable for T {
+ default type Output = u16;
+}
+
+unsafe fn specializable<T>(x: u16) -> <T as Specializable>::Output {
+ transmute(x)
+ //~^ ERROR transmute called with differently sized types
+}
+
fn main() {}
// except according to those terms.
struct t1 { //~ ERROR E0072
+ //~| NOTE recursive type has infinite size
foo: isize,
foolish: t1
}
!v
}
-const VAL: u32 = dummy(0xFFFF); //~ ERROR E0133
+const VAL: u32 = dummy(0xFFFF);
+//~^ ERROR E0133
+//~| NOTE unsafe call requires unsafe function or block
fn main() {
assert_eq!(VAL, 0xFFFF0000);
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Baz {
+ Empty,
+ Foo { x: usize },
+}
+
+fn bar(a: usize) -> Baz {
+ Baz::Foo { x: a }
+}
+
+fn main() {
+ let x = bar(10);
+ match x {
+ Baz::Empty => println!("empty"),
+ Baz::Foo { x } => println!("{}", x),
+ };
+}
+
+// END RUST SOURCE
+// START rustc.node10.Deaggregator.before.mir
+// bb0: {
+// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
+// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
+// return = Baz::Foo { x: tmp0 }; // scope 1 at main.rs:8:5: 8:21
+// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
+// }
+// END rustc.node10.Deaggregator.before.mir
+// START rustc.node10.Deaggregator.after.mir
+// bb0: {
+// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
+// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
+// ((return as Foo).0: usize) = tmp0; // scope 1 at main.rs:8:5: 8:21
+// discriminant(return) = 1; // scope 1 at main.rs:8:5: 8:21
+// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
+// }
+// END rustc.node10.Deaggregator.after.mir
\ No newline at end of file
let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
Success(map) => {
- match (&*map[&str_to_ident("matched").name], &*map[&str_to_ident("pat").name]) {
+ match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) {
(&MatchedNonterminal(NtExpr(ref matched_expr)),
&MatchedSeq(ref pats, seq_sp)) => {
let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
// ignore-android: FIXME(#10356)
// ignore-windows: std::dynamic_lib does not work on Windows well
// ignore-musl
+// ignore-emscripten no dynamic linking
extern crate linkage_visibility as foo;
// except according to those terms.
// exec-env:RUST_LOG=logging_enabled=info
+// ignore-emscripten: FIXME(#31622)
#![feature(rustc_private)]
// ignore-windows
// exec-env:RUST_LOG=debug
// compile-flags:-C debug-assertions=y
+// ignore-emscripten: FIXME(#31622)
#![feature(rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(relaxed_adts)]
+
pub struct XEmpty1 {}
pub struct XEmpty2;
+pub struct XEmpty7();
pub enum XE {
XEmpty3 {},
XEmpty4,
+ XEmpty6(),
}
// compile-flags:-g -Cllvm-args=-enable-tail-merge=0
// ignore-pretty as this critically relies on line numbers
+// ignore-emscripten spawning processes is not supported
use std::io;
use std::io::prelude::*;
// no-pretty-expanded FIXME #15189
// ignore-android FIXME #17520
+// ignore-emscripten spawning processes is not supported
// compile-flags:-g
use std::env;
// except according to those terms.
// ignore-windows - this is a unix-specific test
+// ignore-emscripten
#![feature(process_exec, libc)]
// except according to those terms.
// ignore-windows - this is a unix-specific test
+// ignore-emscripten
// ignore-pretty
#![feature(process_exec)]
// except according to those terms.
// compile-flags: -Z force-dropflag-checks=on
+// ignore-emscripten
// Quick-and-dirty test to ensure -Z force-dropflag-checks=on works as
// expected. Note that the inlined drop-flag is slated for removal
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten no threads support
+
#![allow(unknown_features)]
#![feature(box_syntax)]
+++ /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.
-
-// Feature gate test for empty struct with braces
-// Can't define an empty braced struct
-
-struct Empty1 {}
-struct Empty2;
-
-enum E {
- Empty4 {},
- Empty5,
-}
-
-fn main() {
-}
+++ /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.
-
-// Feature gate test for empty struct with braces
-// Can't use braced expressions and patterns with structs defined without braces
-
-struct Empty2;
-
-enum E {
- Empty5,
-}
-
-fn main() {
- let e2: Empty2 = Empty2 {};
- let e2: Empty2 = Empty2;
- let e5: E = E::Empty5 {};
- let e5: E = E::Empty5;
-
- match e2 {
- Empty2 {} => {}
- }
- match e2 {
- Empty2 => {}
- }
- match e2 {
- Empty2 { .. } => {}
- }
- match e5 {
- E::Empty5 {} => {}
- }
- match e5 {
- E::Empty5 => {}
- }
- match e5 {
- E::Empty5 { .. } => {}
- }
-
- let e22 = Empty2 { ..e2 };
-}
// aux-build:empty-struct.rs
+#![feature(relaxed_adts)]
+
extern crate empty_struct;
use empty_struct::*;
struct Empty1 {}
struct Empty2;
+struct Empty7();
#[derive(PartialEq, Eq)]
struct Empty3 {}
enum E {
Empty4 {},
Empty5,
+ Empty6(),
}
fn local() {
let e4: E = E::Empty4 {};
let e5: E = E::Empty5 {};
let e5: E = E::Empty5;
+ let e6: E = E::Empty6 {};
+ let e6: E = E::Empty6();
+ let ctor6: fn() -> E = E::Empty6;
+ let e7: Empty7 = Empty7 {};
+ let e7: Empty7 = Empty7();
+ let ctor7: fn() -> Empty7 = Empty7;
match e1 {
Empty1 {} => {}
E::Empty5 {} => {}
_ => {}
}
+ match e6 {
+ E::Empty6 {} => {}
+ _ => {}
+ }
+ match e7 {
+ Empty7 {} => {}
+ }
match e1 {
Empty1 { .. } => {}
E::Empty5 { .. } => {}
_ => {}
}
+ match e6 {
+ E::Empty6 { .. } => {}
+ _ => {}
+ }
+ match e7 {
+ Empty7 { .. } => {}
+ }
match e2 {
Empty2 => {}
E::Empty5 => {}
_ => {}
}
+ match e6 {
+ E::Empty6() => {}
+ _ => {}
+ }
+ match e6 {
+ E::Empty6(..) => {}
+ _ => {}
+ }
+ match e7 {
+ Empty7() => {}
+ }
+ match e7 {
+ Empty7(..) => {}
+ }
let e11: Empty1 = Empty1 { ..e1 };
let e22: Empty2 = Empty2 { ..e2 };
let e33: Empty3 = Empty3 { ..e3 };
+ let e77: Empty7 = Empty7 { ..e7 };
}
fn xcrate() {
let e3: XE = XE::XEmpty3 {};
let e4: XE = XE::XEmpty4 {};
let e4: XE = XE::XEmpty4;
+ let e6: XE = XE::XEmpty6 {};
+ let e6: XE = XE::XEmpty6();
+ let ctor6: fn() -> XE = XE::XEmpty6;
+ let e7: XEmpty7 = XEmpty7 {};
+ let e7: XEmpty7 = XEmpty7();
+ let ctor7: fn() -> XEmpty7 = XEmpty7;
match e1 {
XEmpty1 {} => {}
XE::XEmpty4 {} => {}
_ => {}
}
+ match e6 {
+ XE::XEmpty6 {} => {}
+ _ => {}
+ }
+ match e7 {
+ XEmpty7 {} => {}
+ }
match e1 {
XEmpty1 { .. } => {}
XE::XEmpty4 { .. } => {}
_ => {}
}
+ match e6 {
+ XE::XEmpty6 { .. } => {}
+ _ => {}
+ }
+ match e7 {
+ XEmpty7 { .. } => {}
+ }
match e2 {
XEmpty2 => {}
XE::XEmpty4 => {}
_ => {}
}
+ match e6 {
+ XE::XEmpty6() => {}
+ _ => {}
+ }
+ match e6 {
+ XE::XEmpty6(..) => {}
+ _ => {}
+ }
+ match e7 {
+ XEmpty7() => {}
+ }
+ match e7 {
+ XEmpty7(..) => {}
+ }
let e11: XEmpty1 = XEmpty1 { ..e1 };
let e22: XEmpty2 = XEmpty2 { ..e2 };
+ let e77: XEmpty7 = XEmpty7 { ..e7 };
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
use std::env::args;
use std::process::Command;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
#![feature(path)]
// except according to those terms.
// exec-env:TEST_EXEC_ENV=22
-
+// ignore-emscripten FIXME: issue #31622
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten No support for threads
+
#![allow(unknown_features)]
#![feature(std_misc)]
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+// Fast path, main can see the concrete type returned.
+fn before() -> impl FnMut(i32) {
+ let mut p = Box::new(0);
+ move |x| *p = x
+}
+
+fn send<T: Send>(_: T) {}
+
+fn main() {
+ send(before());
+ send(after());
+}
+
+// Deferred path, main has to wait until typeck finishes,
+// to check if the return type of after is Send.
+fn after() -> impl FnMut(i32) {
+ let mut p = Box::new(0);
+ move |x| *p = x
+}
+
+// Cycles should work as the deferred obligations are
+// independently resolved and only require the concrete
+// return type, which can't depend on the obligation.
+fn cycle1() -> impl Clone {
+ send(cycle2().clone());
+ 5
+}
+
+fn cycle2() -> impl Clone {
+ send(cycle1().clone());
+ String::from("foo")
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, specialization)]
+
+trait Foo: std::fmt::Debug + Eq {}
+
+impl<T: std::fmt::Debug + Eq> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+ x
+}
+
+trait Leak<T>: Sized {
+ fn leak(self) -> T;
+}
+impl<T, U> Leak<T> for U {
+ default fn leak(self) -> T { panic!("type mismatch") }
+}
+impl<T> Leak<T> for T {
+ fn leak(self) -> T { self }
+}
+
+fn lucky_seven() -> impl Fn(usize) -> u8 {
+ let a = [1, 2, 3, 4, 5, 6, 7];
+ move |i| a[i]
+}
+
+fn main() {
+ assert_eq!(hide(42), hide(42));
+
+ assert_eq!(std::mem::size_of_val(&hide([0_u8; 5])), 5);
+ assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
+
+ assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, fn_traits, step_trait, unboxed_closures)]
+
+//! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>.
+//!
+//! Originally converted to Rust by [Daniel Keep](https://github.com/DanielKeep).
+
+use std::fmt::Write;
+use std::mem;
+
+/// Date representation.
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+struct NaiveDate(i32, u32, u32);
+
+impl NaiveDate {
+ pub fn from_ymd(y: i32, m: u32, d: u32) -> NaiveDate {
+ assert!(1 <= m && m <= 12, "m = {:?}", m);
+ assert!(1 <= d && d <= NaiveDate(y, m, 1).days_in_month(), "d = {:?}", d);
+ NaiveDate(y, m, d)
+ }
+
+ pub fn year(&self) -> i32 {
+ self.0
+ }
+
+ pub fn month(&self) -> u32 {
+ self.1
+ }
+
+ pub fn day(&self) -> u32 {
+ self.2
+ }
+
+ pub fn succ(&self) -> NaiveDate {
+ let (mut y, mut m, mut d, n) = (
+ self.year(), self.month(), self.day()+1, self.days_in_month());
+ if d > n {
+ d = 1;
+ m += 1;
+ }
+ if m > 12 {
+ m = 1;
+ y += 1;
+ }
+ NaiveDate::from_ymd(y, m, d)
+ }
+
+ pub fn weekday(&self) -> Weekday {
+ use Weekday::*;
+
+ // 0 = Sunday
+ let year = self.year();
+ let dow_jan_1 = (year*365 + ((year-1) / 4) - ((year-1) / 100) + ((year-1) / 400)) % 7;
+ let dow = (dow_jan_1 + (self.day_of_year() as i32 - 1)) % 7;
+ [Sun, Mon, Tue, Wed, Thu, Fri, Sat][dow as usize]
+ }
+
+ pub fn isoweekdate(&self) -> (i32, u32, Weekday) {
+ let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday();
+
+ // Work out this date's DOtY and week number, not including year adjustment.
+ let doy_0 = self.day_of_year() - 1;
+ let mut week_mon_0: i32 = ((first_dow_mon_0 + doy_0) / 7) as i32;
+
+ if self.first_week_in_prev_year() {
+ week_mon_0 -= 1;
+ }
+
+ let weeks_in_year = self.last_week_number();
+
+ // Work out the final result.
+ // If the week is -1 or >= weeks_in_year, we will need to adjust the year.
+ let year = self.year();
+ let wd = self.weekday();
+
+ if week_mon_0 < 0 {
+ (year - 1, NaiveDate::from_ymd(year - 1, 1, 1).last_week_number(), wd)
+ } else if week_mon_0 >= weeks_in_year as i32 {
+ (year + 1, (week_mon_0 + 1 - weeks_in_year as i32) as u32, wd)
+ } else {
+ (year, (week_mon_0 + 1) as u32, wd)
+ }
+ }
+
+ fn first_week_in_prev_year(&self) -> bool {
+ let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday();
+
+ // Any day in the year *before* the first Monday of that year
+ // is considered to be in the last week of the previous year,
+ // assuming the first week has *less* than four days in it.
+ // Adjust the week appropriately.
+ ((7 - first_dow_mon_0) % 7) < 4
+ }
+
+ fn year_first_day_of_week(&self) -> Weekday {
+ NaiveDate::from_ymd(self.year(), 1, 1).weekday()
+ }
+
+ fn weeks_in_year(&self) -> u32 {
+ let days_in_last_week = self.year_first_day_of_week().num_days_from_monday() + 1;
+ if days_in_last_week >= 4 { 53 } else { 52 }
+ }
+
+ fn last_week_number(&self) -> u32 {
+ let wiy = self.weeks_in_year();
+ if self.first_week_in_prev_year() { wiy - 1 } else { wiy }
+ }
+
+ fn day_of_year(&self) -> u32 {
+ (1..self.1).map(|m| NaiveDate::from_ymd(self.year(), m, 1).days_in_month())
+ .fold(0, |a,b| a+b) + self.day()
+ }
+
+ fn is_leap_year(&self) -> bool {
+ let year = self.year();
+ if year % 4 != 0 {
+ return false
+ } else if year % 100 != 0 {
+ return true
+ } else if year % 400 != 0 {
+ return false
+ } else {
+ return true
+ }
+ }
+
+ fn days_in_month(&self) -> u32 {
+ match self.month() {
+ /* Jan */ 1 => 31,
+ /* Feb */ 2 => if self.is_leap_year() { 29 } else { 28 },
+ /* Mar */ 3 => 31,
+ /* Apr */ 4 => 30,
+ /* May */ 5 => 31,
+ /* Jun */ 6 => 30,
+ /* Jul */ 7 => 31,
+ /* Aug */ 8 => 31,
+ /* Sep */ 9 => 30,
+ /* Oct */ 10 => 31,
+ /* Nov */ 11 => 30,
+ /* Dec */ 12 => 31,
+ _ => unreachable!()
+ }
+ }
+}
+
+impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
+ type Output = NaiveDate;
+
+ fn add(self, other: &'b NaiveDate) -> NaiveDate {
+ assert_eq!(*other, NaiveDate(0, 0, 1));
+ self.succ()
+ }
+}
+
+impl std::iter::Step for NaiveDate {
+ fn step(&self, by: &Self) -> Option<Self> {
+ Some(self + by)
+ }
+
+ fn steps_between(_: &Self, _: &Self, _: &Self) -> Option<usize> {
+ unimplemented!()
+ }
+
+ fn steps_between_by_one(_: &Self, _: &Self) -> Option<usize> {
+ unimplemented!()
+ }
+
+ fn is_negative(&self) -> bool {
+ false
+ }
+
+ fn replace_one(&mut self) -> Self {
+ mem::replace(self, NaiveDate(0, 0, 1))
+ }
+
+ fn replace_zero(&mut self) -> Self {
+ mem::replace(self, NaiveDate(0, 0, 0))
+ }
+
+ fn add_one(&self) -> Self {
+ self.succ()
+ }
+
+ fn sub_one(&self) -> Self {
+ unimplemented!()
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum Weekday {
+ Mon,
+ Tue,
+ Wed,
+ Thu,
+ Fri,
+ Sat,
+ Sun,
+}
+
+impl Weekday {
+ pub fn num_days_from_monday(&self) -> u32 {
+ use Weekday::*;
+ match *self {
+ Mon => 0,
+ Tue => 1,
+ Wed => 2,
+ Thu => 3,
+ Fri => 4,
+ Sat => 5,
+ Sun => 6,
+ }
+ }
+
+ pub fn num_days_from_sunday(&self) -> u32 {
+ use Weekday::*;
+ match *self {
+ Sun => 0,
+ Mon => 1,
+ Tue => 2,
+ Wed => 3,
+ Thu => 4,
+ Fri => 5,
+ Sat => 6,
+ }
+ }
+}
+
+/// Wrapper for zero-sized closures.
+// HACK(eddyb) Only needed because closures can't implement Copy.
+struct Fn0<F>(std::marker::PhantomData<F>);
+
+impl<F> Copy for Fn0<F> {}
+impl<F> Clone for Fn0<F> {
+ fn clone(&self) -> Self { *self }
+}
+
+impl<F: FnOnce<A>, A> FnOnce<A> for Fn0<F> {
+ type Output = F::Output;
+
+ extern "rust-call" fn call_once(self, args: A) -> Self::Output {
+ let f = unsafe { std::mem::uninitialized::<F>() };
+ f.call_once(args)
+ }
+}
+
+impl<F: FnMut<A>, A> FnMut<A> for Fn0<F> {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output {
+ let mut f = unsafe { std::mem::uninitialized::<F>() };
+ f.call_mut(args)
+ }
+}
+
+trait AsFn0<A>: Sized {
+ fn copyable(self) -> Fn0<Self>;
+}
+
+impl<F: FnMut<A>, A> AsFn0<A> for F {
+ fn copyable(self) -> Fn0<Self> {
+ assert_eq!(std::mem::size_of::<F>(), 0);
+ Fn0(std::marker::PhantomData)
+ }
+}
+
+/// GroupBy implementation.
+struct GroupBy<It: Iterator, F> {
+ it: std::iter::Peekable<It>,
+ f: F,
+}
+
+impl<It, F> Clone for GroupBy<It, F>
+where It: Iterator + Clone, It::Item: Clone, F: Clone {
+ fn clone(&self) -> GroupBy<It, F> {
+ GroupBy {
+ it: self.it.clone(),
+ f: self.f.clone()
+ }
+ }
+}
+
+impl<'a, G, It: 'a, F: 'a> Iterator for GroupBy<It, F>
+where It: Iterator + Clone,
+ It::Item: Clone,
+ F: Clone + FnMut(&It::Item) -> G,
+ G: Eq + Clone
+{
+ type Item = (G, InGroup<std::iter::Peekable<It>, F, G>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.it.peek().map(&mut self.f).map(|key| {
+ let start = self.it.clone();
+ while let Some(k) = self.it.peek().map(&mut self.f) {
+ if key != k {
+ break;
+ }
+ self.it.next();
+ }
+
+ (key.clone(), InGroup {
+ it: start,
+ f: self.f.clone(),
+ g: key
+ })
+ })
+ }
+}
+
+#[derive(Copy, Clone)]
+struct InGroup<It, F, G> {
+ it: It,
+ f: F,
+ g: G
+}
+
+impl<It: Iterator, F: FnMut(&It::Item) -> G, G: Eq> Iterator for InGroup<It, F, G> {
+ type Item = It::Item;
+
+ fn next(&mut self) -> Option<It::Item> {
+ self.it.next().and_then(|x| {
+ if (self.f)(&x) == self.g { Some(x) } else { None }
+ })
+ }
+}
+
+trait IteratorExt: Iterator + Sized {
+ fn group_by<G, F>(self, f: F) -> GroupBy<Self, Fn0<F>>
+ where F: FnMut(&Self::Item) -> G,
+ G: Eq
+ {
+ GroupBy {
+ it: self.peekable(),
+ f: f.copyable(),
+ }
+ }
+
+ fn join(mut self, sep: &str) -> String
+ where Self::Item: std::fmt::Display {
+ let mut s = String::new();
+ if let Some(e) = self.next() {
+ write!(s, "{}", e);
+ for e in self {
+ s.push_str(sep);
+ write!(s, "{}", e);
+ }
+ }
+ s
+ }
+
+ // HACK(eddyb) Only needed because `impl Trait` can't be
+ // used with trait methods: `.foo()` becomes `.__(foo)`.
+ fn __<F, R>(self, f: F) -> R
+ where F: FnOnce(Self) -> R {
+ f(self)
+ }
+}
+
+impl<It> IteratorExt for It where It: Iterator {}
+
+///
+/// Generates an iterator that yields exactly n spaces.
+///
+fn spaces(n: usize) -> std::iter::Take<std::iter::Repeat<char>> {
+ std::iter::repeat(' ').take(n)
+}
+
+fn test_spaces() {
+ assert_eq!(spaces(0).collect::<String>(), "");
+ assert_eq!(spaces(10).collect::<String>(), " ")
+}
+
+///
+/// Returns an iterator of dates in a given year.
+///
+fn dates_in_year(year: i32) -> impl Iterator<Item=NaiveDate>+Clone {
+ InGroup {
+ it: NaiveDate::from_ymd(year, 1, 1)..,
+ f: (|d: &NaiveDate| d.year()).copyable(),
+ g: year
+ }
+}
+
+fn test_dates_in_year() {
+ {
+ let mut dates = dates_in_year(2013);
+ assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 1)));
+
+ // Check increment
+ assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 2)));
+
+ // Check monthly rollover
+ for _ in 3..31 {
+ assert!(dates.next() != None);
+ }
+
+ assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 31)));
+ assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 2, 1)));
+ }
+
+ {
+ // Check length of year
+ let mut dates = dates_in_year(2013);
+ for _ in 0..365 {
+ assert!(dates.next() != None);
+ }
+ assert_eq!(dates.next(), None);
+ }
+
+ {
+ // Check length of leap year
+ let mut dates = dates_in_year(1984);
+ for _ in 0..366 {
+ assert!(dates.next() != None);
+ }
+ assert_eq!(dates.next(), None);
+ }
+}
+
+///
+/// Convenience trait for verifying that a given type iterates over
+/// `NaiveDate`s.
+///
+trait DateIterator: Iterator<Item=NaiveDate> + Clone {}
+impl<It> DateIterator for It where It: Iterator<Item=NaiveDate> + Clone {}
+
+fn test_group_by() {
+ let input = [
+ [1, 1],
+ [1, 1],
+ [1, 2],
+ [2, 2],
+ [2, 3],
+ [2, 3],
+ [3, 3]
+ ];
+
+ let by_x = input.iter().cloned().group_by(|a| a[0]);
+ let expected_1: &[&[[i32; 2]]] = &[
+ &[[1, 1], [1, 1], [1, 2]],
+ &[[2, 2], [2, 3], [2, 3]],
+ &[[3, 3]]
+ ];
+ for ((_, a), b) in by_x.zip(expected_1.iter().cloned()) {
+ assert_eq!(&a.collect::<Vec<_>>()[..], b);
+ }
+
+ let by_y = input.iter().cloned().group_by(|a| a[1]);
+ let expected_2: &[&[[i32; 2]]] = &[
+ &[[1, 1], [1, 1]],
+ &[[1, 2], [2, 2]],
+ &[[2, 3], [2, 3], [3, 3]]
+ ];
+ for ((_, a), b) in by_y.zip(expected_2.iter().cloned()) {
+ assert_eq!(&a.collect::<Vec<_>>()[..], b);
+ }
+}
+
+///
+/// Groups an iterator of dates by month.
+///
+fn by_month<It>(it: It)
+ -> impl Iterator<Item=(u32, impl Iterator<Item=NaiveDate> + Clone)> + Clone
+where It: Iterator<Item=NaiveDate> + Clone {
+ it.group_by(|d| d.month())
+}
+
+fn test_by_month() {
+ let mut months = dates_in_year(2013).__(by_month);
+ for (month, (_, mut date)) in (1..13).zip(&mut months) {
+ assert_eq!(date.nth(0).unwrap(), NaiveDate::from_ymd(2013, month, 1));
+ }
+ assert!(months.next().is_none());
+}
+
+///
+/// Groups an iterator of dates by week.
+///
+fn by_week<It>(it: It)
+ -> impl Iterator<Item=(u32, impl DateIterator)> + Clone
+where It: DateIterator {
+ // We go forward one day because `isoweekdate` considers the week to start on a Monday.
+ it.group_by(|d| d.succ().isoweekdate().1)
+}
+
+fn test_isoweekdate() {
+ fn weeks_uniq(year: i32) -> Vec<((i32, u32), u32)> {
+ let mut weeks = dates_in_year(year).map(|d| d.isoweekdate())
+ .map(|(y,w,_)| (y,w));
+ let mut result = vec![];
+ let mut accum = (weeks.next().unwrap(), 1);
+ for yw in weeks {
+ if accum.0 == yw {
+ accum.1 += 1;
+ } else {
+ result.push(accum);
+ accum = (yw, 1);
+ }
+ }
+ result.push(accum);
+ result
+ }
+
+ let wu_1984 = weeks_uniq(1984);
+ assert_eq!(&wu_1984[..2], &[((1983, 52), 1), ((1984, 1), 7)]);
+ assert_eq!(&wu_1984[wu_1984.len()-2..], &[((1984, 52), 7), ((1985, 1), 1)]);
+
+ let wu_2013 = weeks_uniq(2013);
+ assert_eq!(&wu_2013[..2], &[((2013, 1), 6), ((2013, 2), 7)]);
+ assert_eq!(&wu_2013[wu_2013.len()-2..], &[((2013, 52), 7), ((2014, 1), 2)]);
+
+ let wu_2015 = weeks_uniq(2015);
+ assert_eq!(&wu_2015[..2], &[((2015, 1), 4), ((2015, 2), 7)]);
+ assert_eq!(&wu_2015[wu_2015.len()-2..], &[((2015, 52), 7), ((2015, 53), 4)]);
+}
+
+fn test_by_week() {
+ let mut weeks = dates_in_year(2013).__(by_week);
+ assert_eq!(
+ &*weeks.next().unwrap().1.collect::<Vec<_>>(),
+ &[
+ NaiveDate::from_ymd(2013, 1, 1),
+ NaiveDate::from_ymd(2013, 1, 2),
+ NaiveDate::from_ymd(2013, 1, 3),
+ NaiveDate::from_ymd(2013, 1, 4),
+ NaiveDate::from_ymd(2013, 1, 5),
+ ]
+ );
+ assert_eq!(
+ &*weeks.next().unwrap().1.collect::<Vec<_>>(),
+ &[
+ NaiveDate::from_ymd(2013, 1, 6),
+ NaiveDate::from_ymd(2013, 1, 7),
+ NaiveDate::from_ymd(2013, 1, 8),
+ NaiveDate::from_ymd(2013, 1, 9),
+ NaiveDate::from_ymd(2013, 1, 10),
+ NaiveDate::from_ymd(2013, 1, 11),
+ NaiveDate::from_ymd(2013, 1, 12),
+ ]
+ );
+ assert_eq!(weeks.next().unwrap().1.nth(0).unwrap(), NaiveDate::from_ymd(2013, 1, 13));
+}
+
+/// The number of columns per day in the formatted output.
+const COLS_PER_DAY: u32 = 3;
+
+/// The number of columns per week in the formatted output.
+const COLS_PER_WEEK: u32 = 7 * COLS_PER_DAY;
+
+///
+/// Formats an iterator of weeks into an iterator of strings.
+///
+fn format_weeks<It>(it: It) -> impl Iterator<Item=String>
+where It: Iterator, It::Item: DateIterator {
+ it.map(|week| {
+ let mut buf = String::with_capacity((COLS_PER_DAY * COLS_PER_WEEK + 2) as usize);
+
+ // Format each day into its own cell and append to target string.
+ let mut last_day = 0;
+ let mut first = true;
+ for d in week {
+ last_day = d.weekday().num_days_from_sunday();
+
+ // Insert enough filler to align the first day with its respective day-of-week.
+ if first {
+ buf.extend(spaces((COLS_PER_DAY * last_day) as usize));
+ first = false;
+ }
+
+ write!(buf, " {:>2}", d.day());
+ }
+
+ // Insert more filler at the end to fill up the remainder of the week,
+ // if its a short week (e.g. at the end of the month).
+ buf.extend(spaces((COLS_PER_DAY * (6 - last_day)) as usize));
+ buf
+ })
+}
+
+fn test_format_weeks() {
+ let jan_2013 = dates_in_year(2013)
+ .__(by_month).next() // pick January 2013 for testing purposes
+ // NOTE: This `map` is because `next` returns an `Option<_>`.
+ .map(|(_, month)|
+ month.__(by_week)
+ .map(|(_, weeks)| weeks)
+ .__(format_weeks)
+ .join("\n"));
+
+ assert_eq!(
+ jan_2013.as_ref().map(|s| &**s),
+ Some(" 1 2 3 4 5\n\
+ \x20 6 7 8 9 10 11 12\n\
+ \x2013 14 15 16 17 18 19\n\
+ \x2020 21 22 23 24 25 26\n\
+ \x2027 28 29 30 31 ")
+ );
+}
+
+///
+/// Formats the name of a month, centered on COLS_PER_WEEK.
+///
+fn month_title(month: u32) -> String {
+ const MONTH_NAMES: &'static [&'static str] = &[
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ ];
+ assert_eq!(MONTH_NAMES.len(), 12);
+
+ // Determine how many spaces before and after the month name
+ // we need to center it over the formatted weeks in the month.
+ let name = MONTH_NAMES[(month - 1) as usize];
+ assert!(name.len() < COLS_PER_WEEK as usize);
+ let before = (COLS_PER_WEEK as usize - name.len()) / 2;
+ let after = COLS_PER_WEEK as usize - name.len() - before;
+
+ // NOTE: Being slightly more verbose to avoid extra allocations.
+ let mut result = String::with_capacity(COLS_PER_WEEK as usize);
+ result.extend(spaces(before));
+ result.push_str(name);
+ result.extend(spaces(after));
+ result
+}
+
+fn test_month_title() {
+ assert_eq!(month_title(1).len(), COLS_PER_WEEK as usize);
+}
+
+///
+/// Formats a month.
+///
+fn format_month<It: DateIterator>(it: It) -> impl Iterator<Item=String> {
+ let mut month_days = it.peekable();
+ let title = month_title(month_days.peek().unwrap().month());
+
+ Some(title).into_iter()
+ .chain(month_days.__(by_week)
+ .map(|(_, week)| week)
+ .__(format_weeks))
+}
+
+fn test_format_month() {
+ let month_fmt = dates_in_year(2013)
+ .__(by_month).next() // Pick January as a test case
+ .map(|(_, days)| days.into_iter()
+ .__(format_month)
+ .join("\n"));
+
+ assert_eq!(
+ month_fmt.as_ref().map(|s| &**s),
+ Some(" January \n\
+ \x20 1 2 3 4 5\n\
+ \x20 6 7 8 9 10 11 12\n\
+ \x2013 14 15 16 17 18 19\n\
+ \x2020 21 22 23 24 25 26\n\
+ \x2027 28 29 30 31 ")
+ );
+}
+
+
+///
+/// Formats an iterator of months.
+///
+fn format_months<It>(it: It) -> impl Iterator<Item=impl Iterator<Item=String>>
+where It: Iterator, It::Item: DateIterator {
+ it.map(format_month)
+}
+
+///
+/// Takes an iterator of iterators of strings; the sub-iterators are consumed
+/// in lock-step, with their elements joined together.
+///
+trait PasteBlocks: Iterator + Sized
+where Self::Item: Iterator<Item=String> {
+ fn paste_blocks(self, sep_width: usize) -> PasteBlocksIter<Self::Item> {
+ PasteBlocksIter {
+ iters: self.collect(),
+ cache: vec![],
+ col_widths: None,
+ sep_width: sep_width,
+ }
+ }
+}
+
+impl<It> PasteBlocks for It where It: Iterator, It::Item: Iterator<Item=String> {}
+
+struct PasteBlocksIter<StrIt>
+where StrIt: Iterator<Item=String> {
+ iters: Vec<StrIt>,
+ cache: Vec<Option<String>>,
+ col_widths: Option<Vec<usize>>,
+ sep_width: usize,
+}
+
+impl<StrIt> Iterator for PasteBlocksIter<StrIt>
+where StrIt: Iterator<Item=String> {
+ type Item = String;
+
+ fn next(&mut self) -> Option<String> {
+ self.cache.clear();
+
+ // `cache` is now the next line from each iterator.
+ self.cache.extend(self.iters.iter_mut().map(|it| it.next()));
+
+ // If every line in `cache` is `None`, we have nothing further to do.
+ if self.cache.iter().all(|e| e.is_none()) { return None }
+
+ // Get the column widths if we haven't already.
+ let col_widths = match self.col_widths {
+ Some(ref v) => &**v,
+ None => {
+ self.col_widths = Some(self.cache.iter()
+ .map(|ms| ms.as_ref().map(|s| s.len()).unwrap_or(0))
+ .collect());
+ &**self.col_widths.as_ref().unwrap()
+ }
+ };
+
+ // Fill in any `None`s with spaces.
+ let mut parts = col_widths.iter().cloned().zip(self.cache.iter_mut())
+ .map(|(w,ms)| ms.take().unwrap_or_else(|| spaces(w).collect()));
+
+ // Join them all together.
+ let first = parts.next().unwrap_or(String::new());
+ let sep_width = self.sep_width;
+ Some(parts.fold(first, |mut accum, next| {
+ accum.extend(spaces(sep_width));
+ accum.push_str(&next);
+ accum
+ }))
+ }
+}
+
+fn test_paste_blocks() {
+ let row = dates_in_year(2013)
+ .__(by_month).map(|(_, days)| days)
+ .take(3)
+ .__(format_months)
+ .paste_blocks(1)
+ .join("\n");
+ assert_eq!(
+ &*row,
+ " January February March \n\
+ \x20 1 2 3 4 5 1 2 1 2\n\
+ \x20 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9\n\
+ \x2013 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16\n\
+ \x2020 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23\n\
+ \x2027 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30\n\
+ \x20 31 "
+ );
+}
+
+///
+/// Produces an iterator that yields `n` elements at a time.
+///
+trait Chunks: Iterator + Sized {
+ fn chunks(self, n: usize) -> ChunksIter<Self> {
+ assert!(n > 0);
+ ChunksIter {
+ it: self,
+ n: n,
+ }
+ }
+}
+
+impl<It> Chunks for It where It: Iterator {}
+
+struct ChunksIter<It>
+where It: Iterator {
+ it: It,
+ n: usize,
+}
+
+// NOTE: `chunks` in Rust is more-or-less impossible without overhead of some kind.
+// Aliasing rules mean you need to add dynamic borrow checking, and the design of
+// `Iterator` means that you need to have the iterator's state kept in an allocation
+// that is jointly owned by the iterator itself and the sub-iterator.
+// As such, I've chosen to cop-out and just heap-allocate each chunk.
+
+impl<It> Iterator for ChunksIter<It>
+where It: Iterator {
+ type Item = Vec<It::Item>;
+
+ fn next(&mut self) -> Option<Vec<It::Item>> {
+ let first = match self.it.next() {
+ Some(e) => e,
+ None => return None
+ };
+
+ let mut result = Vec::with_capacity(self.n);
+ result.push(first);
+
+ Some((&mut self.it).take(self.n-1)
+ .fold(result, |mut acc, next| { acc.push(next); acc }))
+ }
+}
+
+fn test_chunks() {
+ let r = &[1, 2, 3, 4, 5, 6, 7];
+ let c = r.iter().cloned().chunks(3).collect::<Vec<_>>();
+ assert_eq!(&*c, &[vec![1, 2, 3], vec![4, 5, 6], vec![7]]);
+}
+
+///
+/// Formats a year.
+///
+fn format_year(year: i32, months_per_row: usize) -> String {
+ const COL_SPACING: usize = 1;
+
+ // Start by generating all dates for the given year.
+ dates_in_year(year)
+
+ // Group them by month and throw away month number.
+ .__(by_month).map(|(_, days)| days)
+
+ // Group the months into horizontal rows.
+ .chunks(months_per_row)
+
+ // Format each row
+ .map(|r| r.into_iter()
+ // By formatting each month
+ .__(format_months)
+
+ // Horizontally pasting each respective month's lines together.
+ .paste_blocks(COL_SPACING)
+ .join("\n")
+ )
+
+ // Insert a blank line between each row
+ .join("\n\n")
+}
+
+fn test_format_year() {
+ const MONTHS_PER_ROW: usize = 3;
+
+ macro_rules! assert_eq_cal {
+ ($lhs:expr, $rhs:expr) => {
+ if $lhs != $rhs {
+ println!("got:\n```\n{}\n```\n", $lhs.replace(" ", "."));
+ println!("expected:\n```\n{}\n```", $rhs.replace(" ", "."));
+ panic!("calendars didn't match!");
+ }
+ }
+ }
+
+ assert_eq_cal!(&format_year(1984, MONTHS_PER_ROW), "\
+\x20 January February March \n\
+\x20 1 2 3 4 5 6 7 1 2 3 4 1 2 3\n\
+\x20 8 9 10 11 12 13 14 5 6 7 8 9 10 11 4 5 6 7 8 9 10\n\
+\x2015 16 17 18 19 20 21 12 13 14 15 16 17 18 11 12 13 14 15 16 17\n\
+\x2022 23 24 25 26 27 28 19 20 21 22 23 24 25 18 19 20 21 22 23 24\n\
+\x2029 30 31 26 27 28 29 25 26 27 28 29 30 31\n\
+\n\
+\x20 April May June \n\
+\x20 1 2 3 4 5 6 7 1 2 3 4 5 1 2\n\
+\x20 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9\n\
+\x2015 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16\n\
+\x2022 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23\n\
+\x2029 30 27 28 29 30 31 24 25 26 27 28 29 30\n\
+\n\
+\x20 July August September \n\
+\x20 1 2 3 4 5 6 7 1 2 3 4 1\n\
+\x20 8 9 10 11 12 13 14 5 6 7 8 9 10 11 2 3 4 5 6 7 8\n\
+\x2015 16 17 18 19 20 21 12 13 14 15 16 17 18 9 10 11 12 13 14 15\n\
+\x2022 23 24 25 26 27 28 19 20 21 22 23 24 25 16 17 18 19 20 21 22\n\
+\x2029 30 31 26 27 28 29 30 31 23 24 25 26 27 28 29\n\
+\x20 30 \n\
+\n\
+\x20 October November December \n\
+\x20 1 2 3 4 5 6 1 2 3 1\n\
+\x20 7 8 9 10 11 12 13 4 5 6 7 8 9 10 2 3 4 5 6 7 8\n\
+\x2014 15 16 17 18 19 20 11 12 13 14 15 16 17 9 10 11 12 13 14 15\n\
+\x2021 22 23 24 25 26 27 18 19 20 21 22 23 24 16 17 18 19 20 21 22\n\
+\x2028 29 30 31 25 26 27 28 29 30 23 24 25 26 27 28 29\n\
+\x20 30 31 ");
+
+ assert_eq_cal!(&format_year(2015, MONTHS_PER_ROW), "\
+\x20 January February March \n\
+\x20 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6 7\n\
+\x20 4 5 6 7 8 9 10 8 9 10 11 12 13 14 8 9 10 11 12 13 14\n\
+\x2011 12 13 14 15 16 17 15 16 17 18 19 20 21 15 16 17 18 19 20 21\n\
+\x2018 19 20 21 22 23 24 22 23 24 25 26 27 28 22 23 24 25 26 27 28\n\
+\x2025 26 27 28 29 30 31 29 30 31 \n\
+\n\
+\x20 April May June \n\
+\x20 1 2 3 4 1 2 1 2 3 4 5 6\n\
+\x20 5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10 11 12 13\n\
+\x2012 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17 18 19 20\n\
+\x2019 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24 25 26 27\n\
+\x2026 27 28 29 30 24 25 26 27 28 29 30 28 29 30 \n\
+\x20 31 \n\
+\n\
+\x20 July August September \n\
+\x20 1 2 3 4 1 1 2 3 4 5\n\
+\x20 5 6 7 8 9 10 11 2 3 4 5 6 7 8 6 7 8 9 10 11 12\n\
+\x2012 13 14 15 16 17 18 9 10 11 12 13 14 15 13 14 15 16 17 18 19\n\
+\x2019 20 21 22 23 24 25 16 17 18 19 20 21 22 20 21 22 23 24 25 26\n\
+\x2026 27 28 29 30 31 23 24 25 26 27 28 29 27 28 29 30 \n\
+\x20 30 31 \n\
+\n\
+\x20 October November December \n\
+\x20 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5\n\
+\x20 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12\n\
+\x2011 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19\n\
+\x2018 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26\n\
+\x2025 26 27 28 29 30 31 29 30 27 28 29 30 31 ");
+}
+
+fn main() {
+ // Run tests.
+ test_spaces();
+ test_dates_in_year();
+ test_group_by();
+ test_by_month();
+ test_isoweekdate();
+ test_by_week();
+ test_format_weeks();
+ test_month_title();
+ test_format_month();
+ test_paste_blocks();
+ test_chunks();
+ test_format_year();
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait, question_mark)]
+
+struct State;
+type Error = ();
+
+trait Bind<F> {
+ type Output;
+ fn bind(self, f: F) -> Self::Output;
+}
+
+fn bind<T, U, A, B, F>(mut a: A, mut f: F)
+ -> impl FnMut(&mut State) -> Result<U, Error>
+where F: FnMut(T) -> B,
+ A: FnMut(&mut State) -> Result<T, Error>,
+ B: FnMut(&mut State) -> Result<U, Error>
+{
+ move |state | {
+ let r = a(state)?;
+ f(r)(state)
+ }
+}
+
+fn atom<T>(x: T) -> impl FnMut(&mut State) -> Result<T, Error> {
+ let mut x = Some(x);
+ move |_| x.take().map_or(Err(()), Ok)
+}
+
+fn main() {
+ assert_eq!(bind(atom(5), |x| atom(x > 4))(&mut State), Ok(true));
+}
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "solaris"))]
+ target_os = "solaris",
+ target_os = "emscripten"))]
mod m {
#[main]
#[cfg(target_arch = "x86")]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
// Make sure that if a process doesn't have its stdio/stderr descriptors set up
// that we don't die in a large ball of fire
// aux-build:issue-12133-dylib.rs
// aux-build:issue-12133-dylib2.rs
// ignore-musl
+// ignore-emscripten no dylib support
// pretty-expanded FIXME #23616
// except according to those terms.
// ignore-aarch64
+// ignore-emscripten
#![feature(io, process_capture)]
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
#![feature(io, process_capture)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
use std::env;
use std::process::Command;
// except according to those terms.
// ignore-aarch64
+// ignore-emscripten
use std::process::Command;
use std::env;
// except according to those terms.
// ignore-aarch64
+// ignore-emscripten
#![feature(std_misc, os)]
#[cfg(unix)]
// except according to those terms.
// pretty-expanded FIXME #23616
+// ignore-emscripten
use std::thread::Builder;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(dead_code)]
+static X: &'static str = &*"";
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
use std::thread;
use std::env;
use std::process::Command;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
// compile-flags: -Z orbit=off
// (blows the stack with MIR trans and no optimizations)
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: &'static str = "x";
+
+ {
+ let y = "y".to_string();
+ let ref mut x = &*x;
+ *x = &*y;
+ }
+
+ assert_eq!(x, "x");
+}
// except according to those terms.
// aux-build:issue-29485.rs
+// ignore-emscripten
#[feature(recover)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
// Previously libstd would set stdio descriptors of a child process
// by `dup`ing the requested descriptors to inherit directly into the
// stdio descriptors. This, however, would incorrectly handle cases
mod m1 {
fn f() {
- struct Z {
+ pub struct Z {
pub field: u8
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
use std::process::{Command, Stdio};
use std::env;
use std::sync::{Mutex, RwLock};
// ignore-windows
// ignore-macos
+// ignore-emscripten
// aux-build:linkage1.rs
#![feature(linkage)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
fn check_for_no_backtrace(test: std::process::Output) {
assert!(!test.status.success());
let err = String::from_utf8_lossy(&test.stderr);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
#![feature(libc)]
extern crate libc;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(relaxed_adts)]
+
+struct S(u8, u16);
+
+fn main() {
+ let s = S{1: 10, 0: 11};
+ match s {
+ S{0: a, 1: b, ..} => {
+ assert_eq!(a, 11);
+ assert_eq!(b, 10);
+ }
+ }
+}
// <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.
+
+// ignore-emscripten no threads support
+
#![feature(panic_handler, const_fn, std_panic)]
use std::sync::atomic::{AtomicUsize, Ordering};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
use std::env;
use std::process::{self, Command, Stdio};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
use std::process::Command;
use std::env;
// intact.
// ignore-aarch64
+// ignore-emscripten
use std::io::prelude::*;
use std::io;
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "solaris"))]
+ target_os = "solaris",
+ target_os = "emscripten"))]
mod m {
#[cfg(target_arch = "x86")]
pub mod m {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
+
#![feature(start)]
use std::ffi::CStr;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten can't run commands
+
#![feature(libc)]
extern crate libc;
// except according to those terms.
// ignore-windows
+// ignore-emscripten
use std::env;
use std::process::Command;
// doesn't die in a ball of fire, but rather it's gracefully handled.
// ignore-aarch64
+// ignore-emscripten
use std::env;
use std::io::prelude::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten no threads support
+
use std::thread::{self, sleep};
use std::time::Duration;
use std::sync::{Arc, Mutex};
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(specialization)]
+
+trait Specializable { type Output; }
+
+impl<T> Specializable for T {
+ default type Output = u16;
+}
+
+fn main() {
+ unsafe {
+ std::mem::transmute::<u16, <() as Specializable>::Output>(0);
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-emscripten
#![feature(libc)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern crate issue_28927_2 as inner2;
-pub use inner2 as bar;
+mod detail {
+ pub extern crate issue_28927_2 as inner2;
+}
+pub use detail::inner2 as bar;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+type MyResultPriv<T> = Result<T, u16>;
+pub type MyResultPub<T> = Result<T, u64>;
+
+// @has private_type_alias/fn.get_result_priv.html '//pre' 'Result<u8, u16>'
+pub fn get_result_priv() -> MyResultPriv<u8> {
+ panic!();
+}
+
+// @has private_type_alias/fn.get_result_pub.html '//pre' 'MyResultPub<u32>'
+pub fn get_result_pub() -> MyResultPub<u32> {
+ panic!();
+}
+
+pub type PubRecursive = u16;
+type PrivRecursive3 = u8;
+type PrivRecursive2 = PubRecursive;
+type PrivRecursive1 = PrivRecursive3;
+
+// PrivRecursive1 is expanded twice and stops at u8
+// PrivRecursive2 is expanded once and stops at public type alias PubRecursive
+// @has private_type_alias/fn.get_result_recursive.html '//pre' '(u8, PubRecursive)'
+pub fn get_result_recursive() -> (PrivRecursive1, PrivRecursive2) {
+ panic!();
+}
+
+type MyLifetimePriv<'a> = &'a isize;
+
+// @has private_type_alias/fn.get_lifetime_priv.html '//pre' "&'static isize"
+pub fn get_lifetime_priv() -> MyLifetimePriv<'static> {
+ panic!();
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #26083 and #35435
+// Test that span for public struct fields start at `pub`
+
+#![feature(pub_restricted)]
+
+struct Foo {
+ bar: u8,
+ pub bar: u8,
+ pub(crate) bar: u8,
+}
+
+fn main() {}
--- /dev/null
+error[E0124]: field `bar` is already declared
+ --> $DIR/pub-struct-field.rs:18:5
+ |
+17 | bar: u8,
+ | ------- `bar` first declared here
+18 | pub bar: u8,
+ | ^^^^^^^^^^^ field already declared
+
+error[E0124]: field `bar` is already declared
+ --> $DIR/pub-struct-field.rs:19:5
+ |
+17 | bar: u8,
+ | ------- `bar` first declared here
+18 | pub bar: u8,
+19 | pub(crate) bar: u8,
+ | ^^^^^^^^^^^^^^^^^^ field already declared
+
+error: aborting due to 2 previous errors
+
type Err = ();
fn from_str(s: &str) -> Result<Mode, ()> {
match s {
- "compile-fail" => Ok(CompileFail),
- "parse-fail" => Ok(ParseFail),
- "run-fail" => Ok(RunFail),
- "run-pass" => Ok(RunPass),
- "run-pass-valgrind" => Ok(RunPassValgrind),
- "pretty" => Ok(Pretty),
- "debuginfo-lldb" => Ok(DebugInfoLldb),
- "debuginfo-gdb" => Ok(DebugInfoGdb),
- "codegen" => Ok(Codegen),
- "rustdoc" => Ok(Rustdoc),
- "codegen-units" => Ok(CodegenUnits),
- "incremental" => Ok(Incremental),
- "run-make" => Ok(RunMake),
- "ui" => Ok(Ui),
- "mir-opt" => Ok(MirOpt),
- _ => Err(()),
+ "compile-fail" => Ok(CompileFail),
+ "parse-fail" => Ok(ParseFail),
+ "run-fail" => Ok(RunFail),
+ "run-pass" => Ok(RunPass),
+ "run-pass-valgrind" => Ok(RunPassValgrind),
+ "pretty" => Ok(Pretty),
+ "debuginfo-lldb" => Ok(DebugInfoLldb),
+ "debuginfo-gdb" => Ok(DebugInfoGdb),
+ "codegen" => Ok(Codegen),
+ "rustdoc" => Ok(Rustdoc),
+ "codegen-units" => Ok(CodegenUnits),
+ "incremental" => Ok(Incremental),
+ "run-make" => Ok(RunMake),
+ "ui" => Ok(Ui),
+ "mir-opt" => Ok(MirOpt),
+ _ => Err(()),
}
}
}
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(match *self {
- CompileFail => "compile-fail",
- ParseFail => "parse-fail",
- RunFail => "run-fail",
- RunPass => "run-pass",
- RunPassValgrind => "run-pass-valgrind",
- Pretty => "pretty",
- DebugInfoGdb => "debuginfo-gdb",
- DebugInfoLldb => "debuginfo-lldb",
- Codegen => "codegen",
- Rustdoc => "rustdoc",
- CodegenUnits => "codegen-units",
- Incremental => "incremental",
- RunMake => "run-make",
- Ui => "ui",
- MirOpt => "mir-opt",
- }, f)
+ CompileFail => "compile-fail",
+ ParseFail => "parse-fail",
+ RunFail => "run-fail",
+ RunPass => "run-pass",
+ RunPassValgrind => "run-pass-valgrind",
+ Pretty => "pretty",
+ DebugInfoGdb => "debuginfo-gdb",
+ DebugInfoLldb => "debuginfo-lldb",
+ Codegen => "codegen",
+ Rustdoc => "rustdoc",
+ CodegenUnits => "codegen-units",
+ Incremental => "incremental",
+ RunMake => "run-make",
+ Ui => "ui",
+ MirOpt => "mir-opt",
+ },
+ f)
}
}
}
#[derive(PartialEq, Debug)]
-enum WhichLine { ThisLine, FollowPrevious(usize), AdjustBackward(usize) }
+enum WhichLine {
+ ThisLine,
+ FollowPrevious(usize),
+ AdjustBackward(usize),
+}
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
/// The former is a "follow" that inherits its target from the preceding line;
let tag = match cfg {
Some(rev) => format!("//[{}]~", rev),
- None => format!("//~")
+ None => format!("//~"),
};
rdr.lines()
- .enumerate()
- .filter_map(|(line_num, line)| {
- parse_expected(last_nonfollow_error,
- line_num + 1,
- &line.unwrap(),
- &tag)
- .map(|(which, error)| {
- match which {
- FollowPrevious(_) => {}
- _ => last_nonfollow_error = Some(error.line_num),
- }
- error
- })
- })
- .collect()
+ .enumerate()
+ .filter_map(|(line_num, line)| {
+ parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), &tag)
+ .map(|(which, error)| {
+ match which {
+ FollowPrevious(_) => {}
+ _ => last_nonfollow_error = Some(error.line_num),
+ }
+ error
+ })
+ })
+ .collect()
}
fn parse_expected(last_nonfollow_error: Option<usize>,
line: &str,
tag: &str)
-> Option<(WhichLine, Error)> {
- let start = match line.find(tag) { Some(i) => i, None => return None };
+ let start = match line.find(tag) {
+ Some(i) => i,
+ None => return None,
+ };
let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' {
(true, 0)
} else {
};
let kind_start = start + tag.len() + adjusts + (follow as usize);
let (kind, msg);
- match
- line[kind_start..].split_whitespace()
- .next()
- .expect("Encountered unexpected empty comment")
- .parse::<ErrorKind>()
- {
+ match line[kind_start..]
+ .split_whitespace()
+ .next()
+ .expect("Encountered unexpected empty comment")
+ .parse::<ErrorKind>() {
Ok(k) => {
// If we find `//~ ERROR foo` or something like that:
kind = Some(k);
let letters = line[kind_start..].chars();
msg = letters.skip_while(|c| c.is_whitespace())
- .skip_while(|c| !c.is_whitespace())
- .collect::<String>();
+ .skip_while(|c| !c.is_whitespace())
+ .collect::<String>();
}
Err(_) => {
// Otherwise we found `//~ foo`:
kind = None;
let letters = line[kind_start..].chars();
msg = letters.skip_while(|c| c.is_whitespace())
- .collect::<String>();
+ .collect::<String>();
}
}
let msg = msg.trim().to_owned();
preceding //~^ line.");
(FollowPrevious(line_num), line_num)
} else {
- let which =
- if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
+ let which = if adjusts > 0 {
+ AdjustBackward(adjusts)
+ } else {
+ ThisLine
+ };
let line_num = line_num - adjusts;
(which, line_num)
};
debug!("line={} tag={:?} which={:?} kind={:?} msg={:?}",
- line_num, tag, which, kind, msg);
- Some((which, Error { line_num: line_num,
- kind: kind,
- msg: msg, }))
+ line_num,
+ tag,
+ which,
+ kind,
+ msg);
+ Some((which,
+ Error {
+ line_num: line_num,
+ kind: kind,
+ msg: msg,
+ }))
}
should_fail: false,
};
- iter_header(testfile, None, &mut |ln| {
+ iter_header(testfile,
+ None,
+ &mut |ln| {
props.ignore =
- props.ignore ||
- parse_name_directive(ln, "ignore-test") ||
+ props.ignore || parse_name_directive(ln, "ignore-test") ||
parse_name_directive(ln, &ignore_target(config)) ||
parse_name_directive(ln, &ignore_architecture(config)) ||
parse_name_directive(ln, &ignore_stage(config)) ||
parse_name_directive(ln, &ignore_env(config)) ||
- (config.mode == common::Pretty &&
- parse_name_directive(ln, "ignore-pretty")) ||
+ (config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) ||
(config.target != config.host &&
parse_name_directive(ln, "ignore-cross-compile")) ||
- ignore_gdb(config, ln) ||
- ignore_lldb(config, ln);
+ ignore_gdb(config, ln) || ignore_lldb(config, ln);
- props.should_fail =
- props.should_fail ||
- parse_name_directive(ln, "should-fail");
+ props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail");
});
return props;
format!("ignore-{}", util::get_arch(&config.target))
}
fn ignore_stage(config: &Config) -> String {
- format!("ignore-{}",
- config.stage_id.split('-').next().unwrap())
+ format!("ignore-{}", config.stage_id.split('-').next().unwrap())
}
fn ignore_env(config: &Config) -> String {
- format!("ignore-{}", util::get_env(&config.target).unwrap_or("<unknown>"))
+ format!("ignore-{}",
+ util::get_env(&config.target).unwrap_or("<unknown>"))
}
fn ignore_gdb(config: &Config, line: &str) -> bool {
if config.mode != common::DebugInfoGdb {
if let Some(ref actual_version) = config.gdb_version {
if line.contains("min-gdb-version") {
let min_version = line.trim()
- .split(' ')
- .last()
- .expect("Malformed GDB version directive");
+ .split(' ')
+ .last()
+ .expect("Malformed GDB version directive");
// Ignore if actual version is smaller the minimum required
// version
- gdb_version_to_int(actual_version) <
- gdb_version_to_int(min_version)
+ gdb_version_to_int(actual_version) < gdb_version_to_int(min_version)
} else {
false
}
if let Some(ref actual_version) = config.lldb_version {
if line.contains("min-lldb-version") {
let min_version = line.trim()
- .split(' ')
- .last()
- .expect("Malformed lldb version directive");
+ .split(' ')
+ .last()
+ .expect("Malformed lldb version directive");
// Ignore if actual version is smaller the minimum required
// version
- lldb_version_to_int(actual_version) <
- lldb_version_to_int(min_version)
+ lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
} else {
false
}
#[derive(Clone, Debug)]
pub struct TestProps {
// Lines that should be expected, in order, on standard out
- pub error_patterns: Vec<String> ,
+ pub error_patterns: Vec<String>,
// Extra flags to pass to the compiler
pub compile_flags: Vec<String>,
// Extra flags to pass when the compiled code is run (such as --bench)
// Other crates that should be compiled (typically from the same
// directory as the test, but for backwards compatibility reasons
// we also check the auxiliary directory)
- pub aux_builds: Vec<String> ,
+ pub aux_builds: Vec<String>,
// Environment settings to use for compiling
- pub rustc_env: Vec<(String,String)> ,
+ pub rustc_env: Vec<(String, String)>,
// Environment settings to use during execution
- pub exec_env: Vec<(String,String)> ,
+ pub exec_env: Vec<(String, String)>,
// Lines to check if they appear in the expected debugger output
- pub check_lines: Vec<String> ,
+ pub check_lines: Vec<String>,
// Build documentation for all specified aux-builds as well
pub build_aux_docs: bool,
// Flag to force a crate to be built with the host architecture
/// tied to a particular revision `foo` (indicated by writing
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
- pub fn load_from(&mut self, testfile: &Path, cfg: Option<&str>) {
- iter_header(testfile, cfg, &mut |ln| {
+ pub fn load_from(&mut self, testfile: &Path, cfg: Option<&str>) {
+ iter_header(testfile,
+ cfg,
+ &mut |ln| {
if let Some(ep) = parse_error_pattern(ln) {
self.error_patterns.push(ep);
}
if let Some(flags) = parse_compile_flags(ln) {
- self.compile_flags.extend(
- flags
- .split_whitespace()
- .map(|s| s.to_owned()));
+ self.compile_flags.extend(flags.split_whitespace()
+ .map(|s| s.to_owned()));
}
if let Some(r) = parse_revisions(ln) {
self.pretty_compare_only = parse_pretty_compare_only(ln);
}
- if let Some(ab) = parse_aux_build(ln) {
+ if let Some(ab) = parse_aux_build(ln) {
self.aux_builds.push(ab);
}
self.rustc_env.push(ee);
}
- if let Some(cl) = parse_check_line(ln) {
+ if let Some(cl) = parse_check_line(ln) {
self.check_lines.push(cl);
}
for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
match env::var(key) {
- Ok(val) =>
+ Ok(val) => {
if self.exec_env.iter().find(|&&(ref x, _)| *x == key).is_none() {
self.exec_env.push((key.to_owned(), val))
- },
+ }
+ }
Err(..) => {}
}
}
}
}
-fn iter_header(testfile: &Path,
- cfg: Option<&str>,
- it: &mut FnMut(&str)) {
+fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
if testfile.is_dir() {
- return
+ return;
}
let rdr = BufReader::new(File::open(testfile).unwrap());
for ln in rdr.lines() {
None => false,
};
if matches {
- it(&ln[close_brace+1..]);
+ it(&ln[close_brace + 1..]);
}
} else {
panic!("malformed condition directive: expected `//[foo]`, found `{}`",
fn parse_env(line: &str, name: &str) -> Option<(String, String)> {
parse_name_value_directive(line, name).map(|nv| {
// nv is either FOO or FOO=BAR
- let mut strs: Vec<String> = nv
- .splitn(2, '=')
- .map(str::to_owned)
- .collect();
+ let mut strs: Vec<String> = nv.splitn(2, '=')
+ .map(str::to_owned)
+ .collect();
match strs.len() {
- 1 => (strs.pop().unwrap(), "".to_owned()),
- 2 => {
- let end = strs.pop().unwrap();
- (strs.pop().unwrap(), end)
- }
- n => panic!("Expected 1 or 2 strings, not {}", n)
+ 1 => (strs.pop().unwrap(), "".to_owned()),
+ 2 => {
+ let end = strs.pop().unwrap();
+ (strs.pop().unwrap(), end)
+ }
+ n => panic!("Expected 1 or 2 strings, not {}", n),
}
})
}
line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
}
-pub fn parse_name_value_directive(line: &str, directive: &str)
- -> Option<String> {
+pub fn parse_name_value_directive(line: &str, directive: &str) -> Option<String> {
let keycolon = format!("{}:", directive);
if let Some(colon) = line.find(&keycolon) {
- let value = line[(colon + keycolon.len()) .. line.len()].to_owned();
+ let value = line[(colon + keycolon.len())..line.len()].to_owned();
debug!("{}: {}", directive, value);
Some(value)
} else {
}
pub fn gdb_version_to_int(version_string: &str) -> isize {
- let error_string = format!(
- "Encountered GDB version string with unexpected format: {}",
- version_string);
+ let error_string = format!("Encountered GDB version string with unexpected format: {}",
+ version_string);
let error_string = error_string;
let components: Vec<&str> = version_string.trim().split('.').collect();
}
pub fn lldb_version_to_int(version_string: &str) -> isize {
- let error_string = format!(
- "Encountered LLDB version string with unexpected format: {}",
- version_string);
+ let error_string = format!("Encountered LLDB version string with unexpected format: {}",
+ version_string);
let error_string = error_string;
let major: isize = version_string.parse().ok().expect(&error_string);
return major;
use rustc_serialize::json;
use std::str::FromStr;
use std::path::Path;
-use runtest::{ProcRes};
+use runtest::ProcRes;
// These structs are a subset of the ones found in
// `syntax::json`.
pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
output.lines()
- .flat_map(|line| parse_line(file_name, line, output, proc_res))
- .collect()
+ .flat_map(|line| parse_line(file_name, line, output, proc_res))
+ .collect()
}
fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
expected_errors
}
Err(error) => {
- proc_res.fatal(Some(&format!(
- "failed to decode compiler output as json: `{}`\noutput: {}\nline: {}",
- error, line, output)));
+ proc_res.fatal(Some(&format!("failed to decode compiler output as json: \
+ `{}`\noutput: {}\nline: {}",
+ error,
+ line,
+ output)));
}
}
} else {
diagnostic: &Diagnostic,
default_spans: &[&DiagnosticSpan],
file_name: &str) {
- let spans_in_this_file: Vec<_> =
- diagnostic.spans.iter()
- .filter(|span| Path::new(&span.file_name) == Path::new(&file_name))
- .collect();
-
- let primary_spans: Vec<_> =
- spans_in_this_file.iter()
- .cloned()
- .filter(|span| span.is_primary)
- .collect();
+ let spans_in_this_file: Vec<_> = diagnostic.spans
+ .iter()
+ .filter(|span| Path::new(&span.file_name) == Path::new(&file_name))
+ .collect();
+
+ let primary_spans: Vec<_> = spans_in_this_file.iter()
+ .cloned()
+ .filter(|span| span.is_primary)
+ .collect();
let primary_spans = if primary_spans.is_empty() {
// subdiagnostics often don't have a span of their own;
// inherit the span from the parent in that case
for span in primary_spans {
let msg = with_code(span, first_line);
let kind = ErrorKind::from_str(&diagnostic.level).ok();
- expected_errors.push(
- Error {
- line_num: span.line_start,
- kind: kind,
- msg: msg,
- }
- );
+ expected_errors.push(Error {
+ line_num: span.line_start,
+ kind: kind,
+ msg: msg,
+ });
}
}
for next_line in message_lines {
for span in primary_spans {
- expected_errors.push(
- Error {
- line_num: span.line_start,
- kind: None,
- msg: with_code(span, next_line),
- }
- );
+ expected_errors.push(Error {
+ line_num: span.line_start,
+ kind: None,
+ msg: with_code(span, next_line),
+ });
}
}
let start_line = primary_spans.iter().map(|s| s.line_start).min().expect("\
every suggestion should have at least one span");
for (index, line) in rendered.lines().enumerate() {
- expected_errors.push(
- Error {
- line_num: start_line + index,
- kind: Some(ErrorKind::Suggestion),
- msg: line.to_string()
- }
- );
+ expected_errors.push(Error {
+ line_num: start_line + index,
+ kind: Some(ErrorKind::Suggestion),
+ msg: line.to_string(),
+ });
}
}
// Add notes for the backtrace
for span in primary_spans {
for frame in &span.expansion {
- push_backtrace(expected_errors,
- frame,
- file_name);
+ push_backtrace(expected_errors, frame, file_name);
}
}
// Add notes for any labels that appear in the message.
for span in spans_in_this_file.iter()
- .filter(|span| span.label.is_some())
- {
+ .filter(|span| span.label.is_some()) {
expected_errors.push(Error {
line_num: span.line_start,
kind: Some(ErrorKind::Note),
- msg: span.label.clone().unwrap()
+ msg: span.label.clone().unwrap(),
});
}
expansion: &DiagnosticSpanMacroExpansion,
file_name: &str) {
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
- expected_errors.push(
- Error {
- line_num: expansion.span.line_start,
- kind: Some(ErrorKind::Note),
- msg: format!("in this expansion of {}", expansion.macro_decl_name),
- }
- );
+ expected_errors.push(Error {
+ line_num: expansion.span.line_start,
+ kind: Some(ErrorKind::Note),
+ msg: format!("in this expansion of {}", expansion.macro_decl_name),
+ });
}
for previous_expansion in &expansion.span.expansion {
Err(_) => false
},
color: test::AutoColor,
+ test_threads: None,
}
}
use std::ffi::OsString;
use std::io::prelude::*;
use std::path::PathBuf;
-use std::process::{ExitStatus, Command, Child, Output, Stdio};
+use std::process::{Child, Command, ExitStatus, Output, Stdio};
pub fn dylib_env_var() -> &'static str {
if cfg!(windows) {
// search path for the child.
let var = dylib_env_var();
let mut path = env::split_paths(&env::var_os(var).unwrap_or(OsString::new()))
- .collect::<Vec<_>>();
+ .collect::<Vec<_>>();
if let Some(p) = aux_path {
path.insert(0, PathBuf::from(p))
}
cmd.env(var, newpath);
}
-pub struct Result {pub status: ExitStatus, pub out: String, pub err: String}
+pub struct Result {
+ pub status: ExitStatus,
+ pub out: String,
+ pub err: String,
+}
pub fn run(lib_path: &str,
prog: &str,
aux_path: Option<&str>,
args: &[String],
- env: Vec<(String, String)> ,
- input: Option<String>) -> Option<Result> {
+ env: Vec<(String, String)>,
+ input: Option<String>)
+ -> Option<Result> {
let mut cmd = Command::new(prog);
cmd.args(args)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped());
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
add_target_env(&mut cmd, lib_path, aux_path);
for (key, val) in env {
cmd.env(&key, &val);
if let Some(input) = input {
process.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
}
- let Output { status, stdout, stderr } =
- process.wait_with_output().unwrap();
+ let Output { status, stdout, stderr } = process.wait_with_output().unwrap();
Some(Result {
status: status,
out: String::from_utf8(stdout).unwrap(),
- err: String::from_utf8(stderr).unwrap()
+ err: String::from_utf8(stderr).unwrap(),
})
- },
- Err(..) => None
+ }
+ Err(..) => None,
}
}
pub fn run_background(lib_path: &str,
- prog: &str,
- aux_path: Option<&str>,
- args: &[String],
- env: Vec<(String, String)> ,
- input: Option<String>) -> Option<Child> {
+ prog: &str,
+ aux_path: Option<&str>,
+ args: &[String],
+ env: Vec<(String, String)>,
+ input: Option<String>)
+ -> Option<Child> {
let mut cmd = Command::new(prog);
cmd.args(args)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped());
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
add_target_env(&mut cmd, lib_path, aux_path);
for (key, val) in env {
cmd.env(&key, &val);
}
Some(process)
- },
- Err(..) => None
+ }
+ Err(..) => None,
}
}
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
let mut maxfiles: libc::c_int = 0;
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
- if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size,
- null_mut(), 0) != 0 {
+ if libc::sysctl(&mut mib[0],
+ 2,
+ &mut maxfiles as *mut _ as *mut _,
+ &mut size,
+ null_mut(),
+ 0) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling sysctl: {}", err);
}
// Fetch the current resource limits
- let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
+ let mut rlim = libc::rlimit {
+ rlim_cur: 0,
+ rlim_max: 0,
+ };
if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
pub fn diff_lines(actual: &str, expected: &str) -> Vec<String> {
// mega simplistic diff algorithm that just prints the things added/removed
- zip_all(actual.lines(), expected.lines()).enumerate().filter_map(|(i, (a,e))| {
- match (a, e) {
- (Some(a), Some(e)) => {
- if lines_match(e, a) {
- None
- } else {
- Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a))
+ zip_all(actual.lines(), expected.lines())
+ .enumerate()
+ .filter_map(|(i, (a, e))| {
+ match (a, e) {
+ (Some(a), Some(e)) => {
+ if lines_match(e, a) {
+ None
+ } else {
+ Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a))
+ }
}
- },
- (Some(a), None) => {
- Some(format!("{:3} -\n + |{}|\n", i, a))
- },
- (None, Some(e)) => {
- Some(format!("{:3} - |{}|\n +\n", i, e))
- },
- (None, None) => panic!("Cannot get here")
- }
- }).collect()
+ (Some(a), None) => Some(format!("{:3} -\n + |{}|\n", i, a)),
+ (None, Some(e)) => Some(format!("{:3} - |{}|\n +\n", i, e)),
+ (None, None) => panic!("Cannot get here"),
+ }
+ })
+ .collect()
}
fn lines_match(expected: &str, mut actual: &str) -> bool {
match actual.find(part) {
Some(j) => {
if i == 0 && j != 0 {
- return false
+ return false;
}
actual = &actual[j + part.len()..];
}
- None => {
- return false
- }
+ None => return false,
}
}
actual.is_empty() || expected.ends_with("[..]")
second: I2,
}
-impl<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>> Iterator for ZipAll<I1, I2> {
+impl<T, I1: Iterator<Item = T>, I2: Iterator<Item = T>> Iterator for ZipAll<I1, I2> {
type Item = (Option<T>, Option<T>);
fn next(&mut self) -> Option<(Option<T>, Option<T>)> {
let first = self.first.next();
match (first, second) {
(None, None) => None,
- (a, b) => Some((a, b))
+ (a, b) => Some((a, b)),
}
}
}
-fn zip_all<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>>(a: I1, b: I2) -> ZipAll<I1, I2> {
+fn zip_all<T, I1: Iterator<Item = T>, I2: Iterator<Item = T>>(a: I1, b: I2) -> ZipAll<I1, I2> {
ZipAll {
first: a,
second: b,
use common::Config;
/// Conversion table from triple OS name to Rust SYSNAME
-const OS_TABLE: &'static [(&'static str, &'static str)] = &[
- ("android", "android"),
- ("bitrig", "bitrig"),
- ("darwin", "macos"),
- ("dragonfly", "dragonfly"),
- ("freebsd", "freebsd"),
- ("ios", "ios"),
- ("linux", "linux"),
- ("mingw32", "windows"),
- ("netbsd", "netbsd"),
- ("openbsd", "openbsd"),
- ("win32", "windows"),
- ("windows", "windows"),
- ("solaris", "solaris"),
- ("emscripten", "emscripten"),
-];
+const OS_TABLE: &'static [(&'static str, &'static str)] = &[("android", "android"),
+ ("bitrig", "bitrig"),
+ ("darwin", "macos"),
+ ("dragonfly", "dragonfly"),
+ ("freebsd", "freebsd"),
+ ("ios", "ios"),
+ ("linux", "linux"),
+ ("mingw32", "windows"),
+ ("netbsd", "netbsd"),
+ ("openbsd", "openbsd"),
+ ("win32", "windows"),
+ ("windows", "windows"),
+ ("solaris", "solaris"),
+ ("emscripten", "emscripten")];
-const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
- ("aarch64", "aarch64"),
- ("amd64", "x86_64"),
- ("arm", "arm"),
- ("arm64", "aarch64"),
- ("hexagon", "hexagon"),
- ("i386", "x86"),
- ("i686", "x86"),
- ("mips", "mips"),
- ("msp430", "msp430"),
- ("powerpc", "powerpc"),
- ("powerpc64", "powerpc64"),
- ("s390x", "systemz"),
- ("sparc", "sparc"),
- ("x86_64", "x86_64"),
- ("xcore", "xcore"),
- ("asmjs", "asmjs"),
-];
+const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[("aarch64", "aarch64"),
+ ("amd64", "x86_64"),
+ ("arm", "arm"),
+ ("arm64", "aarch64"),
+ ("hexagon", "hexagon"),
+ ("i386", "x86"),
+ ("i686", "x86"),
+ ("mips", "mips"),
+ ("msp430", "msp430"),
+ ("powerpc", "powerpc"),
+ ("powerpc64", "powerpc64"),
+ ("s390x", "systemz"),
+ ("sparc", "sparc"),
+ ("x86_64", "x86_64"),
+ ("xcore", "xcore"),
+ ("asmjs", "asmjs")];
pub fn get_os(triple: &str) -> &'static str {
for &(triple_os, os) in OS_TABLE {
if triple.contains(triple_os) {
- return os
+ return os;
}
}
panic!("Cannot determine OS from triple");
pub fn get_arch(triple: &str) -> &'static str {
for &(triple_arch, arch) in ARCH_TABLE {
if triple.contains(triple_arch) {
- return arch
+ return arch;
}
}
panic!("Cannot determine Architecture from triple");
// Windows just uses PATH as the library search path, so we have to
// maintain the current value while adding our own
match env::var(lib_path_env_var()) {
- Ok(curr) => {
- format!("{}{}{}", path, path_div(), curr)
- }
- Err(..) => path.to_owned()
+ Ok(curr) => format!("{}{}{}", path, path_div(), curr),
+ Err(..) => path.to_owned(),
}
}
-pub fn lib_path_env_var() -> &'static str { "PATH" }
-fn path_div() -> &'static str { ";" }
+pub fn lib_path_env_var() -> &'static str {
+ "PATH"
+}
+fn path_div() -> &'static str {
+ ";"
+}
pub fn logv(config: &Config, s: String) {
debug!("{}", s);
- if config.verbose { println!("{}", s); }
+ if config.verbose {
+ println!("{}", s);
+ }
}