From 265bc31ae19233bc7df868138fe146607751e963 Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Sun, 22 Apr 2018 20:35:21 +0300 Subject: [PATCH 01/33] added missing implementation hint --- src/librustc_typeck/check/op.rs | 161 ++++++++++-------- src/test/ui/codemap_tests/issue-28308.stderr | 2 + src/test/ui/error-codes/E0067.stderr | 2 + src/test/ui/error-codes/E0600.stderr | 2 + src/test/ui/error-festival.stderr | 4 + .../ui/feature-gate-negate-unsigned.stderr | 4 + src/test/ui/issue-5239-1.stderr | 2 + src/test/ui/reachable/expr_unary.stderr | 2 + 8 files changed, 110 insertions(+), 69 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 4a175248d74a3..66b95f0f4ea18 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -246,77 +246,92 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { - if let IsAssign::Yes = is_assign { - struct_span_err!(self.tcx.sess, expr.span, E0368, - "binary assignment operation `{}=` \ - cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty) - .span_label(lhs_expr.span, - format!("cannot use `{}=` on type `{}`", - op.node.as_str(), lhs_ty)) - .emit(); - } else { - let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty); - - if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { - if { - !self.infcx.type_moves_by_default(self.param_env, - ty_mut.ty, - lhs_expr.span) && - self.lookup_op_method(ty_mut.ty, - &[rhs_ty], - Op::Binary(op, is_assign)) - .is_ok() - } { - err.note( - &format!( - "this is a reference to a type that `{}` can be applied \ - to; you need to dereference this variable once for this \ - operation to work", - op.node.as_str())); - } + let (mut err, missing_trait) = match is_assign{ + IsAssign::Yes => { + let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368, + "binary assignment operation `{}=` \ + cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty); + err.span_label(lhs_expr.span, + format!("cannot use `{}=` on type `{}`", + op.node.as_str(), lhs_ty)); + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::AddAssign"), + hir::BiSub => Some("std::ops::SubAssign"), + hir::BiMul => Some("std::ops::MulAssign"), + hir::BiDiv => Some("std::ops::DivAssign"), + hir::BiRem => Some("std::ops::RemAssign"), + hir::BiBitAnd => Some("std::ops::BitAndAssign"), + hir::BiBitXor => Some("std::ops::BitXorAssign"), + hir::BiBitOr => Some("std::ops::BitOrAssign"), + hir::BiShl => Some("std::ops::ShlAssign"), + hir::BiShr => Some("std::ops::ShrAssign"), + _ => None + }; + (err, missing_trait) } - - let missing_trait = match op.node { - hir::BiAdd => Some("std::ops::Add"), - hir::BiSub => Some("std::ops::Sub"), - hir::BiMul => Some("std::ops::Mul"), - hir::BiDiv => Some("std::ops::Div"), - hir::BiRem => Some("std::ops::Rem"), - hir::BiBitAnd => Some("std::ops::BitAnd"), - hir::BiBitOr => Some("std::ops::BitOr"), - hir::BiShl => Some("std::ops::Shl"), - hir::BiShr => Some("std::ops::Shr"), - hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), - hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => - Some("std::cmp::PartialOrd"), - _ => None - }; - - if let Some(missing_trait) = missing_trait { - if missing_trait == "std::ops::Add" && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err) { - // This has nothing here because it means we did string - // concatenation (e.g. "Hello " + "World!"). This means - // we don't want the note in the else clause to be emitted - } else if let ty::TyParam(_) = lhs_ty.sty { - // FIXME: point to span of param - err.note( - &format!("`{}` might need a bound for `{}`", - lhs_ty, missing_trait)); - } else { - err.note( - &format!("an implementation of `{}` might be missing for `{}`", - missing_trait, lhs_ty)); + IsAssign::No => { + let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty); + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::Add"), + hir::BiSub => Some("std::ops::Sub"), + hir::BiMul => Some("std::ops::Mul"), + hir::BiDiv => Some("std::ops::Div"), + hir::BiRem => Some("std::ops::Rem"), + hir::BiBitAnd => Some("std::ops::BitAnd"), + hir::BiBitXor => Some("std::ops::BitXor"), + hir::BiBitOr => Some("std::ops::BitOr"), + hir::BiShl => Some("std::ops::Shl"), + hir::BiShr => Some("std::ops::Shr"), + hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), + hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => + Some("std::cmp::PartialOrd"), + _ => None + }; + if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { + if { + !self.infcx.type_moves_by_default(self.param_env, + ty_mut.ty, + lhs_expr.span) && + self.lookup_op_method(ty_mut.ty, + &[rhs_ty], + Op::Binary(op, is_assign)) + .is_ok() + } { + err.note( + &format!( + "this is a reference to a type that `{}` can be \ + applied to; you need to dereference this variable \ + once for this operation to work", + op.node.as_str())); + } } + (err, missing_trait) + } + }; + if let Some(missing_trait) = missing_trait { + if missing_trait == "std::ops::Add" && + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, + rhs_ty, &mut err) { + // This has nothing here because it means we did string + // concatenation (e.g. "Hello " + "World!"). This means + // we don't want the note in the else clause to be emitted + } else if let ty::TyParam(_) = lhs_ty.sty { + // FIXME: point to span of param + err.note( + &format!("`{}` might need a bound for `{}`", + lhs_ty, missing_trait)); + } else { + err.note( + &format!("an implementation of `{}` might be missing for `{}`", + missing_trait, lhs_ty)); } - err.emit(); } + err.emit(); } self.tcx.types.err } @@ -393,9 +408,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); if !actual.references_error() { - struct_span_err!(self.tcx.sess, ex.span, E0600, + let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600, "cannot apply unary operator `{}` to type `{}`", - op.as_str(), actual).emit(); + op.as_str(), actual); + let missing_trait = match op { + hir::UnNeg => "std::ops::Neg", + hir::UnNot => "std::ops::Not", + hir::UnDeref => "std::ops::UnDerf" + }; + err.note(&format!("an implementation of `{}` might be missing for `{}`", + missing_trait, operand_ty)); + err.emit(); } self.tcx.types.err } diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr index 2c8a33d95c03a..b5c2376239d14 100644 --- a/src/test/ui/codemap_tests/issue-28308.stderr +++ b/src/test/ui/codemap_tests/issue-28308.stderr @@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str` | LL | assert!("foo"); | ^^^^^^^^^^^^^^^ + | + = note: an implementation of `std::ops::Not` might be missing for `&'static str` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index 76f06c7c46379..43e1ca4096cf6 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -5,6 +5,8 @@ LL | LinkedList::new() += 1; //~ ERROR E0368 | -----------------^^^^^ | | | cannot use `+=` on type `std::collections::LinkedList<_>` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>` error[E0067]: invalid left-hand side expression --> $DIR/E0067.rs:14:5 diff --git a/src/test/ui/error-codes/E0600.stderr b/src/test/ui/error-codes/E0600.stderr index 500feb39f5e74..bd79ea79c8b56 100644 --- a/src/test/ui/error-codes/E0600.stderr +++ b/src/test/ui/error-codes/E0600.stderr @@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str` | LL | !"a"; //~ ERROR E0600 | ^^^^ + | + = note: an implementation of `std::ops::Not` might be missing for `&'static str` error: aborting due to previous error diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 345691352b407..6165806aac9c4 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -17,6 +17,8 @@ LL | x += 2; | -^^^^^ | | | cannot use `+=` on type `&str` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `&str` error[E0599]: no method named `z` found for type `&str` in the current scope --> $DIR/error-festival.rs:26:7 @@ -29,6 +31,8 @@ error[E0600]: cannot apply unary operator `!` to type `Question` | LL | !Question::Yes; | ^^^^^^^^^^^^^^ + | + = note: an implementation of `std::ops::Not` might be missing for `Question` error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:35:5 diff --git a/src/test/ui/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gate-negate-unsigned.stderr index 1025b56f55bc3..8831e874a200e 100644 --- a/src/test/ui/feature-gate-negate-unsigned.stderr +++ b/src/test/ui/feature-gate-negate-unsigned.stderr @@ -3,12 +3,16 @@ error[E0600]: cannot apply unary operator `-` to type `usize` | LL | let _max: usize = -1; | ^^ + | + = note: an implementation of `std::ops::Neg` might be missing for `usize` error[E0600]: cannot apply unary operator `-` to type `u8` --> $DIR/feature-gate-negate-unsigned.rs:24:14 | LL | let _y = -x; | ^^ + | + = note: an implementation of `std::ops::Neg` might be missing for `u8` error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-5239-1.stderr b/src/test/ui/issue-5239-1.stderr index 2f9204e72d3fb..adef9848ba743 100644 --- a/src/test/ui/issue-5239-1.stderr +++ b/src/test/ui/issue-5239-1.stderr @@ -5,6 +5,8 @@ LL | let x = |ref x: isize| { x += 1; }; | -^^^^^ | | | cannot use `+=` on type `&isize` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `&isize` error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 165eccd42396b..7ba21efcd5125 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `!` | LL | let x: ! = ! { return; }; //~ ERROR unreachable | ^^^^^^^^^^^^^ + | + = note: an implementation of `std::ops::Not` might be missing for `!` error: unreachable expression --> $DIR/expr_unary.rs:17:16 From 221b7ca3c27df5bb4729a7060e169c0a34dab9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 9 Apr 2018 23:49:25 +0200 Subject: [PATCH 02/33] Remove usages of Term::as_str and mark it for removal --- src/libproc_macro/lib.rs | 5 +++-- src/libproc_macro/quote.rs | 2 +- .../proc-macro/auxiliary/attributes-included.rs | 6 +++--- src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f51dbc3772f06..7efcd0cbf1d93 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -715,6 +715,7 @@ impl Term { } } + // FIXME: Remove this, do not stabilize /// Get a reference to the interned string. #[unstable(feature = "proc_macro", issue = "38356")] pub fn as_str(&self) -> &str { @@ -739,7 +740,7 @@ impl Term { #[unstable(feature = "proc_macro", issue = "38356")] impl fmt::Display for Term { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_str().fmt(f) + self.sym.as_str().fmt(f) } } @@ -1131,7 +1132,7 @@ impl TokenTree { }, self::TokenTree::Term(tt) => { let ident = ast::Ident::new(tt.sym, tt.span.0); - let sym_str = tt.sym.as_str(); + let sym_str = tt.sym.to_string(); let token = if sym_str.starts_with("'") { Lifetime(ident) } else if sym_str.starts_with("r#") { diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index d1f8e75192ae1..70f0b07839981 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -183,7 +183,7 @@ impl Quote for Op { impl Quote for Term { fn quote(self) -> TokenStream { - quote!(::Term::new((quote self.as_str()), (quote self.span()))) + quote!(::Term::new((quote self.sym.as_str()), (quote self.span()))) } } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs index bbfec5815ba5c..6b34ccc6543ea 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs @@ -86,7 +86,7 @@ fn assert_doc(slice: &mut &[TokenTree]) { } match &tokens[0] { - TokenTree::Term(tt) => assert_eq!("doc", tt.as_str()), + TokenTree::Term(tt) => assert_eq!("doc", &*tt.to_string()), _ => panic!("expected `doc`"), } match &tokens[1] { @@ -118,11 +118,11 @@ fn assert_invoc(slice: &mut &[TokenTree]) { fn assert_foo(slice: &mut &[TokenTree]) { match &slice[0] { - TokenTree::Term(tt) => assert_eq!(tt.as_str(), "fn"), + TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "fn"), _ => panic!("expected fn"), } match &slice[1] { - TokenTree::Term(tt) => assert_eq!(tt.as_str(), "foo"), + TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "foo"), _ => panic!("expected foo"), } match &slice[2] { diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index 9e1ae59c01bc0..de26f8296e36b 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -33,7 +33,7 @@ pub fn cond(input: TokenStream) -> TokenStream { panic!("Invalid macro usage in cond: {}", cond); } let is_else = match test { - TokenTree::Term(word) => word.as_str() == "else", + TokenTree::Term(word) => &*word.to_string() == "else", _ => false, }; conds.push(if is_else || input.peek().is_none() { From b0fcb5f4408d59a0dcea4427394a04e72ab5aeff Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Tue, 27 Mar 2018 19:45:44 +0200 Subject: [PATCH 03/33] Extend tests for RFC1598 (GAT) --- .../collections.rs | 85 +++++++++++++++++++ .../collections.stderr | 34 ++++++++ .../iterable.rs | 34 ++++++++ .../iterable.stderr | 26 +++++- .../shadowing.rs | 44 ++++++++++ .../shadowing.stdout | 0 .../streaming_iterator.rs | 44 ++++++++++ .../streaming_iterator.stderr | 14 ++- 8 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/rfc1598-generic-associated-types/collections.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/collections.stderr create mode 100644 src/test/ui/rfc1598-generic-associated-types/shadowing.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/shadowing.stdout diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs new file mode 100644 index 0000000000000..4ea2c82883133 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/collections.rs @@ -0,0 +1,85 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a +//follow-up PR + +// A Collection trait and collection families. +// Based on http://smallcultfollowing.com/babysteps/blog/2016/11/03/associated-type-constructors-part-2-family-traits/ + +trait Collection { + fn empty() -> Self; + fn add(&mut self, value: T); + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + type Iter<'iter>: Iterator; + type Family: CollectionFamily; + // Test associated type defaults with parameters + type Sibling: Collection = <>::Family as CollectionFamily>::Member; + //~^ ERROR type parameters are not allowed on this type [E0109] +} + +trait CollectionFamily { + type Member: Collection; +} + +struct VecFamily; + +impl CollectionFamily for VecFamily { + type Member = Vec; +} + +impl Collection for Vec { + fn empty() -> Self { + Vec::new() + } + fn add(&mut self, value: T) { + self.push(value) + } + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + self.iter() + } + type Iter<'iter> = std::slice::Iter<'iter, T>; + type Family = VecFamily; +} + +fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member + //~^ ERROR type parameters are not allowed on this type [E0109] + where C: Collection { + let mut res = C::Family::Member::::empty(); + for &v in ints.iterate() { + res.add(v as f32); + } + res +} + +fn floatify_sibling(ints: &C) -> >::Sibling + //~^ ERROR type parameters are not allowed on this type [E0109] + where C: Collection { + let mut res = C::Family::Member::::empty(); + for &v in ints.iterate() { + res.add(v as f32); + } + res +} + +fn use_floatify() { + let a = vec![1i32, 2, 3]; + let b = floatify(a); + println!("{}", b.iterate().next()); + let c = floatify_sibling(a); + println!("{}", c.iterate().next()); +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr new file mode 100644 index 0000000000000..6aa7aa993fd25 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr @@ -0,0 +1,34 @@ +error[E0109]: type parameters are not allowed on this type + --> $DIR/collections.rs:57:90 + | +LL | fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member + | ^^^ type parameter not allowed + +error[E0109]: type parameters are not allowed on this type + --> $DIR/collections.rs:67:69 + | +LL | fn floatify_sibling(ints: &C) -> >::Sibling + | ^^^ type parameter not allowed + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/collections.rs:23:50 + | +LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; + | ^^^^^ lifetime parameter not allowed on this type + +error[E0109]: type parameters are not allowed on this type + --> $DIR/collections.rs:28:100 + | +LL | type Sibling: Collection = <>::Family as CollectionFamily>::Member; + | ^ type parameter not allowed + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/collections.rs:49:50 + | +LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { + | ^^^^^ lifetime parameter not allowed on this type + +error: aborting due to 5 previous errors + +Some errors occurred: E0109, E0110. +For more information about an error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.rs b/src/test/ui/rfc1598-generic-associated-types/iterable.rs index 1287ddaf7f7fe..b79aa6179adfd 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.rs +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.rs @@ -29,4 +29,38 @@ trait Iterable { //~^ ERROR lifetime parameters are not allowed on this type [E0110] } +// Impl for struct type +impl Iterable for Vec { + type Item<'a> = &'a T; + type Iter<'a> = std::slice::Iter<'a, T>; + type Iter2<'a> = &'a T; + // gavento: ^^^ Not 100% sure about the intention here + fn iter<'a>(&'a self) -> Self::Iter<'a> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + self.iter() + } +} + +// Impl for a primitive type +impl Iterable for [T] { + type Item<'a> = &'a T; + type Iter<'a> = std::slice::Iter<'a, T>; + type Iter2<'a> = &'a T; + // gavento: ^^^ Not 100% sure about the intention here + fn iter<'a>(&'a self) -> Self::Iter<'a> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + self.iter() + } +} + +fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + it.iter() +} + +fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + it.iter().next() +} + fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr index d33eebb42d607..34266dd3c512f 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr @@ -10,12 +10,36 @@ error[E0110]: lifetime parameters are not allowed on this type LL | type Iter2<'a>: Deref as Iterator>::Item>; | ^^ lifetime parameter not allowed on this type +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/iterable.rs:56:53 + | +LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { + | ^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/iterable.rs:61:60 + | +LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { + | ^^ lifetime parameter not allowed on this type + error[E0110]: lifetime parameters are not allowed on this type --> $DIR/iterable.rs:28:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a>; | ^^ lifetime parameter not allowed on this type -error: aborting due to 3 previous errors +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/iterable.rs:38:41 + | +LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { + | ^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/iterable.rs:50:41 + | +LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { + | ^^ lifetime parameter not allowed on this type + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0110`. diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs new file mode 100644 index 0000000000000..6e77ce2b3dd0c --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs @@ -0,0 +1,44 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] + +//FIXME(#44265): The lifetime shadowing and type parameter shadowing +// should cause an error. This will be addressed by a future PR. +// For now this compiles: +// must-compile-successfully + +trait Shadow<'a> { + type Bar<'a>; // Error: shadowed lifetime +} + +trait NoShadow<'a> { + type Bar<'b>; // OK +} + +impl<'a> NoShadow<'a> for &'a u32 +{ + type Bar<'a> = i32; // Error: shadowed lifetime +} + +trait ShadowT { + type Bar; // Error: shadowed type parameter +} + +trait NoShadowT { + type Bar; // OK +} + +impl NoShadowT for Option +{ + type Bar = i32; // Error: shadowed type parameter +} + +fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.stdout b/src/test/ui/rfc1598-generic-associated-types/shadowing.stdout new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs index f9e270ee92e22..522ddb5dc135e 100644 --- a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs +++ b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs @@ -35,4 +35,48 @@ struct Foo { fn foo(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ } //~^ ERROR lifetime parameters are not allowed on this type [E0110] +// Full example of enumerate iterator + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +struct StreamEnumerate { + iter: I, + count: usize, +} + +impl StreamingIterator for StreamEnumerate { + type Item<'a> = (usize, I::Item<'a>); + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + fn next<'a>(&'a self) -> Option> { + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + match self.iter.next() { + None => None, + Some(val) => { + let r = Some((self.count, val)); + self.count += 1; + r + } + } + } +} + +impl StreamEnumerate { + pub fn new(iter: I) -> Self { + StreamEnumerate { + count: 0, + iter: iter, + } + } +} + +fn test_stream_enumerate() { + let v = vec!["a", "b", "c"]; + let se = StreamEnumerate::new(v.iter()); + let a: &str = se.next().unwrap().1; + for (i, s) in se { + println!("{} {}", i, s); + } + println!("{}", a); +} + + fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr index 9ab80151a7ed3..607a4b8d57996 100644 --- a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr @@ -16,6 +16,18 @@ error[E0110]: lifetime parameters are not allowed on this type LL | fn next<'a>(&'a self) -> Option>; | ^^ lifetime parameter not allowed on this type -error: aborting due to 3 previous errors +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/streaming_iterator.rs:47:37 + | +LL | type Item<'a> = (usize, I::Item<'a>); + | ^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/streaming_iterator.rs:49:48 + | +LL | fn next<'a>(&'a self) -> Option> { + | ^^ lifetime parameter not allowed on this type + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0110`. From e09d9ecbcdbd4563656162be6a69e47a11f67c52 Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Tue, 27 Mar 2018 22:26:46 +0200 Subject: [PATCH 04/33] Tidy up the code --- .../ui/rfc1598-generic-associated-types/collections.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs index 4ea2c82883133..19f5756609678 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.rs +++ b/src/test/ui/rfc1598-generic-associated-types/collections.rs @@ -14,8 +14,9 @@ //FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a //follow-up PR -// A Collection trait and collection families. -// Based on http://smallcultfollowing.com/babysteps/blog/2016/11/03/associated-type-constructors-part-2-family-traits/ +// A Collection trait and collection families. Based on +// http://smallcultfollowing.com/babysteps/blog/2016/11/03/ +// associated-type-constructors-part-2-family-traits/ trait Collection { fn empty() -> Self; @@ -25,7 +26,8 @@ trait Collection { type Iter<'iter>: Iterator; type Family: CollectionFamily; // Test associated type defaults with parameters - type Sibling: Collection = <>::Family as CollectionFamily>::Member; + type Sibling: Collection = <>::Family as CollectionFamily>:: + Member; //~^ ERROR type parameters are not allowed on this type [E0109] } @@ -82,4 +84,4 @@ fn use_floatify() { println!("{}", c.iterate().next()); } -fn main() {} \ No newline at end of file +fn main() {} From a66a0110de5258507c30e26d7e7d055ffc080cfc Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Wed, 28 Mar 2018 09:15:36 +0200 Subject: [PATCH 05/33] Fix test stderr after tidying the source --- .../collections.stderr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr index 6aa7aa993fd25..eda8fb5f93fba 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr @@ -1,29 +1,29 @@ error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:57:90 + --> $DIR/collections.rs:59:90 | LL | fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member | ^^^ type parameter not allowed error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:67:69 + --> $DIR/collections.rs:69:69 | LL | fn floatify_sibling(ints: &C) -> >::Sibling | ^^^ type parameter not allowed error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/collections.rs:23:50 + --> $DIR/collections.rs:24:50 | LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; | ^^^^^ lifetime parameter not allowed on this type error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:28:100 + --> $DIR/collections.rs:30:16 | -LL | type Sibling: Collection = <>::Family as CollectionFamily>::Member; - | ^ type parameter not allowed +LL | Member; + | ^ type parameter not allowed error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/collections.rs:49:50 + --> $DIR/collections.rs:51:50 | LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { | ^^^^^ lifetime parameter not allowed on this type From 0617b925e83079ebebc53bc9a29a9e4105a39ec3 Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Wed, 28 Mar 2018 09:22:44 +0200 Subject: [PATCH 06/33] Add tests for GAT parameter number and kindness --- .../parameter_number_and_kind.rs | 56 +++++++++++++++++++ .../parameter_number_and_kind.stderr | 34 +++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs new file mode 100644 index 0000000000000..51527d4117c2c --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs @@ -0,0 +1,56 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a +//follow-up PR + +//FIXME(#44265): Update expected errors once E110 is resolved, now does not get past `trait Foo` + +trait Foo { + type A<'a>; + type B<'a, 'b>; + type C; + type D; + type E<'a, T>; + // Test parameters in default values + type FOk = Self::E<'static, T>; + //~^ ERROR type parameters are not allowed on this type [E0109] + //~| ERROR lifetime parameters are not allowed on this type [E0110] + type FErr1 = Self::E<'static, 'static>; // Error + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + type FErr2 = Self::E<'static, T, u32>; // Error + //~^ ERROR type parameters are not allowed on this type [E0109] + //~| ERROR lifetime parameters are not allowed on this type [E0110] +} + +struct Fooy; + +impl Foo for Fooy { + type A = u32; // Error: parameter expected + type B<'a, T> = Vec; // Error: lifetime param expected + type C<'a> = u32; // Error: no param expected + type D<'a> = u32; // Error: type param expected + type E = u32; // Error: lifetime expected as the first param +} + +struct Fooer; + +impl Foo for Fooer { + type A = u32; // Error: lifetime parameter expected + type B<'a> = u32; // Error: another lifetime param expected + type C = T; // Error: no param expected + type D<'b, T> = u32; // Error: unexpected lifetime param + type E<'a, 'b> = u32; // Error: type expected as the second param +} + +fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr new file mode 100644 index 0000000000000..df83fdaad5bfa --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr @@ -0,0 +1,34 @@ +error[E0109]: type parameters are not allowed on this type + --> $DIR/parameter_number_and_kind.rs:26:36 + | +LL | type FOk = Self::E<'static, T>; + | ^ type parameter not allowed + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/parameter_number_and_kind.rs:26:27 + | +LL | type FOk = Self::E<'static, T>; + | ^^^^^^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/parameter_number_and_kind.rs:29:26 + | +LL | type FErr1 = Self::E<'static, 'static>; // Error + | ^^^^^^^ lifetime parameter not allowed on this type + +error[E0109]: type parameters are not allowed on this type + --> $DIR/parameter_number_and_kind.rs:31:38 + | +LL | type FErr2 = Self::E<'static, T, u32>; // Error + | ^ type parameter not allowed + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/parameter_number_and_kind.rs:31:29 + | +LL | type FErr2 = Self::E<'static, T, u32>; // Error + | ^^^^^^^ lifetime parameter not allowed on this type + +error: aborting due to 5 previous errors + +Some errors occurred: E0109, E0110. +For more information about an error, try `rustc --explain E0109`. From 571337b3dd89a17930a686a66d815f69889e9b66 Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Wed, 11 Apr 2018 23:41:20 +0200 Subject: [PATCH 07/33] Update tests with Nikos comments --- .../collections.rs | 26 +++++++++++++------ .../collections.stderr | 20 +++++++------- .../construct_with_other_type.rs | 13 ++++++++-- .../construct_with_other_type.stderr | 20 +++++++++++--- .../iterable.rs | 11 ++------ .../iterable.stderr | 18 +++++-------- .../shadowing.rs | 4 +-- 7 files changed, 65 insertions(+), 47 deletions(-) diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs index 19f5756609678..24d756a83314e 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.rs +++ b/src/test/ui/rfc1598-generic-associated-types/collections.rs @@ -19,16 +19,19 @@ // associated-type-constructors-part-2-family-traits/ trait Collection { - fn empty() -> Self; - fn add(&mut self, value: T); - fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; - //~^ ERROR lifetime parameters are not allowed on this type [E0110] type Iter<'iter>: Iterator; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling: Collection = <>::Family as CollectionFamily>:: Member; //~^ ERROR type parameters are not allowed on this type [E0109] + + fn empty() -> Self; + + fn add(&mut self, value: T); + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; + //~^ ERROR lifetime parameters are not allowed on this type [E0110] } trait CollectionFamily { @@ -42,23 +45,28 @@ impl CollectionFamily for VecFamily { } impl Collection for Vec { + type Iter<'iter> = std::slice::Iter<'iter, T>; + type Family = VecFamily; + fn empty() -> Self { Vec::new() } + fn add(&mut self, value: T) { self.push(value) } + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { //~^ ERROR lifetime parameters are not allowed on this type [E0110] self.iter() } - type Iter<'iter> = std::slice::Iter<'iter, T>; - type Family = VecFamily; } fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member //~^ ERROR type parameters are not allowed on this type [E0109] - where C: Collection { +where + C: Collection, +{ let mut res = C::Family::Member::::empty(); for &v in ints.iterate() { res.add(v as f32); @@ -68,7 +76,9 @@ fn floatify(ints: &C) -> <>::Family as CollectionFamily> fn floatify_sibling(ints: &C) -> >::Sibling //~^ ERROR type parameters are not allowed on this type [E0109] - where C: Collection { +where + C: Collection, +{ let mut res = C::Family::Member::::empty(); for &v in ints.iterate() { res.add(v as f32); diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr index eda8fb5f93fba..0a51bf56397df 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr @@ -1,29 +1,29 @@ error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:59:90 + --> $DIR/collections.rs:65:90 | LL | fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member | ^^^ type parameter not allowed error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:69:69 + --> $DIR/collections.rs:77:69 | LL | fn floatify_sibling(ints: &C) -> >::Sibling | ^^^ type parameter not allowed -error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/collections.rs:24:50 - | -LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; - | ^^^^^ lifetime parameter not allowed on this type - error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:30:16 + --> $DIR/collections.rs:26:16 | LL | Member; | ^ type parameter not allowed error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/collections.rs:51:50 + --> $DIR/collections.rs:33:50 + | +LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; + | ^^^^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/collections.rs:59:50 | LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { | ^^^^^ lifetime parameter not allowed on this type diff --git a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs index 0d9b487876e21..0429410031526 100644 --- a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs @@ -10,6 +10,8 @@ #![feature(generic_associated_types)] +use std::ops::Deref; + //FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a //follow-up PR @@ -18,11 +20,18 @@ trait Foo { } trait Baz { - type Quux<'a>; + type Quux<'a>: Foo; + + // This weird type tests that we can use universal function call syntax to access the Item on + type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; + //~^ ERROR lifetime parameters are not allowed on this type [E0110] + //~| ERROR lifetime parameters are not allowed on this type [E0110] } impl Baz for T where T: Foo { - type Quux<'a> = ::Bar<'a, 'static>; + type Quux<'a> = T; + + type Baa<'a> = &'a ::Bar<'a, 'static>; //~^ ERROR lifetime parameters are not allowed on this type [E0110] } diff --git a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr index 054530e24bd18..764a0db2478a8 100644 --- a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr @@ -1,9 +1,21 @@ error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/construct_with_other_type.rs:25:37 + --> $DIR/construct_with_other_type.rs:26:46 | -LL | type Quux<'a> = ::Bar<'a, 'static>; - | ^^ lifetime parameter not allowed on this type +LL | type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; + | ^^ lifetime parameter not allowed on this type -error: aborting due to previous error +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/construct_with_other_type.rs:26:63 + | +LL | type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; + | ^^ lifetime parameter not allowed on this type + +error[E0110]: lifetime parameters are not allowed on this type + --> $DIR/construct_with_other_type.rs:34:40 + | +LL | type Baa<'a> = &'a ::Bar<'a, 'static>; + | ^^ lifetime parameter not allowed on this type + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0110`. diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.rs b/src/test/ui/rfc1598-generic-associated-types/iterable.rs index b79aa6179adfd..38967dbbe4530 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.rs +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.rs @@ -20,11 +20,6 @@ trait Iterable { type Iter<'a>: Iterator>; //~^ ERROR lifetime parameters are not allowed on this type [E0110] - // This weird type tests that we can use universal function call syntax to access the Item on - // Self::Iter which we have declared to be an Iterator - type Iter2<'a>: Deref as Iterator>::Item>; - //~^ ERROR lifetime parameters are not allowed on this type [E0110] - fn iter<'a>(&'a self) -> Self::Iter<'a>; //~^ ERROR lifetime parameters are not allowed on this type [E0110] } @@ -33,8 +28,7 @@ trait Iterable { impl Iterable for Vec { type Item<'a> = &'a T; type Iter<'a> = std::slice::Iter<'a, T>; - type Iter2<'a> = &'a T; - // gavento: ^^^ Not 100% sure about the intention here + fn iter<'a>(&'a self) -> Self::Iter<'a> { //~^ ERROR lifetime parameters are not allowed on this type [E0110] self.iter() @@ -45,8 +39,7 @@ impl Iterable for Vec { impl Iterable for [T] { type Item<'a> = &'a T; type Iter<'a> = std::slice::Iter<'a, T>; - type Iter2<'a> = &'a T; - // gavento: ^^^ Not 100% sure about the intention here + fn iter<'a>(&'a self) -> Self::Iter<'a> { //~^ ERROR lifetime parameters are not allowed on this type [E0110] self.iter() diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr index 34266dd3c512f..0e251300e451f 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr @@ -5,41 +5,35 @@ LL | type Iter<'a>: Iterator>; | ^^ lifetime parameter not allowed on this type error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:25:48 - | -LL | type Iter2<'a>: Deref as Iterator>::Item>; - | ^^ lifetime parameter not allowed on this type - -error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:56:53 + --> $DIR/iterable.rs:49:53 | LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { | ^^ lifetime parameter not allowed on this type error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:61:60 + --> $DIR/iterable.rs:54:60 | LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { | ^^ lifetime parameter not allowed on this type error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:28:41 + --> $DIR/iterable.rs:23:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a>; | ^^ lifetime parameter not allowed on this type error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:38:41 + --> $DIR/iterable.rs:32:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { | ^^ lifetime parameter not allowed on this type error[E0110]: lifetime parameters are not allowed on this type - --> $DIR/iterable.rs:50:41 + --> $DIR/iterable.rs:43:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { | ^^ lifetime parameter not allowed on this type -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0110`. diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs index 6e77ce2b3dd0c..6ed7380f3f87a 100644 --- a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs +++ b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs @@ -11,8 +11,8 @@ #![feature(generic_associated_types)] //FIXME(#44265): The lifetime shadowing and type parameter shadowing -// should cause an error. This will be addressed by a future PR. -// For now this compiles: +// should cause an error. Now it compiles (errorneously) and this will be addressed +// by a future PR. Then remove the following: // must-compile-successfully trait Shadow<'a> { From a43171a24257f015113ecf494286d39f47db88ac Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Thu, 3 May 2018 00:34:34 +0200 Subject: [PATCH 08/33] Update tests to use compile-pass --- src/test/ui/rfc1598-generic-associated-types/shadowing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs index 6ed7380f3f87a..f0e711e71e341 100644 --- a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs +++ b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs @@ -13,7 +13,7 @@ //FIXME(#44265): The lifetime shadowing and type parameter shadowing // should cause an error. Now it compiles (errorneously) and this will be addressed // by a future PR. Then remove the following: -// must-compile-successfully +// compile-pass trait Shadow<'a> { type Bar<'a>; // Error: shadowed lifetime From 9073c897459a8582fa61d87f41654e18f9869b46 Mon Sep 17 00:00:00 2001 From: Tomas Gavenciak Date: Thu, 3 May 2018 00:58:35 +0200 Subject: [PATCH 09/33] Minor fromatting for RFC 1598 tests --- .../ui/rfc1598-generic-associated-types/collections.rs | 8 ++++---- .../rfc1598-generic-associated-types/collections.stderr | 6 +++--- src/test/ui/rfc1598-generic-associated-types/shadowing.rs | 6 ++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs index 24d756a83314e..e71166ed65bba 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.rs +++ b/src/test/ui/rfc1598-generic-associated-types/collections.rs @@ -22,8 +22,8 @@ trait Collection { type Iter<'iter>: Iterator; type Family: CollectionFamily; // Test associated type defaults with parameters - type Sibling: Collection = <>::Family as CollectionFamily>:: - Member; + type Sibling: Collection = + <>::Family as CollectionFamily>::Member; //~^ ERROR type parameters are not allowed on this type [E0109] fn empty() -> Self; @@ -63,7 +63,7 @@ impl Collection for Vec { } fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member - //~^ ERROR type parameters are not allowed on this type [E0109] +//~^ ERROR type parameters are not allowed on this type [E0109] where C: Collection, { @@ -75,7 +75,7 @@ where } fn floatify_sibling(ints: &C) -> >::Sibling - //~^ ERROR type parameters are not allowed on this type [E0109] +//~^ ERROR type parameters are not allowed on this type [E0109] where C: Collection, { diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr index 0a51bf56397df..ed96570583f4f 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr @@ -11,10 +11,10 @@ LL | fn floatify_sibling(ints: &C) -> >::Sibling | ^^^ type parameter not allowed error[E0109]: type parameters are not allowed on this type - --> $DIR/collections.rs:26:16 + --> $DIR/collections.rs:26:71 | -LL | Member; - | ^ type parameter not allowed +LL | <>::Family as CollectionFamily>::Member; + | ^ type parameter not allowed error[E0110]: lifetime parameters are not allowed on this type --> $DIR/collections.rs:33:50 diff --git a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs index f0e711e71e341..6cdcaf2568394 100644 --- a/src/test/ui/rfc1598-generic-associated-types/shadowing.rs +++ b/src/test/ui/rfc1598-generic-associated-types/shadowing.rs @@ -23,8 +23,7 @@ trait NoShadow<'a> { type Bar<'b>; // OK } -impl<'a> NoShadow<'a> for &'a u32 -{ +impl<'a> NoShadow<'a> for &'a u32 { type Bar<'a> = i32; // Error: shadowed lifetime } @@ -36,8 +35,7 @@ trait NoShadowT { type Bar; // OK } -impl NoShadowT for Option -{ +impl NoShadowT for Option { type Bar = i32; // Error: shadowed type parameter } From 000d3c97eeb286a1a1e9c2fa2a1fc8874ed93731 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 7 May 2018 22:30:44 -0400 Subject: [PATCH 10/33] Make DepGraph::previous_work_products immutable Fixes #50501 --- src/librustc/dep_graph/graph.rs | 26 ++---- src/librustc_driver/driver.rs | 19 ++-- src/librustc_incremental/persist/load.rs | 112 ++++++++++++----------- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 22ab1b15c8b8e..61a7404b08526 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -77,7 +77,7 @@ struct DepGraphData { /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. - previous_work_products: RwLock>, + previous_work_products: FxHashMap, /// Work-products that we generate in this run. work_products: RwLock>, @@ -90,7 +90,8 @@ struct DepGraphData { impl DepGraph { - pub fn new(prev_graph: PreviousDepGraph) -> DepGraph { + pub fn new(prev_graph: PreviousDepGraph, + prev_work_products: FxHashMap) -> DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. @@ -100,7 +101,7 @@ impl DepGraph { (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Lrc::new(DepGraphData { - previous_work_products: RwLock::new(FxHashMap()), + previous_work_products: prev_work_products, work_products: RwLock::new(FxHashMap()), dep_node_debug: Lock::new(FxHashMap()), current: Lock::new(CurrentDepGraph::new()), @@ -460,19 +461,6 @@ impl DepGraph { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } - /// Indicates that a previous work product exists for `v`. This is - /// invoked during initial start-up based on what nodes are clean - /// (and what files exist in the incr. directory). - pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) { - debug!("insert_previous_work_product({:?}, {:?})", v, data); - self.data - .as_ref() - .unwrap() - .previous_work_products - .borrow_mut() - .insert(v.clone(), data); - } - /// Indicates that we created the given work-product in this run /// for `v`. This record will be preserved and loaded in the next /// run. @@ -492,7 +480,7 @@ impl DepGraph { self.data .as_ref() .and_then(|data| { - data.previous_work_products.borrow().get(v).cloned() + data.previous_work_products.get(v).cloned() }) } @@ -504,8 +492,8 @@ impl DepGraph { /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> ReadGuard> { - self.data.as_ref().unwrap().previous_work_products.borrow() + pub fn previous_work_products(&self) -> &FxHashMap { + &self.data.as_ref().unwrap().previous_work_products } #[inline(always)] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2fb811eba1e9a..1e74039503d51 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -980,15 +980,16 @@ where let dep_graph = match future_dep_graph { None => DepGraph::new_disabled(), Some(future) => { - let prev_graph = time(sess, "blocked while dep-graph loading finishes", || { - future - .open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }) - .open(sess) - }); - DepGraph::new(prev_graph) + let (prev_graph, prev_work_products) = + time(sess, "blocked while dep-graph loading finishes", || { + future + .open() + .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }) + .open(sess) + }); + DepGraph::new(prev_graph, prev_work_products) } }; let hir_forest = time(sess, "lowering ast -> hir", || { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 44d6e532f79bb..01186483a6839 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,7 +10,8 @@ //! Code to save/load the dep-graph from files. -use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph}; +use rustc_data_structures::fx::FxHashMap; +use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::ty::maps::OnDiskCache; @@ -32,65 +33,22 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.allocate_metadata_dep_nodes(); tcx.precompute_in_scope_traits_hashes(); - - if tcx.sess.incr_comp_session_dir_opt().is_none() { - // If we are only building with -Zquery-dep-graph but without an actual - // incr. comp. session directory, we exit here. Otherwise we'd fail - // when trying to load work products. - return - } - - let work_products_path = work_products_path(tcx.sess); - let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path); - - if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { - // Decode the list of work_products - let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); - let work_products: Vec = - RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { - let msg = format!("Error decoding `work-products` from incremental \ - compilation session directory: {}", e); - tcx.sess.fatal(&msg[..]) - }); - - for swp in work_products { - let mut all_files_exist = true; - for &(_, ref file_name) in swp.work_product.saved_files.iter() { - let path = in_incr_comp_dir_sess(tcx.sess, file_name); - if !path.exists() { - all_files_exist = false; - - if tcx.sess.opts.debugging_opts.incremental_info { - eprintln!("incremental: could not find file for work \ - product: {}", path.display()); - } - } - } - - if all_files_exist { - debug!("reconcile_work_products: all files for {:?} exist", swp); - tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); - } else { - debug!("reconcile_work_products: some file for {:?} does not exist", swp); - delete_dirty_work_product(tcx, swp); - } - } - } } +type WorkProductMap = FxHashMap; + pub enum LoadResult { Ok { data: T }, DataOutOfDate, Error { message: String }, } - -impl LoadResult { - pub fn open(self, sess: &Session) -> PreviousDepGraph { +impl LoadResult<(PreviousDepGraph, WorkProductMap)> { + pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) { match self { LoadResult::Error { message } => { sess.warn(&message); - PreviousDepGraph::new(SerializedDepGraph::new()) + (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) }, LoadResult::DataOutOfDate => { if let Err(err) = delete_all_session_dir_contents(sess) { @@ -98,7 +56,7 @@ impl LoadResult { incremental compilation session directory contents `{}`: {}.", dep_graph_path(sess).display(), err)); } - PreviousDepGraph::new(SerializedDepGraph::new()) + (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) } LoadResult::Ok { data } => data } @@ -125,10 +83,10 @@ fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec, } } -fn delete_dirty_work_product(tcx: TyCtxt, +fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); - work_product::delete_workproduct_files(tcx.sess, &swp.work_product); + work_product::delete_workproduct_files(sess, &swp.work_product); } /// Either a result that has already be computed or a @@ -149,7 +107,7 @@ impl MaybeAsync { /// Launch a thread and load the dependency graph in the background. pub fn load_dep_graph(sess: &Session) -> - MaybeAsync> + MaybeAsync> { // Since `sess` isn't `Sync`, we perform all accesses to `sess` // before we fire the background thread. @@ -159,7 +117,7 @@ pub fn load_dep_graph(sess: &Session) -> if sess.opts.incremental.is_none() { // No incremental compilation. return MaybeAsync::Sync(LoadResult::Ok { - data: PreviousDepGraph::new(SerializedDepGraph::new()) + data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) }); } @@ -169,6 +127,50 @@ pub fn load_dep_graph(sess: &Session) -> let report_incremental_info = sess.opts.debugging_opts.incremental_info; let expected_hash = sess.opts.dep_tracking_hash(); + let mut prev_work_products = FxHashMap(); + + // If we are only building with -Zquery-dep-graph but without an actual + // incr. comp. session directory, we exit here. Otherwise we'd fail + // when trying to load work products. + if sess.incr_comp_session_dir_opt().is_some() { + let work_products_path = work_products_path(sess); + let load_result = load_data(report_incremental_info, &work_products_path); + + if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { + // Decode the list of work_products + let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); + let work_products: Vec = + RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { + let msg = format!("Error decoding `work-products` from incremental \ + compilation session directory: {}", e); + sess.fatal(&msg[..]) + }); + + for swp in work_products { + let mut all_files_exist = true; + for &(_, ref file_name) in swp.work_product.saved_files.iter() { + let path = in_incr_comp_dir_sess(sess, file_name); + if !path.exists() { + all_files_exist = false; + + if sess.opts.debugging_opts.incremental_info { + eprintln!("incremental: could not find file for work \ + product: {}", path.display()); + } + } + } + + if all_files_exist { + debug!("reconcile_work_products: all files for {:?} exist", swp); + prev_work_products.insert(swp.id, swp.work_product); + } else { + debug!("reconcile_work_products: some file for {:?} does not exist", swp); + delete_dirty_work_product(sess, swp); + } + } + } + } + MaybeAsync::Async(std::thread::spawn(move || { time_ext(time_passes, None, "background load prev dep-graph", move || { match load_data(report_incremental_info, &path) { @@ -195,7 +197,7 @@ pub fn load_dep_graph(sess: &Session) -> let dep_graph = SerializedDepGraph::decode(&mut decoder) .expect("Error reading cached dep-graph"); - LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) } + LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) } } } }) From ea4942835d607ffa87eb7f50552e6cf023d27403 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 May 2018 14:32:31 +0200 Subject: [PATCH 11/33] Don't use Lock for heavily accessed CrateMetadata::cnum_map. --- src/librustc_metadata/creader.rs | 9 ++++++--- src/librustc_metadata/cstore.rs | 5 +++-- src/librustc_metadata/decoder.rs | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d0237071a6058..7efcedd73eddf 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -219,6 +219,8 @@ impl<'a> CrateLoader<'a> { let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); + let dependencies: Vec = cnum_map.iter().cloned().collect(); + let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || { crate_root.def_path_table.decode((&metadata, self.sess)) }); @@ -239,8 +241,9 @@ impl<'a> CrateLoader<'a> { }), root: crate_root, blob: metadata, - cnum_map: Lock::new(cnum_map), + cnum_map, cnum, + dependencies: Lock::new(dependencies), codemap_import_info: RwLock::new(vec![]), attribute_cache: Lock::new([Vec::new(), Vec::new()]), dep_kind: Lock::new(dep_kind), @@ -392,7 +395,7 @@ impl<'a> CrateLoader<'a> { // Propagate the extern crate info to dependencies. extern_crate.direct = false; - for &dep_cnum in cmeta.cnum_map.borrow().iter() { + for &dep_cnum in cmeta.dependencies.borrow().iter() { self.update_extern_crate(dep_cnum, extern_crate, visited); } } @@ -1040,7 +1043,7 @@ impl<'a> CrateLoader<'a> { } info!("injecting a dep from {} to {}", cnum, krate); - data.cnum_map.borrow_mut().push(krate); + data.dependencies.borrow_mut().push(krate); }); } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 64bbcf436cb9e..f4d4bd3589398 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -64,8 +64,9 @@ pub struct CrateMetadata { pub extern_crate: Lock>, pub blob: MetadataBlob, - pub cnum_map: Lock, + pub cnum_map: CrateNumMap, pub cnum: CrateNum, + pub dependencies: Lock>, pub codemap_import_info: RwLock>, pub attribute_cache: Lock<[Vec>>; 2]>, @@ -144,7 +145,7 @@ impl CStore { } let data = self.get_crate_data(krate); - for &dep in data.cnum_map.borrow().iter() { + for &dep in data.dependencies.borrow().iter() { if dep != krate { self.push_dependencies_in_postorder(ordering, dep); } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 57f92707ccfe3..53d1ff156274e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> { if cnum == LOCAL_CRATE { self.cdata().cnum } else { - self.cdata().cnum_map.borrow()[cnum] + self.cdata().cnum_map[cnum] } } } @@ -932,7 +932,7 @@ impl<'a, 'tcx> CrateMetadata { // Translate a DefId from the current compilation environment to a DefId // for an external crate. fn reverse_translate_def_id(&self, did: DefId) -> Option { - for (local, &global) in self.cnum_map.borrow().iter_enumerated() { + for (local, &global) in self.cnum_map.iter_enumerated() { if global == did.krate { return Some(DefId { krate: local, @@ -1007,7 +1007,7 @@ impl<'a, 'tcx> CrateMetadata { .enumerate() .flat_map(|(i, link)| { let cnum = CrateNum::new(i + 1); - link.map(|link| (self.cnum_map.borrow()[cnum], link)) + link.map(|link| (self.cnum_map[cnum], link)) }) .collect() } From 868d2a18c11f97265b4aa4a0f0bd3f3f735bfc13 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 8 May 2018 09:13:18 -0400 Subject: [PATCH 12/33] Fix comment --- src/librustc_incremental/persist/load.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 01186483a6839..f846759545eb9 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -130,7 +130,7 @@ pub fn load_dep_graph(sess: &Session) -> let mut prev_work_products = FxHashMap(); // If we are only building with -Zquery-dep-graph but without an actual - // incr. comp. session directory, we exit here. Otherwise we'd fail + // incr. comp. session directory, we skip this. Otherwise we'd fail // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); From ecedf44cecbc36478231b16292786f83df45f251 Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Tue, 8 May 2018 22:20:41 +0300 Subject: [PATCH 13/33] unary op filter, dereference hint --- src/librustc_typeck/check/op.rs | 131 +++++++++++++----- src/test/ui/binary-op-on-double-ref.stderr | 3 +- src/test/ui/codemap_tests/issue-28308.stderr | 4 +- src/test/ui/error-codes/E0600.stderr | 4 +- src/test/ui/error-festival.stderr | 2 +- .../ui/feature-gate-negate-unsigned.stderr | 8 +- src/test/ui/issue-5239-1.stderr | 2 +- src/test/ui/reachable/expr_unary.stderr | 4 +- 8 files changed, 110 insertions(+), 48 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 66b95f0f4ea18..86f51ff4f668c 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -12,8 +12,8 @@ use super::{FnCtxt, Needs}; use super::method::MethodCallee; -use rustc::ty::{self, Ty, TypeFoldable, TypeVariants}; -use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { - let (mut err, missing_trait) = match is_assign{ + match is_assign{ IsAssign::Yes => { let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368, "binary assignment operation `{}=` \ @@ -269,7 +269,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiShr => Some("std::ops::ShrAssign"), _ => None }; - (err, missing_trait) + let mut suggested_deref = false; + if let TyRef(_, ref ty_mut) = lhs_ty.sty { + if { + !self.infcx.type_moves_by_default(self.param_env, + ty_mut.ty, + lhs_expr.span) && + self.lookup_op_method(ty_mut.ty, + &[rhs_ty], + Op::Binary(op, is_assign)) + .is_ok() + } { + let codemap = self.tcx.sess.codemap(); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) =>{ + let msg = &format!( + "`{}=` can be used on '{}', you can \ + dereference `{2}`: `*{2}`", + op.node.as_str(), ty_mut.ty, lstring); + err.help(msg); + suggested_deref = true; + }, + _ => {} + }; + } + } + if let Some(missing_trait) = missing_trait { + if missing_trait == "std::ops::AddAssign" && + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, + rhs_ty, &mut err) { + // This has nothing here because it means we did string + // concatenation (e.g. "Hello " + "World!"). This means + // we don't want the note in the else clause to be emitted + } else if let ty::TyParam(_) = lhs_ty.sty { + // FIXME: point to span of param + err.note( + &format!("`{}` might need a bound for `{}`", + lhs_ty, missing_trait)); + } else { + if !suggested_deref{ + err.note( + &format!("an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty)); + } + } + } + err.emit(); } IsAssign::No => { let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, @@ -292,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some("std::cmp::PartialOrd"), _ => None }; - if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { + let mut suggested_deref = false; + if let TyRef(_, ref ty_mut) = lhs_ty.sty { if { !self.infcx.type_moves_by_default(self.param_env, ty_mut.ty, @@ -302,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Op::Binary(op, is_assign)) .is_ok() } { + let codemap = self.tcx.sess.codemap(); + match codemap.span_to_snippet(lhs_expr.span) { + Ok(lstring) =>{ + let msg = &format!( + "`{}` can be used on '{}', you can \ + dereference `{2}`: `*{2}`", + op.node.as_str(), ty_mut.ty, lstring); + err.help(msg); + suggested_deref = true; + }, + _ =>{} + } + } + } + if let Some(missing_trait) = missing_trait { + if missing_trait == "std::ops::Add" && + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, + rhs_ty, &mut err) { + // This has nothing here because it means we did string + // concatenation (e.g. "Hello " + "World!"). This means + // we don't want the note in the else clause to be emitted + } else if let ty::TyParam(_) = lhs_ty.sty { + // FIXME: point to span of param err.note( - &format!( - "this is a reference to a type that `{}` can be \ - applied to; you need to dereference this variable \ - once for this operation to work", - op.node.as_str())); + &format!("`{}` might need a bound for `{}`", + lhs_ty, missing_trait)); + } else { + if !suggested_deref{ + err.note( + &format!("an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty)); + } } } - (err, missing_trait) - } - }; - if let Some(missing_trait) = missing_trait { - if missing_trait == "std::ops::Add" && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err) { - // This has nothing here because it means we did string - // concatenation (e.g. "Hello " + "World!"). This means - // we don't want the note in the else clause to be emitted - } else if let ty::TyParam(_) = lhs_ty.sty { - // FIXME: point to span of param - err.note( - &format!("`{}` might need a bound for `{}`", - lhs_ty, missing_trait)); - } else { - err.note( - &format!("an implementation of `{}` might be missing for `{}`", - missing_trait, lhs_ty)); + err.emit(); } } - err.emit(); } self.tcx.types.err } @@ -411,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600, "cannot apply unary operator `{}` to type `{}`", op.as_str(), actual); + err.span_label(ex.span, format!("cannot apply unary \ + operator `{}`", op.as_str())); let missing_trait = match op { hir::UnNeg => "std::ops::Neg", hir::UnNot => "std::ops::Not", hir::UnDeref => "std::ops::UnDerf" }; - err.note(&format!("an implementation of `{}` might be missing for `{}`", + match actual.sty{ + TyUint(_) => { + if op == hir::UnNeg{ + err.note(&format!("unsigned values cannot be negated")); + } + }, + TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {}, + TyRef(_, ref lty) if lty.ty.sty == TyStr => {}, + _ => { + err.note(&format!("an implementation of `{}` might \ + be missing for `{}`", missing_trait, operand_ty)); + } + } err.emit(); } self.tcx.types.err diff --git a/src/test/ui/binary-op-on-double-ref.stderr b/src/test/ui/binary-op-on-double-ref.stderr index 07aa3bfe40dea..020d74bee5215 100644 --- a/src/test/ui/binary-op-on-double-ref.stderr +++ b/src/test/ui/binary-op-on-double-ref.stderr @@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}` LL | x % 2 == 0 | ^^^^^ | - = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work - = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}` + = help: `%` can be used on '&{integer}', you can dereference `x`: `*x` error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr index b5c2376239d14..15c159a3b153c 100644 --- a/src/test/ui/codemap_tests/issue-28308.stderr +++ b/src/test/ui/codemap_tests/issue-28308.stderr @@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str` --> $DIR/issue-28308.rs:12:5 | LL | assert!("foo"); - | ^^^^^^^^^^^^^^^ - | - = note: an implementation of `std::ops::Not` might be missing for `&'static str` + | ^^^^^^^^^^^^^^^ cannot apply unary operator `!` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0600.stderr b/src/test/ui/error-codes/E0600.stderr index bd79ea79c8b56..c29ec4fe6ae76 100644 --- a/src/test/ui/error-codes/E0600.stderr +++ b/src/test/ui/error-codes/E0600.stderr @@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str` --> $DIR/E0600.rs:12:5 | LL | !"a"; //~ ERROR E0600 - | ^^^^ - | - = note: an implementation of `std::ops::Not` might be missing for `&'static str` + | ^^^^ cannot apply unary operator `!` error: aborting due to previous error diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 6165806aac9c4..69f11b4b7c08c 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -30,7 +30,7 @@ error[E0600]: cannot apply unary operator `!` to type `Question` --> $DIR/error-festival.rs:29:5 | LL | !Question::Yes; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ cannot apply unary operator `!` | = note: an implementation of `std::ops::Not` might be missing for `Question` diff --git a/src/test/ui/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gate-negate-unsigned.stderr index 8831e874a200e..85e9b56e4af9d 100644 --- a/src/test/ui/feature-gate-negate-unsigned.stderr +++ b/src/test/ui/feature-gate-negate-unsigned.stderr @@ -2,17 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize` --> $DIR/feature-gate-negate-unsigned.rs:20:23 | LL | let _max: usize = -1; - | ^^ + | ^^ cannot apply unary operator `-` | - = note: an implementation of `std::ops::Neg` might be missing for `usize` + = note: unsigned values cannot be negated error[E0600]: cannot apply unary operator `-` to type `u8` --> $DIR/feature-gate-negate-unsigned.rs:24:14 | LL | let _y = -x; - | ^^ + | ^^ cannot apply unary operator `-` | - = note: an implementation of `std::ops::Neg` might be missing for `u8` + = note: unsigned values cannot be negated error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-5239-1.stderr b/src/test/ui/issue-5239-1.stderr index adef9848ba743..7ae01fb7d6012 100644 --- a/src/test/ui/issue-5239-1.stderr +++ b/src/test/ui/issue-5239-1.stderr @@ -6,7 +6,7 @@ LL | let x = |ref x: isize| { x += 1; }; | | | cannot use `+=` on type `&isize` | - = note: an implementation of `std::ops::AddAssign` might be missing for `&isize` + = help: `+=` can be used on 'isize', you can dereference `x`: `*x` error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 7ba21efcd5125..b889c884fcbb2 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!` --> $DIR/expr_unary.rs:17:16 | LL | let x: ! = ! { return; }; //~ ERROR unreachable - | ^^^^^^^^^^^^^ - | - = note: an implementation of `std::ops::Not` might be missing for `!` + | ^^^^^^^^^^^^^ cannot apply unary operator `!` error: unreachable expression --> $DIR/expr_unary.rs:17:16 From 5128affbc482e65cc678745cd529e7e055b9cf8b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 4 May 2018 08:46:30 -0700 Subject: [PATCH 14/33] Fix update-references for tests within subdirectories. Fixes #50438. I'll make this more robust later for #49815. --- src/test/ui/update-references.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh index 47a85352b0044..00b4b5c5caa78 100755 --- a/src/test/ui/update-references.sh +++ b/src/test/ui/update-references.sh @@ -26,6 +26,7 @@ if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" fi +MYDIR=$(dirname $0) BUILD_DIR="$1" shift @@ -33,13 +34,13 @@ shift shopt -s nullglob while [[ "$1" != "" ]]; do - MYDIR=$(dirname $1) for EXT in "stderr" "stdout" "fixed"; do for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do + OUT_DIR=`dirname "$1"` OUT_BASE=`basename "$OUT_NAME"` - if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then - echo updating $MYDIR/$OUT_BASE - cp $OUT_NAME $MYDIR + if ! (diff $OUT_NAME $MYDIR/$OUT_DIR/$OUT_BASE >& /dev/null); then + echo updating $MYDIR/$OUT_DIR/$OUT_BASE + cp $OUT_NAME $MYDIR/$OUT_DIR fi done done From 127d2434932ec25892435ae65aeaa49390f38e1b Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Wed, 9 May 2018 10:47:09 +0300 Subject: [PATCH 15/33] [wip] fixed some error, added missing test --- src/librustc_typeck/check/op.rs | 133 ++++++++---------- src/test/ui/type-check/missing_trait_impl.rs | 4 + .../ui/type-check/missing_trait_impl.stderr | 15 +- 3 files changed, 77 insertions(+), 75 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 86f51ff4f668c..29adac324ef48 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -246,7 +246,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { - match is_assign{ + let codemap = self.tcx.sess.codemap(); + match is_assign { IsAssign::Yes => { let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368, "binary assignment operation `{}=` \ @@ -256,19 +257,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.span_label(lhs_expr.span, format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty)); - let missing_trait = match op.node { - hir::BiAdd => Some("std::ops::AddAssign"), - hir::BiSub => Some("std::ops::SubAssign"), - hir::BiMul => Some("std::ops::MulAssign"), - hir::BiDiv => Some("std::ops::DivAssign"), - hir::BiRem => Some("std::ops::RemAssign"), - hir::BiBitAnd => Some("std::ops::BitAndAssign"), - hir::BiBitXor => Some("std::ops::BitXorAssign"), - hir::BiBitOr => Some("std::ops::BitOrAssign"), - hir::BiShl => Some("std::ops::ShlAssign"), - hir::BiShr => Some("std::ops::ShrAssign"), - _ => None - }; let mut suggested_deref = false; if let TyRef(_, ref ty_mut) = lhs_ty.sty { if { @@ -280,22 +268,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Op::Binary(op, is_assign)) .is_ok() } { - let codemap = self.tcx.sess.codemap(); - match codemap.span_to_snippet(lhs_expr.span) { - Ok(lstring) =>{ - let msg = &format!( + if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) { + let msg = &format!( "`{}=` can be used on '{}', you can \ dereference `{2}`: `*{2}`", op.node.as_str(), ty_mut.ty, lstring); - err.help(msg); - suggested_deref = true; - }, - _ => {} - }; + err.help(msg); + suggested_deref = true; + } } } + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::AddAssign"), + hir::BiSub => Some("std::ops::SubAssign"), + hir::BiMul => Some("std::ops::MulAssign"), + hir::BiDiv => Some("std::ops::DivAssign"), + hir::BiRem => Some("std::ops::RemAssign"), + hir::BiBitAnd => Some("std::ops::BitAndAssign"), + hir::BiBitXor => Some("std::ops::BitXorAssign"), + hir::BiBitOr => Some("std::ops::BitOrAssign"), + hir::BiShl => Some("std::ops::ShlAssign"), + hir::BiShr => Some("std::ops::ShrAssign"), + _ => None + }; if let Some(missing_trait) = missing_trait { - if missing_trait == "std::ops::AddAssign" && + if op.node == hir::BiAdd && self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err) { // This has nothing here because it means we did string @@ -306,13 +303,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.note( &format!("`{}` might need a bound for `{}`", lhs_ty, missing_trait)); - } else { - if !suggested_deref{ - err.note( - &format!("an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty)); - } + } else if !suggested_deref { + err.note( + &format!("an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty)); } } err.emit(); @@ -322,22 +317,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); - let missing_trait = match op.node { - hir::BiAdd => Some("std::ops::Add"), - hir::BiSub => Some("std::ops::Sub"), - hir::BiMul => Some("std::ops::Mul"), - hir::BiDiv => Some("std::ops::Div"), - hir::BiRem => Some("std::ops::Rem"), - hir::BiBitAnd => Some("std::ops::BitAnd"), - hir::BiBitXor => Some("std::ops::BitXor"), - hir::BiBitOr => Some("std::ops::BitOr"), - hir::BiShl => Some("std::ops::Shl"), - hir::BiShr => Some("std::ops::Shr"), - hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), - hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => - Some("std::cmp::PartialOrd"), - _ => None - }; let mut suggested_deref = false; if let TyRef(_, ref ty_mut) = lhs_ty.sty { if { @@ -349,22 +328,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Op::Binary(op, is_assign)) .is_ok() } { - let codemap = self.tcx.sess.codemap(); - match codemap.span_to_snippet(lhs_expr.span) { - Ok(lstring) =>{ - let msg = &format!( + if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) { + let msg = &format!( "`{}` can be used on '{}', you can \ dereference `{2}`: `*{2}`", op.node.as_str(), ty_mut.ty, lstring); - err.help(msg); - suggested_deref = true; - }, - _ =>{} + err.help(msg); + suggested_deref = true; } } } + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::Add"), + hir::BiSub => Some("std::ops::Sub"), + hir::BiMul => Some("std::ops::Mul"), + hir::BiDiv => Some("std::ops::Div"), + hir::BiRem => Some("std::ops::Rem"), + hir::BiBitAnd => Some("std::ops::BitAnd"), + hir::BiBitXor => Some("std::ops::BitXor"), + hir::BiBitOr => Some("std::ops::BitOr"), + hir::BiShl => Some("std::ops::Shl"), + hir::BiShr => Some("std::ops::Shr"), + hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), + hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => + Some("std::cmp::PartialOrd"), + _ => None + }; if let Some(missing_trait) = missing_trait { - if missing_trait == "std::ops::Add" && + if op.node == hir::BiAdd && self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err) { // This has nothing here because it means we did string @@ -375,13 +366,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.note( &format!("`{}` might need a bound for `{}`", lhs_ty, missing_trait)); - } else { - if !suggested_deref{ - err.note( - &format!("an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty)); - } + } else if !suggested_deref { + err.note( + &format!("an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty)); } } err.emit(); @@ -468,20 +457,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op.as_str(), actual); err.span_label(ex.span, format!("cannot apply unary \ operator `{}`", op.as_str())); - let missing_trait = match op { - hir::UnNeg => "std::ops::Neg", - hir::UnNot => "std::ops::Not", - hir::UnDeref => "std::ops::UnDerf" - }; - match actual.sty{ - TyUint(_) => { - if op == hir::UnNeg{ - err.note(&format!("unsigned values cannot be negated")); - } + match actual.sty { + TyUint(_) if op == hir::UnNeg => { + err.note(&format!("unsigned values cannot be negated")); }, TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {}, TyRef(_, ref lty) if lty.ty.sty == TyStr => {}, _ => { + let missing_trait = match op { + hir::UnNeg => "std::ops::Neg", + hir::UnNot => "std::ops::Not", + hir::UnDeref => "std::ops::UnDerf" + }; err.note(&format!("an implementation of `{}` might \ be missing for `{}`", missing_trait, operand_ty)); diff --git a/src/test/ui/type-check/missing_trait_impl.rs b/src/test/ui/type-check/missing_trait_impl.rs index adf6b85b6429c..b3e79ce2447fb 100644 --- a/src/test/ui/type-check/missing_trait_impl.rs +++ b/src/test/ui/type-check/missing_trait_impl.rs @@ -14,3 +14,7 @@ fn main() { fn foo(x: T, y: T) { let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T` } + +fn bar(x: T) { + x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T` +} diff --git a/src/test/ui/type-check/missing_trait_impl.stderr b/src/test/ui/type-check/missing_trait_impl.stderr index 777f16b12ce68..4b01a626814e5 100644 --- a/src/test/ui/type-check/missing_trait_impl.stderr +++ b/src/test/ui/type-check/missing_trait_impl.stderr @@ -6,6 +6,17 @@ LL | let z = x + y; //~ ERROR binary operation `+` cannot be applied to type | = note: `T` might need a bound for `std::ops::Add` -error: aborting due to previous error +error[E0368]: binary assignment operation `+=` cannot be applied to type `T` + --> $DIR/missing_trait_impl.rs:19:5 + | +LL | x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T` + | -^^^^^ + | | + | cannot use `+=` on type `T` + | + = note: `T` might need a bound for `std::ops::AddAssign` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors occurred: E0368, E0369. +For more information about an error, try `rustc --explain E0368`. From 31d2012ef7468a3da17299c9964e8b01d68a67fc Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 May 2018 16:50:48 +0200 Subject: [PATCH 16/33] Adapt some method visibilities in librustc_metadata::cstore. --- src/librustc_metadata/cstore.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 64bbcf436cb9e..abecee2277c4b 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -104,15 +104,15 @@ impl CStore { /// You cannot use this function to allocate a CrateNum in a thread-safe manner. /// It is currently only used in CrateLoader which is single-threaded code. - pub fn next_crate_num(&self) -> CrateNum { + pub(super) fn next_crate_num(&self) -> CrateNum { CrateNum::new(self.metas.borrow().len() + 1) } - pub fn get_crate_data(&self, cnum: CrateNum) -> Lrc { + pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc { self.metas.borrow()[cnum].clone().unwrap() } - pub fn set_crate_data(&self, cnum: CrateNum, data: Lrc) { + pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc) { use rustc_data_structures::indexed_vec::Idx; let mut met = self.metas.borrow_mut(); while met.len() <= cnum.index() { @@ -121,7 +121,7 @@ impl CStore { met[cnum] = Some(data); } - pub fn iter_crate_data(&self, mut i: I) + pub(super) fn iter_crate_data(&self, mut i: I) where I: FnMut(CrateNum, &Lrc) { for (k, v) in self.metas.borrow().iter_enumerated() { @@ -131,14 +131,16 @@ impl CStore { } } - pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec { + pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec { let mut ordering = Vec::new(); self.push_dependencies_in_postorder(&mut ordering, krate); ordering.reverse(); ordering } - pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec, krate: CrateNum) { + pub(super) fn push_dependencies_in_postorder(&self, + ordering: &mut Vec, + krate: CrateNum) { if ordering.contains(&krate) { return; } @@ -153,7 +155,7 @@ impl CStore { ordering.push(krate); } - pub fn do_postorder_cnums_untracked(&self) -> Vec { + pub(super) fn do_postorder_cnums_untracked(&self) -> Vec { let mut ordering = Vec::new(); for (num, v) in self.metas.borrow().iter_enumerated() { if let &Some(_) = v { @@ -163,11 +165,11 @@ impl CStore { return ordering } - pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) { + pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) { self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); } - pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { + pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } } From fa8ac4aac845b1abaf7e8c969432f14ace68d037 Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Wed, 9 May 2018 12:38:09 +0300 Subject: [PATCH 17/33] fixed double ref hint --- src/librustc_typeck/check/op.rs | 52 ++++++++++++++-------- src/test/ui/binary-op-on-double-ref.stderr | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 29adac324ef48..0c717b9f20125 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -258,7 +258,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty)); let mut suggested_deref = false; - if let TyRef(_, ref ty_mut) = lhs_ty.sty { + if let TyRef(_, mut ty_mut) = lhs_ty.sty { if { !self.infcx.type_moves_by_default(self.param_env, ty_mut.ty, @@ -269,10 +269,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .is_ok() } { if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) { + while let TyRef(_, ty_mut_inner) = ty_mut.ty.sty{ + ty_mut = ty_mut_inner; + } let msg = &format!( "`{}=` can be used on '{}', you can \ dereference `{2}`: `*{2}`", - op.node.as_str(), ty_mut.ty, lstring); + op.node.as_str(), + ty_mut.ty, + lstring + ); err.help(msg); suggested_deref = true; } @@ -300,14 +306,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we don't want the note in the else clause to be emitted } else if let ty::TyParam(_) = lhs_ty.sty { // FIXME: point to span of param - err.note( - &format!("`{}` might need a bound for `{}`", - lhs_ty, missing_trait)); + err.note(&format!( + "`{}` might need a bound for `{}`", + lhs_ty, missing_trait + )); } else if !suggested_deref { - err.note( - &format!("an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty)); + err.note(&format!( + "an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty + )); } } err.emit(); @@ -318,7 +326,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op.node.as_str(), lhs_ty); let mut suggested_deref = false; - if let TyRef(_, ref ty_mut) = lhs_ty.sty { + if let TyRef(_, mut ty_mut) = lhs_ty.sty { if { !self.infcx.type_moves_by_default(self.param_env, ty_mut.ty, @@ -329,10 +337,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .is_ok() } { if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) { + while let TyRef(_, ty_mut_inner) = ty_mut.ty.sty{ + ty_mut = ty_mut_inner; + } let msg = &format!( "`{}` can be used on '{}', you can \ dereference `{2}`: `*{2}`", - op.node.as_str(), ty_mut.ty, lstring); + op.node.as_str(), + ty_mut.ty, + lstring + ); err.help(msg); suggested_deref = true; } @@ -363,14 +377,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we don't want the note in the else clause to be emitted } else if let ty::TyParam(_) = lhs_ty.sty { // FIXME: point to span of param - err.note( - &format!("`{}` might need a bound for `{}`", - lhs_ty, missing_trait)); + err.note(&format!( + "`{}` might need a bound for `{}`", + lhs_ty, missing_trait + )); } else if !suggested_deref { - err.note( - &format!("an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty)); + err.note(&format!( + "an implementation of `{}` might \ + be missing for `{}`", + missing_trait, lhs_ty + )); } } err.emit(); diff --git a/src/test/ui/binary-op-on-double-ref.stderr b/src/test/ui/binary-op-on-double-ref.stderr index 020d74bee5215..c89defa3dd196 100644 --- a/src/test/ui/binary-op-on-double-ref.stderr +++ b/src/test/ui/binary-op-on-double-ref.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}` LL | x % 2 == 0 | ^^^^^ | - = help: `%` can be used on '&{integer}', you can dereference `x`: `*x` + = help: `%` can be used on '{integer}', you can dereference `x`: `*x` error: aborting due to previous error From 77c40f8c6f8cc472f6438f7724d60bf3b7718a0c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 May 2018 15:25:44 +1000 Subject: [PATCH 18/33] Inline `Span` methods. Because they are simple and hot. This change speeds up some incremental runs of a few rustc-perf benchmarks, the best by 3%. --- src/libsyntax_pos/span_encoding.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs index b55fe4bcb2672..601a0273ae911 100644 --- a/src/libsyntax_pos/span_encoding.rs +++ b/src/libsyntax_pos/span_encoding.rs @@ -31,11 +31,13 @@ pub struct Span(u32); impl Copy for Span {} impl Clone for Span { + #[inline] fn clone(&self) -> Span { *self } } impl PartialEq for Span { + #[inline] fn eq(&self, other: &Span) -> bool { let a = self.0; let b = other.0; @@ -44,6 +46,7 @@ impl PartialEq for Span { } impl Eq for Span {} impl Hash for Span { + #[inline] fn hash(&self, state: &mut H) { let a = self.0; a.hash(state) From 78262e700dc6a7b57e376742f344e80115d2d3f2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 May 2018 12:21:48 +1000 Subject: [PATCH 19/33] Use SmallVec for DepNodeIndex within dep_graph. This avoids a decent number of allocations, enough to speed up incremental runs of many rustc-benchmarks, the best by 2%. --- src/librustc/dep_graph/graph.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 22ab1b15c8b8e..e9400e17b86c0 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -12,6 +12,7 @@ use errors::DiagnosticBuilder; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock}; use std::env; use std::hash::Hash; @@ -131,7 +132,7 @@ impl DepGraph { let mut edges = Vec::new(); for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() { let from = current_dep_graph.nodes[index]; - for &edge_target in edge_targets { + for &edge_target in edge_targets.iter() { let to = current_dep_graph.nodes[edge_target]; edges.push((from, to)); } @@ -209,7 +210,7 @@ impl DepGraph { self.with_task_impl(key, cx, arg, false, task, |key| OpenTask::Regular(Lock::new(RegularOpenTask { node: key, - reads: Vec::new(), + reads: SmallVec::new(), read_set: FxHashSet(), })), |data, key, task| data.borrow_mut().complete_task(key, task)) @@ -230,7 +231,7 @@ impl DepGraph { self.with_task_impl(key, cx, input, true, identity_fn, |_| OpenTask::Ignore, - |data, key, _| data.borrow_mut().alloc_node(key, Vec::new())) + |data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new())) } fn with_task_impl<'gcx, C, A, R>( @@ -353,7 +354,7 @@ impl DepGraph { if let Some(ref data) = self.data { let (result, open_task) = ty::tls::with_context(|icx| { let task = OpenTask::Anon(Lock::new(AnonOpenTask { - reads: Vec::new(), + reads: SmallVec::new(), read_set: FxHashSet(), })); @@ -626,7 +627,7 @@ impl DepGraph { debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); - let mut current_deps = Vec::new(); + let mut current_deps = SmallVec::new(); for &dep_dep_node_index in prev_deps { let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); @@ -923,7 +924,7 @@ pub enum WorkProductFileKind { pub(super) struct CurrentDepGraph { nodes: IndexVec, - edges: IndexVec>, + edges: IndexVec>, node_to_node_index: FxHashMap, forbidden_edge: Option, @@ -1061,7 +1062,7 @@ impl CurrentDepGraph { } = task { debug_assert_eq!(node, key); let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)]; - self.alloc_node(node, vec![krate_idx]) + self.alloc_node(node, SmallVec::one(krate_idx)) } else { bug!("complete_eval_always_task() - Expected eval always task to be popped"); } @@ -1107,7 +1108,7 @@ impl CurrentDepGraph { fn alloc_node(&mut self, dep_node: DepNode, - edges: Vec) + edges: SmallVec<[DepNodeIndex; 8]>) -> DepNodeIndex { debug_assert_eq!(self.edges.len(), self.nodes.len()); debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len()); @@ -1122,12 +1123,12 @@ impl CurrentDepGraph { pub struct RegularOpenTask { node: DepNode, - reads: Vec, + reads: SmallVec<[DepNodeIndex; 8]>, read_set: FxHashSet, } pub struct AnonOpenTask { - reads: Vec, + reads: SmallVec<[DepNodeIndex; 8]>, read_set: FxHashSet, } From 0ba1c101dce22fbe30933a90efd237a09227e07d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 9 May 2018 06:47:37 -0700 Subject: [PATCH 20/33] Clarify in the docs that `mul_add` is not always faster. Fixes https://github.com/rust-lang/rust/issues/49842. Other resources: - https://users.rust-lang.org/t/why-does-the-mul-add-method-produce-a-more-accurate-result-with-better-performance/1626 - https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation --- src/libstd/f32.rs | 6 ++++-- src/libstd/f64.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 26644c769575c..4f4baf1e8cd91 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -195,8 +195,10 @@ impl f32 { } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// /// ``` /// use std::f32; diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a7e63f59b1c67..e00ff60452dd0 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -173,8 +173,10 @@ impl f64 { } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// /// ``` /// let m = 10.0_f64; From b8b957d4792be619a3251c917199fe7e7c01997c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 May 2018 17:15:42 +0200 Subject: [PATCH 21/33] Make CrateNum allocation more thread-safe. --- src/librustc_metadata/creader.rs | 5 +---- src/librustc_metadata/cstore.rs | 20 +++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d0237071a6058..d9038105da08b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -51,7 +51,6 @@ pub struct Library { pub struct CrateLoader<'a> { pub sess: &'a Session, cstore: &'a CStore, - next_crate_num: CrateNum, local_crate_name: Symbol, } @@ -102,7 +101,6 @@ impl<'a> CrateLoader<'a> { CrateLoader { sess, cstore, - next_crate_num: cstore.next_crate_num(), local_crate_name: Symbol::intern(local_crate_name), } } @@ -198,8 +196,7 @@ impl<'a> CrateLoader<'a> { self.verify_no_symbol_conflicts(span, &crate_root); // Claim this crate number and cache it - let cnum = self.next_crate_num; - self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1); + let cnum = self.cstore.alloc_new_crate_num(); // Stash paths for top-most crate locally if necessary. let crate_paths = if root.is_none() { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index abecee2277c4b..4872d560d27f0 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -96,16 +96,17 @@ pub struct CStore { impl CStore { pub fn new(metadata_loader: Box) -> CStore { CStore { - metas: RwLock::new(IndexVec::new()), + metas: RwLock::new(IndexVec::from_elem_n(None, 1)), extern_mod_crate_map: Lock::new(FxHashMap()), metadata_loader, } } - /// You cannot use this function to allocate a CrateNum in a thread-safe manner. - /// It is currently only used in CrateLoader which is single-threaded code. - pub(super) fn next_crate_num(&self) -> CrateNum { - CrateNum::new(self.metas.borrow().len() + 1) + pub(super) fn alloc_new_crate_num(&self) -> CrateNum { + let mut metas = self.metas.borrow_mut(); + let cnum = CrateNum::new(metas.len()); + metas.push(None); + cnum } pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc { @@ -113,12 +114,9 @@ impl CStore { } pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc) { - use rustc_data_structures::indexed_vec::Idx; - let mut met = self.metas.borrow_mut(); - while met.len() <= cnum.index() { - met.push(None); - } - met[cnum] = Some(data); + let mut metas = self.metas.borrow_mut(); + assert!(metas[cnum].is_none(), "Overwriting crate metadata entry"); + metas[cnum] = Some(data); } pub(super) fn iter_crate_data(&self, mut i: I) From a9810899a290a7746e88382558454e31bb8f85b7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 25 Apr 2018 15:45:04 +0200 Subject: [PATCH 22/33] Allow for specifying a linker plugin for cross-language LTO --- src/librustc/session/config.rs | 55 +++++++++++++++++++++-- src/librustc/session/mod.rs | 7 +++ src/librustc_trans/back/link.rs | 3 ++ src/librustc_trans/back/linker.rs | 52 ++++++++++++++++++++- src/librustc_trans/back/write.rs | 10 ++--- src/test/run-make/cross-lang-lto/Makefile | 4 +- 6 files changed, 118 insertions(+), 13 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 83dac033f9408..245663494ddef 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -95,6 +95,23 @@ pub enum Lto { Fat, } +#[derive(Clone, PartialEq, Hash)] +pub enum CrossLangLto { + LinkerPlugin(PathBuf), + NoLink, + Disabled +} + +impl CrossLangLto { + pub fn embed_bitcode(&self) -> bool { + match *self { + CrossLangLto::LinkerPlugin(_) | + CrossLangLto::NoLink => true, + CrossLangLto::Disabled => false, + } + } +} + #[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfoLevel { NoDebugInfo, @@ -412,6 +429,7 @@ top_level_options!( // Remap source path prefixes in all output (messages, object files, debug, etc) remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], + edition: Edition [TRACKED], } ); @@ -777,11 +795,15 @@ macro_rules! options { Some("`string` or `string=string`"); pub const parse_lto: Option<&'static str> = Some("one of `thin`, `fat`, or omitted"); + pub const parse_cross_lang_lto: Option<&'static str> = + Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \ + or the path to the linker plugin"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto}; + use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto, + CrossLangLto}; use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; use std::path::PathBuf; @@ -986,6 +1008,26 @@ macro_rules! options { true } + fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + CrossLangLto::NoLink + } else { + CrossLangLto::Disabled + }; + return true + } + } + + *slot = match v { + None | + Some("no-link") => CrossLangLto::NoLink, + Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)), + }; + true + } } ) } @@ -1295,7 +1337,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "make the current crate share its generic instantiations"), chalk: bool = (false, parse_bool, [TRACKED], "enable the experimental Chalk-based trait solving engine"), - cross_lang_lto: bool = (false, parse_bool, [TRACKED], + cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED], "generate build artifacts that are compatible with linker-based LTO."), } @@ -2327,7 +2369,7 @@ mod dep_tracking { use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes, - Passes, Sanitizer}; + Passes, Sanitizer, CrossLangLto}; use syntax::feature_gate::UnstableFeatures; use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple}; use syntax::edition::Edition; @@ -2391,6 +2433,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(TargetTriple); impl_dep_tracking_hash_via_hash!(Edition); + impl_dep_tracking_hash_via_hash!(CrossLangLto); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); @@ -2455,7 +2498,7 @@ mod tests { use lint; use middle::cstore; use session::config::{build_configuration, build_session_options_and_crate_config}; - use session::config::Lto; + use session::config::{Lto, CrossLangLto}; use session::build_session; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -3111,6 +3154,10 @@ mod tests { opts = reference.clone(); opts.debugging_opts.relro_level = Some(RelroLevel::Full); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + + opts = reference.clone(); + opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink; + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } #[test] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2ab72ba20bf4f..23f84881c7980 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -657,6 +657,13 @@ impl Session { } } + pub fn target_cpu(&self) -> &str { + match self.opts.cg.target_cpu { + Some(ref s) => &**s, + None => &*self.target.target.options.cpu + } + } + pub fn must_not_eliminate_frame_pointers(&self) -> bool { if let Some(x) = self.opts.cg.force_frame_pointers { x diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 92f9a9e8ba974..d39556e9bb197 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -970,6 +970,9 @@ fn link_args(cmd: &mut Linker, out_filename: &Path, trans: &CrateTranslation) { + // Linker plugins should be specified early in the list of arguments + cmd.cross_lang_lto(); + // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index ea3f5b408604e..2a84ffe79b285 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -21,7 +21,8 @@ use back::symbol_export; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use rustc::middle::dependency_format::Linkage; use rustc::session::Session; -use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; +use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel, + CrossLangLto}; use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; @@ -127,6 +128,7 @@ pub trait Linker { fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); fn group_end(&mut self); + fn cross_lang_lto(&mut self); // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). fn finalize(&mut self) -> Command; } @@ -434,6 +436,42 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("--end-group"); } } + + fn cross_lang_lto(&mut self) { + match self.sess.opts.debugging_opts.cross_lang_lto { + CrossLangLto::Disabled | + CrossLangLto::NoLink => { + // Nothing to do + } + CrossLangLto::LinkerPlugin(ref path) => { + self.linker_arg(&format!("-plugin={}", path.display())); + + let opt_level = match self.sess.opts.optimize { + config::OptLevel::No => "O0", + config::OptLevel::Less => "O1", + config::OptLevel::Default => "O2", + config::OptLevel::Aggressive => "O3", + config::OptLevel::Size => "Os", + config::OptLevel::SizeMin => "Oz", + }; + + self.linker_arg(&format!("-plugin-opt={}", opt_level)); + self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu())); + + match self.sess.opts.cg.lto { + config::Lto::Thin | + config::Lto::ThinLocal => { + self.linker_arg(&format!("-plugin-opt=thin")); + } + config::Lto::Fat | + config::Lto::Yes | + config::Lto::No => { + // default to regular LTO + } + } + } + } + } } pub struct MsvcLinker<'a> { @@ -666,6 +704,10 @@ impl<'a> Linker for MsvcLinker<'a> { // MSVC doesn't need group indicators fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } } pub struct EmLinker<'a> { @@ -832,6 +874,10 @@ impl<'a> Linker for EmLinker<'a> { // Appears not necessary on Emscripten fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } } fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { @@ -984,4 +1030,8 @@ impl Linker for WasmLd { // Not needed for now with LLD fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing for now + } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index b6fae3eaff23a..64876e82309f0 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) let triple = &sess.target.target.llvm_target; let triple = CString::new(triple.as_bytes()).unwrap(); - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => &**s, - None => &*sess.target.target.options.cpu - }; + let cpu = sess.target_cpu(); let cpu = CString::new(cpu.as_bytes()).unwrap(); let features = attributes::llvm_target_features(sess) .collect::>() @@ -294,7 +291,7 @@ impl ModuleConfig { self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; let embed_bitcode = sess.target.target.options.embed_bitcode || sess.opts.debugging_opts.embed_bitcode || - sess.opts.debugging_opts.cross_lang_lto; + sess.opts.debugging_opts.cross_lang_lto.embed_bitcode(); if embed_bitcode { match sess.opts.optimize { config::OptLevel::No | @@ -1358,7 +1355,8 @@ fn execute_work_item(cgcx: &CodegenContext, // Don't run LTO passes when cross-lang LTO is enabled. The linker // will do that for us in this case. - let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto; + let needs_lto = needs_lto && + !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode(); if needs_lto { Ok(WorkItemResult::NeedsLTO(mtrans)) diff --git a/src/test/run-make/cross-lang-lto/Makefile b/src/test/run-make/cross-lang-lto/Makefile index 98b509cd81f54..925f686fe1161 100644 --- a/src/test/run-make/cross-lang-lto/Makefile +++ b/src/test/run-make/cross-lang-lto/Makefile @@ -18,9 +18,9 @@ endif OBJDUMP=llvm-objdump SECTION_HEADERS=$(OBJDUMP) -section-headers -BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 +BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 -BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj +BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib From 23aa4831026b96869d0e0c283d39ba5fb35e786f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20K=C3=B6ln?= Date: Wed, 9 May 2018 18:03:13 +0200 Subject: [PATCH 23/33] add fn `into_inner(self) -> (Idx, Idx)` to RangeInclusive (#49022) --- src/libcore/ops/range.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index b01a769eda7fd..697e6a3efde28 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -411,6 +411,21 @@ impl RangeInclusive { pub fn end(&self) -> &Idx { &self.end } + + /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound). + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).into_inner(), (3, 5)); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn into_inner(self) -> (Idx, Idx) { + (self.start, self.end) + } } #[stable(feature = "inclusive_range", since = "1.26.0")] From 254b6014d20f51a3e91b88c24a8f19e31f17acc9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 May 2018 08:33:49 -0700 Subject: [PATCH 24/33] std: Avoid `ptr::copy` if unnecessary in `vec::Drain` This commit is spawned out of a performance regression investigation in #50496. In tracking down this regression it turned out that the `expand_statements` function in the compiler was taking quite a long time. Further investigation showed two key properties: * The function was "fast" on glibc 2.24 and slow on glibc 2.23 * The hottest function was memmove from glibc Combined together it looked like glibc gained an optimization to the memmove function in 2.24. Ideally we don't want to rely on this optimization, so I wanted to dig further to see what was happening. The hottest part of `expand_statements` was `Drop for Drain` in the call to `splice` where we insert new statements into the original vector. This *should* be a cheap operation because we're draining and replacing iterators of the exact same length, but under the hood memmove was being called a lot, causing a slowdown on glibc 2.23. It turns out that at least one of the optimizations in glibc 2.24 was that `memmove` where the src/dst are equal becomes much faster. [This program][prog] executes in ~2.5s against glibc 2.23 and ~0.3s against glibc 2.24, exhibiting how glibc 2.24 is optimizing `memmove` if the src/dst are equal. And all that brings us to what this commit itself is doing. The change here is purely to `Drop for Drain` to avoid the call to `ptr::copy` if the region being copied doesn't actually need to be copied. For normal usage of just `Drain` itself this check isn't really necessary, but because `Splice` internally contains `Drain` this provides a nice speed boost on glibc 2.23. Overall this should fix the regression seen in #50496 on glibc 2.23 and also fix the regression on Windows where `memmove` looks to not have this optimization. Note that the way `splice` was called in `expand_statements` would cause a quadratic number of elements to be copied via `memmove` which is likely why the tuple-stress benchmark showed such a severe regression. Closes #50496 [prog]: https://gist.github.com/alexcrichton/c05bc51c6771bba5ae5b57561a6c1cd3 --- src/liballoc/vec.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 35d0a69a05abe..690cbcb559bbf 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2533,9 +2533,11 @@ impl<'a, T> Drop for Drain<'a, T> { // memmove back untouched tail, update to new length let start = source_vec.len(); let tail = self.tail_start; - let src = source_vec.as_ptr().offset(tail as isize); - let dst = source_vec.as_mut_ptr().offset(start as isize); - ptr::copy(src, dst, self.tail_len); + if tail != start { + let src = source_vec.as_ptr().offset(tail as isize); + let dst = source_vec.as_mut_ptr().offset(start as isize); + ptr::copy(src, dst, self.tail_len); + } source_vec.set_len(start + self.tail_len); } } From 050cb1c45232017a7708144b867114d7a7fbb569 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 17:34:37 +0200 Subject: [PATCH 25/33] Don't require clippy/miri for beta --- src/ci/docker/x86_64-gnu-tools/checktools.sh | 37 ++++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3fed0175371a7..b0b88a6f30516 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -57,17 +57,34 @@ verify_status() { fi } +check_dispatch() { + if [ "$1" = submodule_changed ]; then + # ignore $2 (branch id) + verify_status $3 $4 + elif [ "$2" = beta ]; then + echo "Requiring test passing for $3..." + if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then + exit 4 + fi + fi +} + +status_check() { + check_dispatch $1 beta book src/doc/book + check_dispatch $1 beta nomicon src/doc/nomicon + check_dispatch $1 beta reference src/doc/reference + check_dispatch $1 beta rust-by-example src/doc/rust-by-example + check_dispatch $1 beta rls src/tool/rls + check_dispatch $1 beta rustfmt src/tool/rustfmt + # these tools are not required for beta to successfully branch + check_dispatch $1 nightly clippy-driver src/tool/clippy + check_dispatch $1 nightly miri src/tool/miri +} + # If this PR is intended to update one of these tools, do not let the build pass # when they do not test-pass. -verify_status book src/doc/book -verify_status nomicon src/doc/nomicon -verify_status reference src/doc/reference -verify_status rust-by-example src/doc/rust-by-example -verify_status rls src/tool/rls -verify_status rustfmt src/tool/rustfmt -verify_status clippy-driver src/tool/clippy -verify_status miri src/tool/miri +status_check "submodule_changed" if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then . "$(dirname $0)/repo.sh" @@ -86,6 +103,4 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE") exit 0 fi -if grep -q fail "$TOOLSTATE_FILE"; then - exit 4 -fi +status_check "beta_required" From b8174030841d1b3a26add05ba7de6d252c135d8c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 18:22:46 +0200 Subject: [PATCH 26/33] Document the checktools script --- src/ci/docker/x86_64-gnu-tools/checktools.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index b0b88a6f30516..d71d5daf8113b 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))" touch "$TOOLSTATE_FILE" +# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE + set +e python2.7 "$X_PY" test --no-fail-fast \ src/doc/book \ @@ -38,6 +40,7 @@ set -e cat "$TOOLSTATE_FILE" echo +# This function checks that if a tool's submodule changed, the tool's state must improve verify_status() { echo "Verifying status of $1..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then @@ -57,6 +60,7 @@ verify_status() { fi } +# deduplicates the submodule check and the assertion that on beta some tools MUST be passing check_dispatch() { if [ "$1" = submodule_changed ]; then # ignore $2 (branch id) @@ -69,6 +73,7 @@ check_dispatch() { fi } +# list all tools here status_check() { check_dispatch $1 beta book src/doc/book check_dispatch $1 beta nomicon src/doc/nomicon @@ -103,4 +108,6 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE") exit 0 fi +# abort compilation if an important tool doesn't build +# (this code is reachable if not on the nightly channel) status_check "beta_required" From 4537025c7193b4f1412807ab15f723f51ff0b01e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 9 May 2018 21:32:18 +0200 Subject: [PATCH 27/33] Add comment about first element in CStore::metas. --- src/librustc_metadata/cstore.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 4872d560d27f0..0c54ec7c27ab2 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -96,6 +96,10 @@ pub struct CStore { impl CStore { pub fn new(metadata_loader: Box) -> CStore { CStore { + // We add an empty entry for LOCAL_CRATE (which maps to zero) in + // order to make array indices in `metas` match with the + // corresponding `CrateNum`. This first entry will always remain + // `None`. metas: RwLock::new(IndexVec::from_elem_n(None, 1)), extern_mod_crate_map: Lock::new(FxHashMap()), metadata_loader, From 8010604b2d888ac839147fe27de76cdcc713aa1b Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 9 May 2018 18:03:56 -0400 Subject: [PATCH 28/33] move See also links to top --- src/liballoc/slice.rs | 4 ++-- src/liballoc/str.rs | 4 ++-- src/libcore/num/f32.rs | 4 ++-- src/libcore/num/f64.rs | 4 ++-- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- src/libstd/primitive_docs.rs | 16 ++++++++-------- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d50a3458f20d1..6caf12aa7eb81 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -10,6 +10,8 @@ //! A dynamically-sized view into a contiguous sequence, `[T]`. //! +//! *[See also the slice primitive type](../../std/primitive.slice.html).* +//! //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,8 +80,6 @@ //! * Further methods that return iterators are [`.split`], [`.splitn`], //! [`.chunks`], [`.windows`] and more. //! -//! *[See also the slice primitive type](../../std/primitive.slice.html).* -//! //! [`Clone`]: ../../std/clone/trait.Clone.html //! [`Eq`]: ../../std/cmp/trait.Eq.html //! [`Ord`]: ../../std/cmp/trait.Ord.html diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9e693c89be90d..42efdea74b1ab 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -10,6 +10,8 @@ //! Unicode string slices. //! +//! *[See also the `str` primitive type](../../std/primitive.str.html).* +//! //! The `&str` type is one of the two main string types, the other being `String`. //! Unlike its `String` counterpart, its contents are borrowed. //! @@ -29,8 +31,6 @@ //! ``` //! let hello_world: &'static str = "Hello, world!"; //! ``` -//! -//! *[See also the `str` primitive type](../../std/primitive.str.html).* #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 672119eba7f9d..4a7dc13f0f2ca 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 220b23a1e6a01..801de5e87bd10 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 26644c769575c..f4d897b0111e7 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a7e63f59b1c67..bd24e84dbedc5 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 437d7d74cae0d..6e329d85539b1 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -370,6 +370,8 @@ mod prim_unit { } // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// @@ -444,8 +446,6 @@ mod prim_unit { } /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// *[See also the `std::ptr` module](ptr/index.html).* -/// /// [`null`]: ../std/ptr/fn.null.html /// [`null_mut`]: ../std/ptr/fn.null_mut.html /// [`is_null`]: ../std/primitive.pointer.html#method.is_null @@ -563,6 +563,8 @@ mod prim_array { } // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// +/// *[See also the `std::slice` module](slice/index.html).* +/// /// Slices are a view into a block of memory represented as a pointer and a /// length. /// @@ -585,8 +587,6 @@ mod prim_array { } /// assert_eq!(x, &[1, 7, 3]); /// ``` /// -/// *[See also the `std::slice` module](slice/index.html).* -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice { } @@ -862,11 +862,11 @@ mod prim_u128 { } // /// The pointer-sized signed integer type. /// +/// *[See also the `std::isize` module](isize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::isize` module](isize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -874,11 +874,11 @@ mod prim_isize { } // /// The pointer-sized unsigned integer type. /// +/// *[See also the `std::usize` module](usize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::usize` module](usize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } From b8eb91a5ade04804118d39a0f74ae908f33b6268 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 9 May 2018 18:05:36 -0400 Subject: [PATCH 29/33] make std::str link into See also link also make a drive-by typo fix --- src/libstd/primitive_docs.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 6e329d85539b1..7074928eaf6da 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -594,15 +594,13 @@ mod prim_slice { } // /// String slices. /// +/// *[See also the `std::str` module](str/index.html).* +/// /// The `str` type, also called a 'string slice', is the most primitive string /// type. It is usually seen in its borrowed form, `&str`. It is also the type /// of string literals, `&'static str`. /// -/// Strings slices are always valid UTF-8. -/// -/// This documentation describes a number of methods and trait implementations -/// on the `str` type. For technical reasons, there is additional, separate -/// documentation in the [`std::str`](str/index.html) module as well. +/// String slices are always valid UTF-8. /// /// # Examples /// From 9c4e5b3b6cbf9b31ac7bd74d760214e36e79bfff Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 10 May 2018 09:16:10 +0900 Subject: [PATCH 30/33] Restore RawVec::reserve* documentation When the RawVec::try_reserve* methods were added, they took the place of the ::reserve* methods in the source file, and new ::reserve* methods wrapping the new try_reserve* methods were created. But the documentation didn't move along, such that: - reserve_* methods are barely documented. - try_reserve_* methods have unmodified documentation from reserve_*, such that their documentation indicate they are panicking/aborting. This moves the documentation back to the right methods, with a placeholder documentation for the try_reserve* methods. --- src/liballoc/raw_vec.rs | 113 ++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 4d73d3aa07e66..5c6f6b22aae06 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -385,26 +385,7 @@ impl RawVec { } } - /// Ensures that the buffer contains at least enough space to hold - /// `used_cap + needed_extra_cap` elements. If it doesn't already, - /// will reallocate the minimum possible amount of memory necessary. - /// Generally this will be exactly the amount of memory necessary, - /// but in principle the allocator is free to give back more than - /// we asked for. - /// - /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate - /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behavior of this function may break. - /// - /// # Panics - /// - /// * Panics if the requested capacity exceeds `usize::MAX` bytes. - /// * Panics on 32-bit platforms if the requested capacity exceeds - /// `isize::MAX` bytes. - /// - /// # Aborts - /// - /// Aborts on OOM + /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) -> Result<(), CollectionAllocErr> { @@ -441,6 +422,26 @@ impl RawVec { } } + /// Ensures that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already, + /// will reallocate the minimum possible amount of memory necessary. + /// Generally this will be exactly the amount of memory necessary, + /// but in principle the allocator is free to give back more than + /// we asked for. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), @@ -463,6 +464,42 @@ impl RawVec { Ok(cmp::max(double_cap, required_cap)) } + /// The same as `reserve`, but returns on errors instead of panicking or aborting. + pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) + -> Result<(), CollectionAllocErr> { + unsafe { + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. + // Wrapping in case they give a bad `used_cap` + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return Ok(()); + } + + let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; + + // FIXME: may crash and burn on over-reserve + alloc_guard(new_layout.size())?; + + let res = match self.current_layout() { + Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) + } + None => self.a.alloc(new_layout), + }; + + self.ptr = res?.cast().into(); + self.cap = new_cap; + + Ok(()) + } + } + /// Ensures that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate enough space plus comfortable slack @@ -515,42 +552,6 @@ impl RawVec { /// # vector.push_all(&[1, 3, 5, 7, 9]); /// # } /// ``` - pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) - -> Result<(), CollectionAllocErr> { - unsafe { - // NOTE: we don't early branch on ZSTs here because we want this - // to actually catch "asking for more than usize::MAX" in that case. - // If we make it past the first branch then we are guaranteed to - // panic. - - // Don't actually need any more capacity. - // Wrapping in case they give a bad `used_cap` - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return Ok(()); - } - - let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; - - // FIXME: may crash and burn on over-reserve - alloc_guard(new_layout.size())?; - - let res = match self.current_layout() { - Some(layout) => { - debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) - } - None => self.a.alloc(new_layout), - }; - - self.ptr = res?.cast().into(); - self.cap = new_cap; - - Ok(()) - } - } - - /// The same as try_reserve, but errors are lowered to a call to oom(). pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), From ae3feff0281b2f08f6dbb75dc2e50e338a711e5f Mon Sep 17 00:00:00 2001 From: Isaac Whitfield Date: Wed, 9 May 2018 23:36:57 -0700 Subject: [PATCH 31/33] Remove unnecessary mutable borrow and resizing --- src/librustc/dep_graph/graph.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 22ab1b15c8b8e..b26281ad7ebf2 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -534,15 +534,9 @@ impl DepGraph { } pub fn serialize(&self) -> SerializedDepGraph { - let mut fingerprints = self.fingerprints.borrow_mut(); let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); - // Make sure we don't run out of bounds below. - if current_dep_graph.nodes.len() > fingerprints.len() { - fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO); - } - - let fingerprints = fingerprints.clone().convert_index_type(); + let fingerprints = self.fingerprints.borrow().clone().convert_index_type(); let nodes = current_dep_graph.nodes.clone().convert_index_type(); let total_edge_count: usize = current_dep_graph.edges.iter() From 7def3f0c82a95ee9147c969e94665418bf77468c Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 10 May 2018 20:00:29 +0800 Subject: [PATCH 32/33] Retry when downloading the Docker cache. Prevent spuriously needing to rebuild the docker image when the network was down. Also, adjusted the retry function to insert a sleep between retries, because retrying immediately will often just hit the same issue. --- src/ci/docker/run.sh | 4 +++- src/ci/shared.sh | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c470ae7eb3030..3465e386cd925 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then s3url="s3://$SCCACHE_BUCKET/docker/$cksum" url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum" echo "Attempting to download $s3url" + rm -f /tmp/rustci_docker_cache set +e - loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/') + retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url" + loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/') set -e echo "Downloaded containers:\n$loaded_images" fi diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 4a08683e3ee86..bb6945f0fd6bb 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -21,11 +21,12 @@ function retry { while true; do "$@" && break || { if [[ $n -lt $max ]]; then + sleep $n # don't retry immediately ((n++)) echo "Command failed. Attempt $n/$max:" else echo "The command has failed after $n attempts." - exit 1 + return 1 fi } done From 12446dd52cd078ff05e7d0d2fc341fb0a569fb5d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 May 2018 11:43:58 -0700 Subject: [PATCH 33/33] Pull in a wasm fix from LLVM upstream This pulls in a fix for https://bugs.llvm.org/show_bug.cgi?id=36564 which has already landed in upstream LLVM and should... Closes rust-lang-nursery/rust-wasm#168 --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index b6c1a03fb498f..fd7dd99edf371 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit b6c1a03fb498f6c03d1cbfd4404223a046f8c3b2 +Subproject commit fd7dd99edf371ac502ae4e70288c027f6692ace0