.project
.settings/
.valgrindrc
+.vscode/
/*-*-*-*/
/*-*-*/
/Makefile
.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
$$(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
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
- target.contains("msvc") {
+ target.contains("msvc") ||
+ target.contains("emscripten") {
build.config.use_jemalloc = false;
}
in different languages. To keep things simple, we’ll stick to ‘greetings’ and
‘farewells’ as two kinds of phrases, and use English and Japanese (日本語) as
two languages for those phrases to be in. We’ll use this module layout:
+
```text
+-----------+
+---| greetings |
y: i32,
}
-let origin = Point { x: 0, y: 0 };
+let point = Point { x: 2, y: 3 };
-match origin {
+match point {
Point { x, .. } => println!("x is {}", x),
}
```
-This prints `x is 0`.
+This prints `x is 2`.
You can do this kind of match on any member, not only the first:
y: i32,
}
-let origin = Point { x: 0, y: 0 };
+let point = Point { x: 2, y: 3 };
-match origin {
+match point {
Point { y, .. } => println!("y is {}", y),
}
```
-This prints `y is 0`.
+This prints `y is 3`.
This ‘destructuring’ behavior works on any compound data type, like
[tuples][tuples] or [enums][enums].
strong to weak:
```{.text .precedence}
-as
+as :
* / %
+ -
<< >>
&&
||
.. ...
+<-
=
```
#[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,
/// }
/// }
///
```
"##,
+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);
},
_ => ()
}
let &(ref first_arm_pats, _) = &arms[0];
let first_pat = &first_arm_pats[0];
let span = first_pat.span;
- span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern");
+ struct_span_err!(cx.tcx.sess, span, E0162,
+ "irrefutable if-let pattern")
+ .span_label(span, &format!("irrefutable pattern"))
+ .emit();
printed_if_let_err = true;
}
},
// 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)))
}
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};
self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data)
}
hir::ParenthesizedParameters(..) => {
- span_err!(tcx.sess, span, E0214,
- "parenthesized parameters may only be used with a trait");
+ struct_span_err!(tcx.sess, span, E0214,
+ "parenthesized parameters may only be used with a trait")
+ .span_label(span, &format!("only traits may use parentheses"))
+ .emit();
+
let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
(Substs::empty(),
ty_param_defs.iter().map(|_| tcx.types.err).collect(),
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 => {
}
for (trait_def_id, name) in associated_types {
- span_err!(tcx.sess, span, E0191,
+ struct_span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name,
- tcx.item_path_str(trait_def_id));
+ tcx.item_path_str(trait_def_id))
+ .span_label(span, &format!(
+ "missing associated type `{}` value", name))
+ .emit();
}
tcx.mk_trait(object.principal, object.bounds)
}
if bounds.len() > 1 {
- let mut err = struct_span_err!(self.tcx().sess, span, E0221,
- "ambiguous associated type `{}` in bounds of `{}`",
- assoc_name,
- ty_param_name);
+ let mut err = struct_span_err!(
+ self.tcx().sess, span, E0221,
+ "ambiguous associated type `{}` in bounds of `{}`",
+ assoc_name,
+ ty_param_name);
+ err.span_label(span, &format!("ambiguous associated type `{}`", assoc_name));
for bound in &bounds {
span_note!(&mut err, span,
return self.tcx().types.err;
}
_ => {
- span_err!(tcx.sess, span, E0248,
- "found value `{}` used as a type",
- tcx.item_path_str(def.def_id()));
+ struct_span_err!(tcx.sess, span, E0248,
+ "found value `{}` used as a type",
+ tcx.item_path_str(def.def_id()))
+ .span_label(span, &format!("value used as a type"))
+ .emit();
return self.tcx().types.err;
}
}
}
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
};
self.check_pat(&subpat, field_ty);
}
} else {
- span_err!(tcx.sess, pat.span, E0023,
- "this pattern has {} field{s}, but the corresponding {} has {} field{s}",
- subpats.len(), def.kind_name(), variant.fields.len(),
- s = if variant.fields.len() == 1 {""} else {"s"});
+ let subpats_ending = if subpats.len() == 1 {
+ ""
+ } else {
+ "s"
+ };
+ let fields_ending = if variant.fields.len() == 1 {
+ ""
+ } else {
+ "s"
+ };
+ struct_span_err!(tcx.sess, pat.span, E0023,
+ "this pattern has {} field{}, but the corresponding {} has {} field{}",
+ subpats.len(), subpats_ending, def.kind_name(),
+ variant.fields.len(), fields_ending)
+ .span_label(pat.span, &format!("expected {} field{}, found {}",
+ variant.fields.len(), fields_ending, subpats.len()))
+ .emit();
on_error();
}
}
field_map.get(&field.name)
.map(|f| self.field_ty(span, f, substs))
.unwrap_or_else(|| {
- span_err!(tcx.sess, span, E0026,
- "struct `{}` does not have a field named `{}`",
- tcx.item_path_str(variant.did),
- field.name);
+ struct_span_err!(tcx.sess, span, E0026,
+ "struct `{}` does not have a field named `{}`",
+ tcx.item_path_str(variant.did),
+ field.name)
+ .span_label(span,
+ &format!("struct `{}` does not have field `{}`",
+ tcx.item_path_str(variant.did),
+ field.name))
+ .emit();
+
tcx.types.err
})
}
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,
if i < type_count {
substs.types.push(space, t);
} else if i == type_count {
- span_err!(self.tcx.sess, typ.span, E0087,
- "too many type parameters provided: \
- expected at most {} parameter{}, \
- found {} parameter{}",
- type_count,
- if type_count == 1 {""} else {"s"},
- data.types.len(),
- if data.types.len() == 1 {""} else {"s"});
+ struct_span_err!(self.tcx.sess, typ.span, E0087,
+ "too many type parameters provided: \
+ expected at most {} parameter{}, \
+ found {} parameter{}",
+ type_count,
+ if type_count == 1 {""} else {"s"},
+ data.types.len(),
+ if data.types.len() == 1 {""} else {"s"})
+ .span_label(typ.span , &format!("expected {} parameter{}",
+ type_count,
+ if type_count == 1 {""} else {"s"})).emit();
substs.types.truncate(space, 0);
break;
}
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!(
}
Err(CopyImplementationError::InfrigingVariant(name)) => {
- struct_span_err!(tcx.sess, span, E0205,
- "the trait `Copy` may not be \
- implemented for this type")
- .span_label(span, &format!("variant \
- `{}` does not implement `Copy`",
- name))
- .emit()
+ let item = tcx.map.expect_item(impl_node_id);
+ let span = if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
+ tr.path.span
+ } else {
+ span
+ };
+
+ struct_span_err!(tcx.sess, span, E0205,
+ "the trait `Copy` may not be implemented for this type")
+ .span_label(span, &format!("variant `{}` does not implement `Copy`",
+ name))
+ .emit()
}
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.map.expect_item(impl_node_id);
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
match it.node {
hir::ItemFn(_,_,_,_,ref ps,_)
if ps.is_parameterized() => {
- struct_span_err!(tcx.sess, start_span, E0132,
+ let sp = if let Some(sp) = ps.span() { sp } else { start_span };
+ struct_span_err!(tcx.sess, sp, E0132,
"start function is not allowed to have type parameters")
- .span_label(ps.span().unwrap(),
+ .span_label(sp,
&format!("start function cannot have type parameters"))
.emit();
return;
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
/// A hash map implementation which uses linear probing with Robin
/// Hood bucket stealing.
///
-/// The hashes are all keyed by the thread-local random number generator
-/// on creation by default. This means that the ordering of the keys is
-/// randomized, but makes the tables more resistant to
-/// denial-of-service attacks (Hash DoS). No guarantees are made to the
-/// quality of the random data. The implementation uses the best available
-/// random data from your platform at the time of creation. This behavior
-/// can be overridden with one of the constructors.
+/// By default, HashMap uses a somewhat slow hashing algorithm which can provide resistance
+/// to DoS attacks. Rust makes a best attempt at acquiring random numbers without IO
+/// blocking from your system. Because of this HashMap is not guaranteed to provide
+/// DoS resistance since the numbers generated might not be truly random. If you do
+/// require this behavior you can create your own hashing function using
+/// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html).
///
/// It is required that the keys implement the `Eq` and `Hash` traits, although
/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`.
/// 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() {}
Pear(u32),
}
+
fn main() {
let x = Fruit::Apple(String::new(), String::new());
match x {
Fruit::Apple(a) => {}, //~ ERROR E0023
+ //~| NOTE expected 2 fields, found 1
Fruit::Apple(a, b, c) => {}, //~ ERROR E0023
+ //~| NOTE expected 2 fields, found 3
+ Fruit::Pear(1, 2) => {}, //~ ERROR E0023
+ //~| NOTE expected 1 field, found 2
}
}
fn main() {
let thing = Thing { x: 0, y: 0 };
match thing {
- Thing { x, y, z } => {} //~ ERROR E0026
+ Thing { x, y, z } => {}
+ //~^ ERROR struct `Thing` does not have a field named `z` [E0026]
+ //~| NOTE struct `Thing` does not have field `z`
}
}
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
}
fn main() {
foo::<f64, bool>(); //~ ERROR E0087
+ //~^ NOTE expected
}
// 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
fn main() {
let irr = Irrefutable(0);
if let Irrefutable(x) = irr { //~ ERROR E0162
+ //~| NOTE irrefutable pattern
println!("{}", x);
}
}
}
type Foo = Trait; //~ ERROR E0191
+ //~| NOTE missing associated type `Bar` value
fn main() {
}
}
impl Copy for Foo { }
-//~^ ERROR E0205
+//~^ ERROR the trait `Copy` may not be implemented for this type
//~| NOTE variant `Bar` does not implement `Copy`
#[derive(Copy)]
-//~^ ERROR E0205
+//~^ ERROR the trait `Copy` may not be implemented for this type
//~| NOTE variant `Bar` does not implement `Copy`
//~| NOTE in this expansion of #[derive(Copy)]
enum Foo2<'a> {
// except according to those terms.
fn main() {
- let v: Vec(&str) = vec!["foo"]; //~ ERROR E0214
+ let v: Vec(&str) = vec!["foo"];
+ //~^ ERROR E0214
+ //~| NOTE only traits may use parentheses
}
}
fn do_something(x: Foo::Bar) { } //~ ERROR E0248
-
+ //~| NOTE value used as a type
fn main() {
}
}
}
-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() {}
--- /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() {}
fn dent<C:BoxCar>(c: C, color: C::Color) {
//~^ ERROR ambiguous associated type `Color` in bounds of `C`
+ //~| NOTE ambiguous associated type `Color`
//~| NOTE could derive from `Vehicle`
//~| NOTE could derive from `Box`
}
fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
//~^ ERROR ambiguous associated type
//~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified
+ //~| NOTE ambiguous associated type `Color`
//~| NOTE could derive from `Vehicle`
//~| NOTE could derive from `Box`
+ //~| NOTE missing associated type `Color` value
}
fn paint<C:BoxCar>(c: C, d: C::Color) {
//~^ ERROR ambiguous associated type `Color` in bounds of `C`
+ //~| NOTE ambiguous associated type `Color`
//~| NOTE could derive from `Vehicle`
//~| NOTE could derive from `Box`
}
// 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
}
--- /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 fn main() {
+ let x = (0, 2);
+
+ match x {
+ (0, ref y) => {}
+ (y, 0) => {}
+ _ => (),
+ }
+}
// 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);
+ }
}